advapi32: Don't shadow keychain_item in mac_write_credential.
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blobb094b58b03d5659ffea29b6f723a4ba58c5e9f80
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 WCHAR *url;
90 } domdoc_properties;
92 typedef struct ConnectionPoint ConnectionPoint;
93 typedef struct domdoc domdoc;
95 struct ConnectionPoint
97 IConnectionPoint IConnectionPoint_iface;
98 const IID *iid;
100 ConnectionPoint *next;
101 IConnectionPointContainer *container;
102 domdoc *doc;
104 union
106 IUnknown *unk;
107 IDispatch *disp;
108 IPropertyNotifySink *propnotif;
109 } *sinks;
110 DWORD sinks_size;
113 typedef enum {
114 EVENTID_READYSTATECHANGE = 0,
115 EVENTID_DATAAVAILABLE,
116 EVENTID_TRANSFORMNODE,
117 EVENTID_LAST
118 } eventid_t;
120 struct domdoc
122 xmlnode node;
123 IXMLDOMDocument3 IXMLDOMDocument3_iface;
124 IPersistStreamInit IPersistStreamInit_iface;
125 IObjectWithSite IObjectWithSite_iface;
126 IObjectSafety IObjectSafety_iface;
127 IConnectionPointContainer IConnectionPointContainer_iface;
128 LONG ref;
129 VARIANT_BOOL async;
130 VARIANT_BOOL validating;
131 VARIANT_BOOL resolving;
132 domdoc_properties* properties;
133 HRESULT error;
135 /* IObjectWithSite */
136 IUnknown *site;
138 /* IObjectSafety */
139 DWORD safeopt;
141 /* connection list */
142 ConnectionPoint *cp_list;
143 ConnectionPoint cp_domdocevents;
144 ConnectionPoint cp_propnotif;
145 ConnectionPoint cp_dispatch;
147 /* events */
148 IDispatch *events[EVENTID_LAST];
150 IXMLDOMSchemaCollection2 *namespaces;
153 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
155 IDispatch *disp;
157 switch (V_VT(v))
159 case VT_UNKNOWN:
160 if (V_UNKNOWN(v))
161 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
162 else
163 disp = NULL;
164 break;
165 case VT_DISPATCH:
166 disp = V_DISPATCH(v);
167 if (disp) IDispatch_AddRef(disp);
168 break;
169 default:
170 return DISP_E_TYPEMISMATCH;
173 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
174 doc->events[eid] = disp;
176 return S_OK;
179 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
181 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 In native windows, the whole lifetime management of XMLDOMNodes is
186 managed automatically using reference counts. Wine emulates that by
187 maintaining a reference count to the document that is increased for
188 each IXMLDOMNode pointer passed out for this document. If all these
189 pointers are gone, the document is unreachable and gets freed, that
190 is, all nodes in the tree of the document get freed.
192 You are able to create nodes that are associated to a document (in
193 fact, in msxml's XMLDOM model, all nodes are associated to a document),
194 but not in the tree of that document, for example using the createFoo
195 functions from IXMLDOMDocument. These nodes do not get cleaned up
196 by libxml, so we have to do it ourselves.
198 To catch these nodes, a list of "orphan nodes" is introduced.
199 It contains pointers to all roots of node trees that are
200 associated with the document without being part of the document
201 tree. All nodes with parent==NULL (except for the document root nodes)
202 should be in the orphan node list of their document. All orphan nodes
203 get freed together with the document itself.
206 typedef struct _xmldoc_priv {
207 LONG refs;
208 struct list orphans;
209 domdoc_properties* properties;
210 } xmldoc_priv;
212 typedef struct _orphan_entry {
213 struct list entry;
214 xmlNode * node;
215 } orphan_entry;
217 typedef struct _select_ns_entry {
218 struct list entry;
219 xmlChar const* prefix;
220 xmlChar prefix_end;
221 xmlChar const* href;
222 xmlChar href_end;
223 } select_ns_entry;
225 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
227 return doc->_private;
230 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
232 return priv_from_xmlDocPtr(doc)->properties;
235 BOOL is_xpathmode(const xmlDocPtr doc)
237 return properties_from_xmlDocPtr(doc)->XPath;
240 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
242 properties_from_xmlDocPtr(doc)->XPath = xpath;
245 int registerNamespaces(xmlXPathContextPtr ctxt)
247 int n = 0;
248 const select_ns_entry* ns = NULL;
249 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
251 TRACE("(%p)\n", ctxt);
253 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
255 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
256 ++n;
259 return n;
262 static inline void clear_selectNsList(struct list* pNsList)
264 select_ns_entry *ns, *ns2;
265 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
267 heap_free( ns );
269 list_init(pNsList);
272 static xmldoc_priv * create_priv(void)
274 xmldoc_priv *priv;
275 priv = heap_alloc( sizeof (*priv) );
277 if (priv)
279 priv->refs = 0;
280 list_init( &priv->orphans );
281 priv->properties = NULL;
284 return priv;
287 static domdoc_properties *create_properties(MSXML_VERSION version)
289 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
291 list_init(&properties->selectNsList);
292 properties->preserving = VARIANT_FALSE;
293 properties->schemaCache = NULL;
294 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
295 properties->selectNsStr_len = 0;
297 /* properties that are dependent on object versions */
298 properties->version = version;
299 properties->XPath = (version == MSXML4 || version == MSXML6);
301 /* document url */
302 properties->url = NULL;
304 return properties;
307 static domdoc_properties* copy_properties(domdoc_properties const* properties)
309 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
310 select_ns_entry const* ns = NULL;
311 select_ns_entry* new_ns = NULL;
312 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
313 ptrdiff_t offset;
315 if (pcopy)
317 pcopy->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);
338 if (properties->url)
340 int len = strlenW(properties->url);
342 pcopy->url = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
343 memcpy(pcopy->url, properties->url, len*sizeof(WCHAR));
344 pcopy->url[len] = 0;
346 else
347 pcopy->url = NULL;
350 return pcopy;
353 static void free_properties(domdoc_properties* properties)
355 if (properties)
357 if (properties->schemaCache)
358 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
359 clear_selectNsList(&properties->selectNsList);
360 heap_free((xmlChar*)properties->selectNsStr);
361 CoTaskMemFree(properties->url);
362 heap_free(properties);
366 static void release_namespaces(domdoc *This)
368 if (This->namespaces)
370 IXMLDOMSchemaCollection2_Release(This->namespaces);
371 This->namespaces = NULL;
375 /* links a "<?xml" node as a first child */
376 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
378 assert(doc != NULL);
379 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
382 /* unlinks a first "<?xml" child if it was created */
383 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
385 static const xmlChar xmlA[] = "xml";
386 xmlNodePtr node, first_child;
388 assert(doc != NULL);
390 /* xml declaration node could be created automatically after parsing or added
391 to a tree later */
392 first_child = doc->children;
393 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
395 node = first_child;
396 xmlUnlinkNode( node );
398 else
399 node = NULL;
401 return node;
404 BOOL is_preserving_whitespace(xmlNodePtr node)
406 domdoc_properties* properties = NULL;
407 /* during parsing the xmlDoc._private stuff is not there */
408 if (priv_from_xmlDocPtr(node->doc))
409 properties = properties_from_xmlDocPtr(node->doc);
410 return ((properties && properties->preserving == VARIANT_TRUE) ||
411 xmlNodeGetSpacePreserve(node) == 1);
414 static inline BOOL strn_isspace(xmlChar const* str, int len)
416 for (; str && len > 0 && *str; ++str, --len)
417 if (!isspace(*str))
418 break;
420 return len == 0;
423 static void sax_characters(void *ctx, const xmlChar *ch, int len)
425 xmlParserCtxtPtr ctxt;
426 const domdoc *This;
428 ctxt = (xmlParserCtxtPtr) ctx;
429 This = (const domdoc*) ctxt->_private;
431 if (ctxt->node)
433 xmlChar cur = *(ctxt->input->cur);
435 /* Characters are reported with multiple calls, for example each charref is reported with a separate
436 call and then parser appends it to a single text node or creates a new node if not created.
437 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
438 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
439 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
440 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
441 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
442 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
443 a text node it's safe to ignore.
445 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
447 if (!This->properties->preserving &&
448 !is_preserving_whitespace(ctxt->node) &&
449 strn_isspace(ch, len) &&
450 (!ctxt->node->last ||
451 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
453 return;
456 xmlSAX2Characters(ctxt, ch, len);
459 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
461 va_list ap;
462 va_start(ap, msg);
463 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
464 va_end(ap);
467 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
469 va_list ap;
470 va_start(ap, msg);
471 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
472 va_end(ap);
475 static void sax_serror(void* ctx, xmlErrorPtr err)
477 LIBXML2_CALLBACK_SERROR(doparse, err);
480 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
482 xmlDocPtr doc = NULL;
483 xmlParserCtxtPtr pctx;
484 static xmlSAXHandler sax_handler = {
485 xmlSAX2InternalSubset, /* internalSubset */
486 xmlSAX2IsStandalone, /* isStandalone */
487 xmlSAX2HasInternalSubset, /* hasInternalSubset */
488 xmlSAX2HasExternalSubset, /* hasExternalSubset */
489 xmlSAX2ResolveEntity, /* resolveEntity */
490 xmlSAX2GetEntity, /* getEntity */
491 xmlSAX2EntityDecl, /* entityDecl */
492 xmlSAX2NotationDecl, /* notationDecl */
493 xmlSAX2AttributeDecl, /* attributeDecl */
494 xmlSAX2ElementDecl, /* elementDecl */
495 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
496 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
497 xmlSAX2StartDocument, /* startDocument */
498 xmlSAX2EndDocument, /* endDocument */
499 xmlSAX2StartElement, /* startElement */
500 xmlSAX2EndElement, /* endElement */
501 xmlSAX2Reference, /* reference */
502 sax_characters, /* characters */
503 sax_characters, /* ignorableWhitespace */
504 xmlSAX2ProcessingInstruction, /* processingInstruction */
505 xmlSAX2Comment, /* comment */
506 sax_warning, /* warning */
507 sax_error, /* error */
508 sax_error, /* fatalError */
509 xmlSAX2GetParameterEntity, /* getParameterEntity */
510 xmlSAX2CDataBlock, /* cdataBlock */
511 xmlSAX2ExternalSubset, /* externalSubset */
512 0, /* initialized */
513 NULL, /* _private */
514 xmlSAX2StartElementNs, /* startElementNs */
515 xmlSAX2EndElementNs, /* endElementNs */
516 sax_serror /* serror */
519 pctx = xmlCreateMemoryParserCtxt(ptr, len);
520 if (!pctx)
522 ERR("Failed to create parser context\n");
523 return NULL;
526 if (pctx->sax) xmlFree(pctx->sax);
527 pctx->sax = &sax_handler;
528 pctx->_private = This;
529 pctx->recovery = 0;
531 if (encoding != XML_CHAR_ENCODING_NONE)
532 xmlSwitchEncoding(pctx, encoding);
534 xmlParseDocument(pctx);
536 if (pctx->wellFormed)
538 doc = pctx->myDoc;
540 else
542 xmlFreeDoc(pctx->myDoc);
543 pctx->myDoc = NULL;
545 pctx->sax = NULL;
546 xmlFreeParserCtxt(pctx);
548 /* TODO: put this in one of the SAX callbacks */
549 /* create first child as a <?xml...?> */
550 if (doc && doc->standalone != -1)
552 xmlNodePtr node;
553 char buff[30];
554 xmlChar *xmlbuff = (xmlChar*)buff;
556 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
558 /* version attribute can't be omitted */
559 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
560 xmlNodeAddContent( node, xmlbuff );
562 if (doc->encoding)
564 sprintf(buff, " encoding=\"%s\"", doc->encoding);
565 xmlNodeAddContent( node, xmlbuff );
568 if (doc->standalone != -2)
570 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
571 xmlNodeAddContent( node, xmlbuff );
574 xmldoc_link_xmldecl( doc, node );
577 return doc;
580 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
582 doc->_private = create_priv();
583 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
586 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
588 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
589 TRACE("(%p)->(%d)\n", doc, ref);
590 return ref;
593 LONG xmldoc_add_ref(xmlDocPtr doc)
595 return xmldoc_add_refs(doc, 1);
598 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
600 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
601 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
602 TRACE("(%p)->(%d)\n", doc, ref);
604 if (ref < 0)
605 WARN("negative refcount, expect troubles\n");
607 if (ref == 0)
609 orphan_entry *orphan, *orphan2;
610 TRACE("freeing docptr %p\n", doc);
612 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
614 xmlFreeNode( orphan->node );
615 heap_free( orphan );
617 free_properties(priv->properties);
618 heap_free(doc->_private);
620 xmlFreeDoc(doc);
623 return ref;
626 LONG xmldoc_release(xmlDocPtr doc)
628 return xmldoc_release_refs(doc, 1);
631 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
633 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
634 orphan_entry *entry;
636 entry = heap_alloc( sizeof (*entry) );
637 if(!entry)
638 return E_OUTOFMEMORY;
640 entry->node = node;
641 list_add_head( &priv->orphans, &entry->entry );
642 return S_OK;
645 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
647 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
648 orphan_entry *entry, *entry2;
650 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
652 if( entry->node == node )
654 list_remove( &entry->entry );
655 heap_free( entry );
656 return S_OK;
660 return S_FALSE;
663 static inline xmlDocPtr get_doc( domdoc *This )
665 return This->node.node->doc;
668 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
670 release_namespaces(This);
672 if(This->node.node)
674 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
675 if (xmldoc_release(get_doc(This)) != 0)
676 priv_from_xmlDocPtr(get_doc(This))->properties =
677 copy_properties(This->properties);
680 This->node.node = (xmlNodePtr) xml;
682 if(This->node.node)
684 xmldoc_add_ref(get_doc(This));
685 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
688 return S_OK;
691 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
693 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
696 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
698 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
701 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
703 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
706 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
708 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
711 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
713 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
716 /************************************************************************
717 * domdoc implementation of IPersistStream.
719 static HRESULT WINAPI PersistStreamInit_QueryInterface(
720 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
722 domdoc* This = impl_from_IPersistStreamInit(iface);
723 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
726 static ULONG WINAPI PersistStreamInit_AddRef(
727 IPersistStreamInit *iface)
729 domdoc* This = impl_from_IPersistStreamInit(iface);
730 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
733 static ULONG WINAPI PersistStreamInit_Release(
734 IPersistStreamInit *iface)
736 domdoc* This = impl_from_IPersistStreamInit(iface);
737 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
740 static HRESULT WINAPI PersistStreamInit_GetClassID(
741 IPersistStreamInit *iface, CLSID *classid)
743 domdoc* This = impl_from_IPersistStreamInit(iface);
744 TRACE("(%p)->(%p)\n", This, classid);
746 if(!classid)
747 return E_POINTER;
749 *classid = *DOMDocument_version(This->properties->version);
751 return S_OK;
754 static HRESULT WINAPI PersistStreamInit_IsDirty(
755 IPersistStreamInit *iface)
757 domdoc *This = impl_from_IPersistStreamInit(iface);
758 FIXME("(%p): stub!\n", This);
759 return S_FALSE;
762 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
764 DWORD read, written, len;
765 xmlDocPtr xmldoc = NULL;
766 IStream *hstream;
767 HGLOBAL hglobal;
768 BYTE buf[4096];
769 HRESULT hr;
770 char *ptr;
772 hstream = NULL;
773 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
774 if (FAILED(hr))
775 return hr;
779 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
780 hr = IStream_Write(hstream, buf, read, &written);
781 } while(SUCCEEDED(hr) && written != 0 && read != 0);
783 if (FAILED(hr))
785 ERR("failed to copy stream 0x%08x\n", hr);
786 IStream_Release(hstream);
787 return hr;
790 hr = GetHGlobalFromStream(hstream, &hglobal);
791 if (FAILED(hr))
792 return hr;
794 len = GlobalSize(hglobal);
795 ptr = GlobalLock(hglobal);
796 if (len)
797 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
798 GlobalUnlock(hglobal);
800 if (!xmldoc)
802 ERR("Failed to parse xml\n");
803 return E_FAIL;
806 xmldoc->_private = create_priv();
808 return attach_xmldoc(doc, xmldoc);
811 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
813 domdoc *This = impl_from_IPersistStreamInit(iface);
815 TRACE("(%p)->(%p)\n", This, stream);
817 if (!stream)
818 return E_INVALIDARG;
820 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
823 static HRESULT WINAPI PersistStreamInit_Save(
824 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
826 domdoc *This = impl_from_IPersistStreamInit(iface);
827 BSTR xmlString;
828 HRESULT hr;
830 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
832 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
833 if(hr == S_OK)
835 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
837 hr = IStream_Write( stream, xmlString, len, NULL );
838 SysFreeString(xmlString);
841 TRACE("ret 0x%08x\n", hr);
843 return hr;
846 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
847 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
849 domdoc *This = impl_from_IPersistStreamInit(iface);
850 TRACE("(%p)->(%p)\n", This, pcbSize);
851 return E_NOTIMPL;
854 static HRESULT WINAPI PersistStreamInit_InitNew(
855 IPersistStreamInit *iface)
857 domdoc *This = impl_from_IPersistStreamInit(iface);
858 TRACE("(%p)\n", This);
859 return S_OK;
862 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
864 PersistStreamInit_QueryInterface,
865 PersistStreamInit_AddRef,
866 PersistStreamInit_Release,
867 PersistStreamInit_GetClassID,
868 PersistStreamInit_IsDirty,
869 PersistStreamInit_Load,
870 PersistStreamInit_Save,
871 PersistStreamInit_GetSizeMax,
872 PersistStreamInit_InitNew
875 /* IXMLDOMDocument3 interface */
877 static const tid_t domdoc_se_tids[] = {
878 IXMLDOMNode_tid,
879 IXMLDOMDocument_tid,
880 IXMLDOMDocument2_tid,
881 IXMLDOMDocument3_tid,
882 NULL_tid
885 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
887 domdoc *This = impl_from_IXMLDOMDocument3( iface );
889 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
891 *ppvObject = NULL;
893 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
894 IsEqualGUID( riid, &IID_IDispatch ) ||
895 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
896 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
897 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
898 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
900 *ppvObject = iface;
902 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
903 IsEqualGUID(&IID_IPersistStreamInit, riid))
905 *ppvObject = &This->IPersistStreamInit_iface;
907 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
909 *ppvObject = &This->IObjectWithSite_iface;
911 else if (IsEqualGUID(&IID_IObjectSafety, riid))
913 *ppvObject = &This->IObjectSafety_iface;
915 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
917 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
919 else if(node_query_interface(&This->node, riid, ppvObject))
921 return *ppvObject ? S_OK : E_NOINTERFACE;
923 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
925 *ppvObject = &This->IConnectionPointContainer_iface;
927 else
929 TRACE("interface %s not implemented\n", debugstr_guid(riid));
930 return E_NOINTERFACE;
933 IUnknown_AddRef((IUnknown*)*ppvObject);
935 return S_OK;
938 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
940 domdoc *This = impl_from_IXMLDOMDocument3( iface );
941 ULONG ref = InterlockedIncrement( &This->ref );
942 TRACE("(%p)->(%d)\n", This, ref );
943 return ref;
946 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
948 domdoc *This = impl_from_IXMLDOMDocument3( iface );
949 LONG ref = InterlockedDecrement( &This->ref );
951 TRACE("(%p)->(%d)\n", This, ref );
953 if ( ref == 0 )
955 int eid;
957 if (This->site)
958 IUnknown_Release( This->site );
959 destroy_xmlnode(&This->node);
961 for (eid = 0; eid < EVENTID_LAST; eid++)
962 if (This->events[eid]) IDispatch_Release(This->events[eid]);
964 release_namespaces(This);
965 heap_free(This);
968 return ref;
971 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
973 domdoc *This = impl_from_IXMLDOMDocument3( iface );
974 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
977 static HRESULT WINAPI domdoc_GetTypeInfo(
978 IXMLDOMDocument3 *iface,
979 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
981 domdoc *This = impl_from_IXMLDOMDocument3( iface );
982 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
985 static HRESULT WINAPI domdoc_GetIDsOfNames(
986 IXMLDOMDocument3 *iface,
987 REFIID riid,
988 LPOLESTR* rgszNames,
989 UINT cNames,
990 LCID lcid,
991 DISPID* rgDispId)
993 domdoc *This = impl_from_IXMLDOMDocument3( iface );
994 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
995 riid, rgszNames, cNames, lcid, rgDispId);
998 static HRESULT WINAPI domdoc_Invoke(
999 IXMLDOMDocument3 *iface,
1000 DISPID dispIdMember,
1001 REFIID riid,
1002 LCID lcid,
1003 WORD wFlags,
1004 DISPPARAMS* pDispParams,
1005 VARIANT* pVarResult,
1006 EXCEPINFO* pExcepInfo,
1007 UINT* puArgErr)
1009 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1010 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1011 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1014 static HRESULT WINAPI domdoc_get_nodeName(
1015 IXMLDOMDocument3 *iface,
1016 BSTR* name )
1018 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1020 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1022 TRACE("(%p)->(%p)\n", This, name);
1024 return return_bstr(documentW, name);
1028 static HRESULT WINAPI domdoc_get_nodeValue(
1029 IXMLDOMDocument3 *iface,
1030 VARIANT* value )
1032 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1034 TRACE("(%p)->(%p)\n", This, value);
1036 if(!value)
1037 return E_INVALIDARG;
1039 V_VT(value) = VT_NULL;
1040 V_BSTR(value) = NULL; /* tests show that we should do this */
1041 return S_FALSE;
1045 static HRESULT WINAPI domdoc_put_nodeValue(
1046 IXMLDOMDocument3 *iface,
1047 VARIANT value)
1049 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1050 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1051 return E_FAIL;
1055 static HRESULT WINAPI domdoc_get_nodeType(
1056 IXMLDOMDocument3 *iface,
1057 DOMNodeType* type )
1059 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1061 TRACE("(%p)->(%p)\n", This, type);
1063 *type = NODE_DOCUMENT;
1064 return S_OK;
1068 static HRESULT WINAPI domdoc_get_parentNode(
1069 IXMLDOMDocument3 *iface,
1070 IXMLDOMNode** parent )
1072 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1074 TRACE("(%p)->(%p)\n", This, parent);
1076 return node_get_parent(&This->node, parent);
1080 static HRESULT WINAPI domdoc_get_childNodes(
1081 IXMLDOMDocument3 *iface,
1082 IXMLDOMNodeList** childList )
1084 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1086 TRACE("(%p)->(%p)\n", This, childList);
1088 return node_get_child_nodes(&This->node, childList);
1092 static HRESULT WINAPI domdoc_get_firstChild(
1093 IXMLDOMDocument3 *iface,
1094 IXMLDOMNode** firstChild )
1096 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1098 TRACE("(%p)->(%p)\n", This, firstChild);
1100 return node_get_first_child(&This->node, firstChild);
1104 static HRESULT WINAPI domdoc_get_lastChild(
1105 IXMLDOMDocument3 *iface,
1106 IXMLDOMNode** lastChild )
1108 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1110 TRACE("(%p)->(%p)\n", This, lastChild);
1112 return node_get_last_child(&This->node, lastChild);
1116 static HRESULT WINAPI domdoc_get_previousSibling(
1117 IXMLDOMDocument3 *iface,
1118 IXMLDOMNode** previousSibling )
1120 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1122 TRACE("(%p)->(%p)\n", This, previousSibling);
1124 return return_null_node(previousSibling);
1128 static HRESULT WINAPI domdoc_get_nextSibling(
1129 IXMLDOMDocument3 *iface,
1130 IXMLDOMNode** nextSibling )
1132 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1134 TRACE("(%p)->(%p)\n", This, nextSibling);
1136 return return_null_node(nextSibling);
1140 static HRESULT WINAPI domdoc_get_attributes(
1141 IXMLDOMDocument3 *iface,
1142 IXMLDOMNamedNodeMap** attributeMap )
1144 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1146 TRACE("(%p)->(%p)\n", This, attributeMap);
1148 return return_null_ptr((void**)attributeMap);
1152 static HRESULT WINAPI domdoc_insertBefore(
1153 IXMLDOMDocument3 *iface,
1154 IXMLDOMNode* newChild,
1155 VARIANT refChild,
1156 IXMLDOMNode** outNewChild )
1158 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1159 DOMNodeType type;
1160 HRESULT hr;
1162 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1164 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1165 if (hr != S_OK) return hr;
1167 TRACE("new node type %d\n", type);
1168 switch (type)
1170 case NODE_ATTRIBUTE:
1171 case NODE_DOCUMENT:
1172 case NODE_CDATA_SECTION:
1173 if (outNewChild) *outNewChild = NULL;
1174 return E_FAIL;
1175 default:
1176 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1180 static HRESULT WINAPI domdoc_replaceChild(
1181 IXMLDOMDocument3 *iface,
1182 IXMLDOMNode* newChild,
1183 IXMLDOMNode* oldChild,
1184 IXMLDOMNode** outOldChild)
1186 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1188 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1190 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1194 static HRESULT WINAPI domdoc_removeChild(
1195 IXMLDOMDocument3 *iface,
1196 IXMLDOMNode *child,
1197 IXMLDOMNode **oldChild)
1199 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1200 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1201 return node_remove_child(&This->node, child, oldChild);
1205 static HRESULT WINAPI domdoc_appendChild(
1206 IXMLDOMDocument3 *iface,
1207 IXMLDOMNode *child,
1208 IXMLDOMNode **outChild)
1210 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1211 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1212 return node_append_child(&This->node, child, outChild);
1216 static HRESULT WINAPI domdoc_hasChildNodes(
1217 IXMLDOMDocument3 *iface,
1218 VARIANT_BOOL *ret)
1220 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1221 TRACE("(%p)->(%p)\n", This, ret);
1222 return node_has_childnodes(&This->node, ret);
1226 static HRESULT WINAPI domdoc_get_ownerDocument(
1227 IXMLDOMDocument3 *iface,
1228 IXMLDOMDocument **doc)
1230 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1231 TRACE("(%p)->(%p)\n", This, doc);
1232 return node_get_owner_doc(&This->node, doc);
1236 static HRESULT WINAPI domdoc_cloneNode(
1237 IXMLDOMDocument3 *iface,
1238 VARIANT_BOOL deep,
1239 IXMLDOMNode** outNode)
1241 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1242 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1243 return node_clone( &This->node, deep, outNode );
1247 static HRESULT WINAPI domdoc_get_nodeTypeString(
1248 IXMLDOMDocument3 *iface,
1249 BSTR *p)
1251 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1252 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1254 TRACE("(%p)->(%p)\n", This, p);
1256 return return_bstr(documentW, p);
1260 static HRESULT WINAPI domdoc_get_text(
1261 IXMLDOMDocument3 *iface,
1262 BSTR *p)
1264 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1265 TRACE("(%p)->(%p)\n", This, p);
1266 return node_get_text(&This->node, p);
1270 static HRESULT WINAPI domdoc_put_text(
1271 IXMLDOMDocument3 *iface,
1272 BSTR text )
1274 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1275 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1276 return E_FAIL;
1280 static HRESULT WINAPI domdoc_get_specified(
1281 IXMLDOMDocument3 *iface,
1282 VARIANT_BOOL* isSpecified )
1284 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1285 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1286 *isSpecified = VARIANT_TRUE;
1287 return S_OK;
1291 static HRESULT WINAPI domdoc_get_definition(
1292 IXMLDOMDocument3 *iface,
1293 IXMLDOMNode** definitionNode )
1295 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1296 FIXME("(%p)->(%p)\n", This, definitionNode);
1297 return E_NOTIMPL;
1301 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1302 IXMLDOMDocument3 *iface,
1303 VARIANT* v )
1305 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1306 TRACE("(%p)->(%p)\n", This, v);
1307 return return_null_var(v);
1310 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1311 IXMLDOMDocument3 *iface,
1312 VARIANT typedValue )
1314 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1315 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1316 return E_NOTIMPL;
1320 static HRESULT WINAPI domdoc_get_dataType(
1321 IXMLDOMDocument3 *iface,
1322 VARIANT* typename )
1324 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1325 TRACE("(%p)->(%p)\n", This, typename);
1326 return return_null_var( typename );
1330 static HRESULT WINAPI domdoc_put_dataType(
1331 IXMLDOMDocument3 *iface,
1332 BSTR dataTypeName )
1334 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1336 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1338 if(!dataTypeName)
1339 return E_INVALIDARG;
1341 return E_FAIL;
1344 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1346 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1349 static HRESULT WINAPI domdoc_get_xml(
1350 IXMLDOMDocument3 *iface,
1351 BSTR* p)
1353 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1354 xmlSaveCtxtPtr ctxt;
1355 xmlBufferPtr buf;
1356 int options;
1357 long ret;
1359 TRACE("(%p)->(%p)\n", This, p);
1361 if(!p)
1362 return E_INVALIDARG;
1364 *p = NULL;
1366 buf = xmlBufferCreate();
1367 if(!buf)
1368 return E_OUTOFMEMORY;
1370 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1371 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1373 if(!ctxt)
1375 xmlBufferFree(buf);
1376 return E_OUTOFMEMORY;
1379 ret = xmlSaveDoc(ctxt, get_doc(This));
1380 /* flushes on close */
1381 xmlSaveClose(ctxt);
1383 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1384 if(ret != -1 && xmlBufferLength(buf) > 0)
1386 BSTR content;
1388 content = bstr_from_xmlChar(xmlBufferContent(buf));
1389 content = EnsureCorrectEOL(content);
1391 *p = content;
1393 else
1395 *p = SysAllocStringLen(NULL, 0);
1398 xmlBufferFree(buf);
1400 return *p ? S_OK : E_OUTOFMEMORY;
1404 static HRESULT WINAPI domdoc_transformNode(
1405 IXMLDOMDocument3 *iface,
1406 IXMLDOMNode *node,
1407 BSTR *p)
1409 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1410 TRACE("(%p)->(%p %p)\n", This, node, p);
1411 return node_transform_node(&This->node, node, p);
1415 static HRESULT WINAPI domdoc_selectNodes(
1416 IXMLDOMDocument3 *iface,
1417 BSTR p,
1418 IXMLDOMNodeList **outList)
1420 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1421 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1422 return node_select_nodes(&This->node, p, outList);
1426 static HRESULT WINAPI domdoc_selectSingleNode(
1427 IXMLDOMDocument3 *iface,
1428 BSTR p,
1429 IXMLDOMNode **outNode)
1431 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1432 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1433 return node_select_singlenode(&This->node, p, outNode);
1437 static HRESULT WINAPI domdoc_get_parsed(
1438 IXMLDOMDocument3 *iface,
1439 VARIANT_BOOL* isParsed )
1441 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1442 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1443 *isParsed = VARIANT_TRUE;
1444 return S_OK;
1447 static HRESULT WINAPI domdoc_get_namespaceURI(
1448 IXMLDOMDocument3 *iface,
1449 BSTR* namespaceURI )
1451 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1452 TRACE("(%p)->(%p)\n", This, namespaceURI);
1453 return return_null_bstr( namespaceURI );
1456 static HRESULT WINAPI domdoc_get_prefix(
1457 IXMLDOMDocument3 *iface,
1458 BSTR* prefix )
1460 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1461 TRACE("(%p)->(%p)\n", This, prefix);
1462 return return_null_bstr( prefix );
1466 static HRESULT WINAPI domdoc_get_baseName(
1467 IXMLDOMDocument3 *iface,
1468 BSTR* name )
1470 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1471 TRACE("(%p)->(%p)\n", This, name);
1472 return return_null_bstr( name );
1476 static HRESULT WINAPI domdoc_transformNodeToObject(
1477 IXMLDOMDocument3 *iface,
1478 IXMLDOMNode* stylesheet,
1479 VARIANT outputObject)
1481 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1482 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1483 return E_NOTIMPL;
1487 static HRESULT WINAPI domdoc_get_doctype(
1488 IXMLDOMDocument3 *iface,
1489 IXMLDOMDocumentType** doctype )
1491 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1492 IXMLDOMNode *node;
1493 xmlDtdPtr dtd;
1494 HRESULT hr;
1496 TRACE("(%p)->(%p)\n", This, doctype);
1498 if (!doctype) return E_INVALIDARG;
1500 *doctype = NULL;
1502 dtd = xmlGetIntSubset(get_doc(This));
1503 if (!dtd) return S_FALSE;
1505 node = create_node((xmlNodePtr)dtd);
1506 if (!node) return S_FALSE;
1508 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1509 IXMLDOMNode_Release(node);
1511 return hr;
1515 static HRESULT WINAPI domdoc_get_implementation(
1516 IXMLDOMDocument3 *iface,
1517 IXMLDOMImplementation** impl )
1519 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1521 TRACE("(%p)->(%p)\n", This, impl);
1523 if(!impl)
1524 return E_INVALIDARG;
1526 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1528 return S_OK;
1531 static HRESULT WINAPI domdoc_get_documentElement(
1532 IXMLDOMDocument3 *iface,
1533 IXMLDOMElement** DOMElement )
1535 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1536 IXMLDOMNode *element_node;
1537 xmlNodePtr root;
1538 HRESULT hr;
1540 TRACE("(%p)->(%p)\n", This, DOMElement);
1542 if(!DOMElement)
1543 return E_INVALIDARG;
1545 *DOMElement = NULL;
1547 root = xmlDocGetRootElement( get_doc(This) );
1548 if ( !root )
1549 return S_FALSE;
1551 element_node = create_node( root );
1552 if(!element_node) return S_FALSE;
1554 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1555 IXMLDOMNode_Release(element_node);
1557 return hr;
1561 static HRESULT WINAPI domdoc_put_documentElement(
1562 IXMLDOMDocument3 *iface,
1563 IXMLDOMElement* DOMElement )
1565 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1566 IXMLDOMNode *elementNode;
1567 xmlNodePtr oldRoot;
1568 xmlDocPtr old_doc;
1569 xmlnode *xmlNode;
1570 int refcount = 0;
1571 HRESULT hr;
1573 TRACE("(%p)->(%p)\n", This, DOMElement);
1575 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1576 if(FAILED(hr))
1577 return hr;
1579 xmlNode = get_node_obj( elementNode );
1580 if(!xmlNode) return E_FAIL;
1582 if(!xmlNode->node->parent)
1583 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1584 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1586 old_doc = xmlNode->node->doc;
1587 if (old_doc != get_doc(This))
1588 refcount = xmlnode_get_inst_cnt(xmlNode);
1590 /* old root is still orphaned by its document, update refcount from new root */
1591 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1592 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1593 if (refcount) xmldoc_release_refs(old_doc, refcount);
1594 IXMLDOMNode_Release( elementNode );
1596 if(oldRoot)
1597 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1599 return S_OK;
1603 static HRESULT WINAPI domdoc_createElement(
1604 IXMLDOMDocument3 *iface,
1605 BSTR tagname,
1606 IXMLDOMElement** element )
1608 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1609 IXMLDOMNode *node;
1610 VARIANT type;
1611 HRESULT hr;
1613 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1615 if (!element || !tagname) return E_INVALIDARG;
1617 V_VT(&type) = VT_I1;
1618 V_I1(&type) = NODE_ELEMENT;
1620 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1621 if (hr == S_OK)
1623 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1624 IXMLDOMNode_Release(node);
1627 return hr;
1631 static HRESULT WINAPI domdoc_createDocumentFragment(
1632 IXMLDOMDocument3 *iface,
1633 IXMLDOMDocumentFragment** frag )
1635 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1636 IXMLDOMNode *node;
1637 VARIANT type;
1638 HRESULT hr;
1640 TRACE("(%p)->(%p)\n", This, frag);
1642 if (!frag) return E_INVALIDARG;
1644 *frag = NULL;
1646 V_VT(&type) = VT_I1;
1647 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1649 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1650 if (hr == S_OK)
1652 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1653 IXMLDOMNode_Release(node);
1656 return hr;
1660 static HRESULT WINAPI domdoc_createTextNode(
1661 IXMLDOMDocument3 *iface,
1662 BSTR data,
1663 IXMLDOMText** text )
1665 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1666 IXMLDOMNode *node;
1667 VARIANT type;
1668 HRESULT hr;
1670 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1672 if (!text) return E_INVALIDARG;
1674 *text = NULL;
1676 V_VT(&type) = VT_I1;
1677 V_I1(&type) = NODE_TEXT;
1679 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1680 if (hr == S_OK)
1682 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1683 IXMLDOMNode_Release(node);
1684 hr = IXMLDOMText_put_data(*text, data);
1687 return hr;
1691 static HRESULT WINAPI domdoc_createComment(
1692 IXMLDOMDocument3 *iface,
1693 BSTR data,
1694 IXMLDOMComment** comment )
1696 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1697 VARIANT type;
1698 HRESULT hr;
1699 IXMLDOMNode *node;
1701 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1703 if (!comment) return E_INVALIDARG;
1705 *comment = NULL;
1707 V_VT(&type) = VT_I1;
1708 V_I1(&type) = NODE_COMMENT;
1710 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1711 if (hr == S_OK)
1713 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1714 IXMLDOMNode_Release(node);
1715 hr = IXMLDOMComment_put_data(*comment, data);
1718 return hr;
1722 static HRESULT WINAPI domdoc_createCDATASection(
1723 IXMLDOMDocument3 *iface,
1724 BSTR data,
1725 IXMLDOMCDATASection** cdata )
1727 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1728 IXMLDOMNode *node;
1729 VARIANT type;
1730 HRESULT hr;
1732 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1734 if (!cdata) return E_INVALIDARG;
1736 *cdata = NULL;
1738 V_VT(&type) = VT_I1;
1739 V_I1(&type) = NODE_CDATA_SECTION;
1741 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1742 if (hr == S_OK)
1744 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1745 IXMLDOMNode_Release(node);
1746 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1749 return hr;
1753 static HRESULT WINAPI domdoc_createProcessingInstruction(
1754 IXMLDOMDocument3 *iface,
1755 BSTR target,
1756 BSTR data,
1757 IXMLDOMProcessingInstruction** pi )
1759 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1760 IXMLDOMNode *node;
1761 VARIANT type;
1762 HRESULT hr;
1764 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1766 if (!pi) return E_INVALIDARG;
1768 *pi = NULL;
1770 V_VT(&type) = VT_I1;
1771 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1773 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1774 if (hr == S_OK)
1776 xmlnode *node_obj;
1778 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1779 node_obj = get_node_obj(node);
1780 hr = node_set_content(node_obj, data);
1782 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1783 IXMLDOMNode_Release(node);
1786 return hr;
1790 static HRESULT WINAPI domdoc_createAttribute(
1791 IXMLDOMDocument3 *iface,
1792 BSTR name,
1793 IXMLDOMAttribute** attribute )
1795 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1796 IXMLDOMNode *node;
1797 VARIANT type;
1798 HRESULT hr;
1800 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1802 if (!attribute || !name) return E_INVALIDARG;
1804 V_VT(&type) = VT_I1;
1805 V_I1(&type) = NODE_ATTRIBUTE;
1807 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1808 if (hr == S_OK)
1810 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1811 IXMLDOMNode_Release(node);
1814 return hr;
1818 static HRESULT WINAPI domdoc_createEntityReference(
1819 IXMLDOMDocument3 *iface,
1820 BSTR name,
1821 IXMLDOMEntityReference** entityref )
1823 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1824 IXMLDOMNode *node;
1825 VARIANT type;
1826 HRESULT hr;
1828 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1830 if (!entityref) return E_INVALIDARG;
1832 *entityref = NULL;
1834 V_VT(&type) = VT_I1;
1835 V_I1(&type) = NODE_ENTITY_REFERENCE;
1837 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1838 if (hr == S_OK)
1840 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1841 IXMLDOMNode_Release(node);
1844 return hr;
1847 xmlChar* tagName_to_XPath(const BSTR tagName)
1849 xmlChar *query, *tmp;
1850 static const xmlChar mod_pre[] = "*[local-name()='";
1851 static const xmlChar mod_post[] = "']";
1852 static const xmlChar prefix[] = "descendant::";
1853 const WCHAR *tokBegin, *tokEnd;
1854 int len;
1856 query = xmlStrdup(prefix);
1858 tokBegin = tagName;
1859 while (tokBegin && *tokBegin)
1861 switch (*tokBegin)
1863 case '/':
1864 query = xmlStrcat(query, BAD_CAST "/");
1865 ++tokBegin;
1866 break;
1867 case '*':
1868 query = xmlStrcat(query, BAD_CAST "*");
1869 ++tokBegin;
1870 break;
1871 default:
1872 query = xmlStrcat(query, mod_pre);
1873 tokEnd = tokBegin;
1874 while (*tokEnd && *tokEnd != '/')
1875 ++tokEnd;
1876 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1877 tmp = xmlMalloc(len);
1878 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1879 query = xmlStrncat(query, tmp, len);
1880 xmlFree(tmp);
1881 tokBegin = tokEnd;
1882 query = xmlStrcat(query, mod_post);
1886 return query;
1889 static HRESULT WINAPI domdoc_getElementsByTagName(
1890 IXMLDOMDocument3 *iface,
1891 BSTR tagName,
1892 IXMLDOMNodeList** resultList )
1894 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1895 xmlChar *query;
1896 HRESULT hr;
1897 BOOL XPath;
1899 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1901 if (!tagName || !resultList) return E_INVALIDARG;
1903 XPath = This->properties->XPath;
1904 This->properties->XPath = TRUE;
1905 query = tagName_to_XPath(tagName);
1906 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1907 xmlFree(query);
1908 This->properties->XPath = XPath;
1910 return hr;
1913 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1915 VARIANT tmp;
1916 HRESULT hr;
1918 VariantInit(&tmp);
1919 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1920 if(FAILED(hr))
1921 return E_INVALIDARG;
1923 *type = V_I4(&tmp);
1925 return S_OK;
1928 static HRESULT WINAPI domdoc_createNode(
1929 IXMLDOMDocument3 *iface,
1930 VARIANT Type,
1931 BSTR name,
1932 BSTR namespaceURI,
1933 IXMLDOMNode** node )
1935 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1936 DOMNodeType node_type;
1937 xmlNodePtr xmlnode;
1938 xmlChar *xml_name, *href;
1939 HRESULT hr;
1941 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1943 if(!node) return E_INVALIDARG;
1945 hr = get_node_type(Type, &node_type);
1946 if(FAILED(hr)) return hr;
1948 TRACE("node_type %d\n", node_type);
1950 /* exit earlier for types that need name */
1951 switch(node_type)
1953 case NODE_ELEMENT:
1954 case NODE_ATTRIBUTE:
1955 case NODE_ENTITY_REFERENCE:
1956 case NODE_PROCESSING_INSTRUCTION:
1957 if (!name || *name == 0) return E_FAIL;
1958 break;
1959 default:
1960 break;
1963 xml_name = xmlchar_from_wchar(name);
1964 /* prevent empty href to be allocated */
1965 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1967 switch(node_type)
1969 case NODE_ELEMENT:
1971 xmlChar *local, *prefix;
1973 local = xmlSplitQName2(xml_name, &prefix);
1975 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1977 /* allow to create default namespace xmlns= */
1978 if (local || (href && *href))
1980 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1981 xmlSetNs(xmlnode, ns);
1984 xmlFree(local);
1985 xmlFree(prefix);
1987 break;
1989 case NODE_ATTRIBUTE:
1991 xmlChar *local, *prefix;
1993 local = xmlSplitQName2(xml_name, &prefix);
1995 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
1997 if (local || (href && *href))
1999 /* we need a floating namespace here, it can't be created linked to attribute from
2000 a start */
2001 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2002 xmlSetNs(xmlnode, ns);
2005 xmlFree(local);
2006 xmlFree(prefix);
2008 break;
2010 case NODE_TEXT:
2011 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2012 break;
2013 case NODE_CDATA_SECTION:
2014 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2015 break;
2016 case NODE_ENTITY_REFERENCE:
2017 xmlnode = xmlNewReference(get_doc(This), xml_name);
2018 break;
2019 case NODE_PROCESSING_INSTRUCTION:
2020 #ifdef HAVE_XMLNEWDOCPI
2021 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2022 #else
2023 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2024 xmlnode = NULL;
2025 #endif
2026 break;
2027 case NODE_COMMENT:
2028 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2029 break;
2030 case NODE_DOCUMENT_FRAGMENT:
2031 xmlnode = xmlNewDocFragment(get_doc(This));
2032 break;
2033 /* unsupported types */
2034 case NODE_DOCUMENT:
2035 case NODE_DOCUMENT_TYPE:
2036 case NODE_ENTITY:
2037 case NODE_NOTATION:
2038 heap_free(xml_name);
2039 return E_INVALIDARG;
2040 default:
2041 FIXME("unhandled node type %d\n", node_type);
2042 xmlnode = NULL;
2043 break;
2046 *node = create_node(xmlnode);
2047 heap_free(xml_name);
2048 heap_free(href);
2050 if(*node)
2052 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2053 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2054 return S_OK;
2057 return E_FAIL;
2060 static HRESULT WINAPI domdoc_nodeFromID(
2061 IXMLDOMDocument3 *iface,
2062 BSTR idString,
2063 IXMLDOMNode** node )
2065 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2066 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2067 return E_NOTIMPL;
2070 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2072 domdoc *This = obj;
2073 xmlDocPtr xmldoc;
2075 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2076 if(xmldoc) {
2077 xmldoc->_private = create_priv();
2078 return attach_xmldoc(This, xmldoc);
2081 return E_FAIL;
2084 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2086 bsc_t *bsc;
2087 HRESULT hr;
2089 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2090 if(FAILED(hr))
2091 return hr;
2093 return detach_bsc(bsc);
2096 static HRESULT WINAPI domdoc_load(
2097 IXMLDOMDocument3 *iface,
2098 VARIANT source,
2099 VARIANT_BOOL* isSuccessful )
2101 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2102 LPWSTR filename = NULL;
2103 HRESULT hr = S_FALSE;
2104 xmlDocPtr xmldoc;
2106 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2108 if (!isSuccessful)
2109 return E_POINTER;
2110 *isSuccessful = VARIANT_FALSE;
2112 assert( &This->node );
2114 switch( V_VT(&source) )
2116 case VT_BSTR:
2117 filename = V_BSTR(&source);
2118 break;
2119 case VT_BSTR|VT_BYREF:
2120 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2121 filename = *V_BSTRREF(&source);
2122 break;
2123 case VT_ARRAY|VT_UI1:
2125 SAFEARRAY *psa = V_ARRAY(&source);
2126 char *str;
2127 LONG len;
2128 UINT dim = SafeArrayGetDim(psa);
2130 switch (dim)
2132 case 0:
2133 ERR("SAFEARRAY == NULL\n");
2134 hr = This->error = E_INVALIDARG;
2135 break;
2136 case 1:
2137 /* Only takes UTF-8 strings.
2138 * NOT NULL-terminated. */
2139 SafeArrayAccessData(psa, (void**)&str);
2140 SafeArrayGetUBound(psa, 1, &len);
2142 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2144 hr = This->error = S_OK;
2145 *isSuccessful = VARIANT_TRUE;
2146 TRACE("parsed document %p\n", xmldoc);
2148 else
2150 This->error = E_FAIL;
2151 TRACE("failed to parse document\n");
2154 SafeArrayUnaccessData(psa);
2156 if(xmldoc)
2158 xmldoc->_private = create_priv();
2159 return attach_xmldoc(This, xmldoc);
2161 break;
2162 default:
2163 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2164 hr = This->error = E_NOTIMPL;
2167 break;
2168 case VT_UNKNOWN:
2170 ISequentialStream *stream = NULL;
2171 IXMLDOMDocument3 *newdoc = NULL;
2173 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2175 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2176 if(hr == S_OK)
2178 if(newdoc)
2180 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2182 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2183 xmldoc->_private = create_priv();
2184 hr = attach_xmldoc(This, xmldoc);
2186 if(SUCCEEDED(hr))
2187 *isSuccessful = VARIANT_TRUE;
2189 return hr;
2193 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2194 if (FAILED(hr))
2195 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2197 if (hr == S_OK)
2199 hr = domdoc_load_from_stream(This, stream);
2200 if (hr == S_OK)
2201 *isSuccessful = VARIANT_TRUE;
2202 ISequentialStream_Release(stream);
2203 return hr;
2206 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2207 break;
2209 default:
2210 FIXME("VT type not supported (%d)\n", V_VT(&source));
2213 if ( filename )
2215 IMoniker *mon;
2217 CoTaskMemFree(This->properties->url);
2218 This->properties->url = NULL;
2220 hr = create_moniker_from_url( filename, &mon);
2221 if ( SUCCEEDED(hr) )
2223 hr = domdoc_load_moniker( This, mon );
2224 if (hr == S_OK)
2225 IMoniker_GetDisplayName(mon, NULL, NULL, &This->properties->url);
2226 IMoniker_Release(mon);
2229 if ( FAILED(hr) )
2230 This->error = E_FAIL;
2231 else
2233 hr = This->error = S_OK;
2234 *isSuccessful = VARIANT_TRUE;
2238 if(!filename || FAILED(hr)) {
2239 xmldoc = xmlNewDoc(NULL);
2240 xmldoc->_private = create_priv();
2241 hr = attach_xmldoc(This, xmldoc);
2242 if(SUCCEEDED(hr))
2243 hr = S_FALSE;
2246 TRACE("ret (%d)\n", hr);
2248 return hr;
2252 static HRESULT WINAPI domdoc_get_readyState(
2253 IXMLDOMDocument3 *iface,
2254 LONG *value )
2256 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2257 FIXME("stub! (%p)->(%p)\n", This, value);
2259 if (!value)
2260 return E_INVALIDARG;
2262 *value = READYSTATE_COMPLETE;
2263 return S_OK;
2267 static HRESULT WINAPI domdoc_get_parseError(
2268 IXMLDOMDocument3 *iface,
2269 IXMLDOMParseError** errorObj )
2271 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2272 static const WCHAR err[] = {'e','r','r','o','r',0};
2273 BSTR error_string = NULL;
2275 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2277 if(This->error)
2278 error_string = SysAllocString(err);
2280 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2281 if(!*errorObj) return E_OUTOFMEMORY;
2282 return S_OK;
2286 static HRESULT WINAPI domdoc_get_url(
2287 IXMLDOMDocument3 *iface,
2288 BSTR* url )
2290 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2292 TRACE("(%p)->(%p)\n", This, url);
2294 if (!url)
2295 return E_INVALIDARG;
2297 if (This->properties->url)
2299 *url = SysAllocString(This->properties->url);
2300 if (!*url)
2301 return E_OUTOFMEMORY;
2303 return S_OK;
2305 else
2306 return return_null_bstr(url);
2310 static HRESULT WINAPI domdoc_get_async(
2311 IXMLDOMDocument3 *iface,
2312 VARIANT_BOOL* isAsync )
2314 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2316 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2317 *isAsync = This->async;
2318 return S_OK;
2322 static HRESULT WINAPI domdoc_put_async(
2323 IXMLDOMDocument3 *iface,
2324 VARIANT_BOOL isAsync )
2326 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2328 TRACE("(%p)->(%d)\n", This, isAsync);
2329 This->async = isAsync;
2330 return S_OK;
2334 static HRESULT WINAPI domdoc_abort(
2335 IXMLDOMDocument3 *iface )
2337 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2338 FIXME("%p\n", This);
2339 return E_NOTIMPL;
2342 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2343 static HRESULT WINAPI domdoc_loadXML(
2344 IXMLDOMDocument3 *iface,
2345 BSTR data,
2346 VARIANT_BOOL* isSuccessful )
2348 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2349 xmlDocPtr xmldoc = NULL;
2350 HRESULT hr = S_FALSE, hr2;
2352 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2354 assert ( &This->node );
2356 if ( isSuccessful )
2358 *isSuccessful = VARIANT_FALSE;
2360 if (data)
2362 WCHAR *ptr = data;
2364 /* skip leading spaces if needed */
2365 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2366 while (*ptr && isspaceW(*ptr)) ptr++;
2368 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2369 if ( !xmldoc )
2371 This->error = E_FAIL;
2372 TRACE("failed to parse document\n");
2374 else
2376 hr = This->error = S_OK;
2377 *isSuccessful = VARIANT_TRUE;
2378 TRACE("parsed document %p\n", xmldoc);
2383 if(!xmldoc)
2384 xmldoc = xmlNewDoc(NULL);
2385 xmldoc->_private = create_priv();
2386 hr2 = attach_xmldoc(This, xmldoc);
2387 if( FAILED(hr2) )
2388 hr = hr2;
2390 return hr;
2393 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2395 DWORD written = -1;
2397 if(!WriteFile(ctx, buffer, len, &written, NULL))
2399 WARN("write error\n");
2400 return -1;
2402 else
2403 return written;
2406 static int XMLCALL domdoc_save_closecallback(void *ctx)
2408 return CloseHandle(ctx) ? 0 : -1;
2411 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2413 ULONG written = 0;
2414 HRESULT hr;
2416 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2417 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2418 if (hr != S_OK)
2420 WARN("stream write error: 0x%08x\n", hr);
2421 return -1;
2423 else
2424 return len;
2427 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2429 IStream_Release((IStream*)ctx);
2430 return 0;
2433 static HRESULT WINAPI domdoc_save(
2434 IXMLDOMDocument3 *iface,
2435 VARIANT destination )
2437 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2438 xmlSaveCtxtPtr ctx = NULL;
2439 xmlNodePtr xmldecl;
2440 HRESULT ret = S_OK;
2442 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2444 switch (V_VT(&destination))
2446 case VT_UNKNOWN:
2448 IUnknown *pUnk = V_UNKNOWN(&destination);
2449 IXMLDOMDocument3 *document;
2450 IStream *stream;
2452 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2453 if(ret == S_OK)
2455 VARIANT_BOOL success;
2456 BSTR xml;
2458 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2459 if(ret == S_OK)
2461 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2462 SysFreeString(xml);
2465 IXMLDOMDocument3_Release(document);
2466 return ret;
2469 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2470 if(ret == S_OK)
2472 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2473 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2474 domdoc_stream_save_closecallback, stream, NULL, options);
2476 if(!ctx)
2478 IStream_Release(stream);
2479 return E_FAIL;
2483 break;
2485 case VT_BSTR:
2486 case VT_BSTR | VT_BYREF:
2488 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2490 /* save with file path */
2491 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2492 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2493 if( handle == INVALID_HANDLE_VALUE )
2495 WARN("failed to create file\n");
2496 return E_FAIL;
2499 /* disable top XML declaration */
2500 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2501 handle, NULL, options);
2502 if (!ctx)
2504 CloseHandle(handle);
2505 return E_FAIL;
2508 break;
2510 default:
2511 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2512 return S_FALSE;
2515 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2516 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2517 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2519 /* will release resources through close callback */
2520 xmlSaveClose(ctx);
2522 return ret;
2525 static HRESULT WINAPI domdoc_get_validateOnParse(
2526 IXMLDOMDocument3 *iface,
2527 VARIANT_BOOL* isValidating )
2529 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2530 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2531 *isValidating = This->validating;
2532 return S_OK;
2536 static HRESULT WINAPI domdoc_put_validateOnParse(
2537 IXMLDOMDocument3 *iface,
2538 VARIANT_BOOL isValidating )
2540 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2541 TRACE("(%p)->(%d)\n", This, isValidating);
2542 This->validating = isValidating;
2543 return S_OK;
2547 static HRESULT WINAPI domdoc_get_resolveExternals(
2548 IXMLDOMDocument3 *iface,
2549 VARIANT_BOOL* isResolving )
2551 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2552 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2553 *isResolving = This->resolving;
2554 return S_OK;
2558 static HRESULT WINAPI domdoc_put_resolveExternals(
2559 IXMLDOMDocument3 *iface,
2560 VARIANT_BOOL isResolving )
2562 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2563 TRACE("(%p)->(%d)\n", This, isResolving);
2564 This->resolving = isResolving;
2565 return S_OK;
2569 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2570 IXMLDOMDocument3 *iface,
2571 VARIANT_BOOL* isPreserving )
2573 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2574 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2575 *isPreserving = This->properties->preserving;
2576 return S_OK;
2580 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2581 IXMLDOMDocument3 *iface,
2582 VARIANT_BOOL isPreserving )
2584 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2585 TRACE("(%p)->(%d)\n", This, isPreserving);
2586 This->properties->preserving = isPreserving;
2587 return S_OK;
2591 static HRESULT WINAPI domdoc_put_onreadystatechange(
2592 IXMLDOMDocument3 *iface,
2593 VARIANT event )
2595 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2597 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2598 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2602 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2604 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2605 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2606 return E_NOTIMPL;
2609 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2611 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2612 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2613 return E_NOTIMPL;
2616 static HRESULT WINAPI domdoc_get_namespaces(
2617 IXMLDOMDocument3* iface,
2618 IXMLDOMSchemaCollection** collection )
2620 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2621 HRESULT hr;
2623 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2625 if (!collection) return E_POINTER;
2627 if (!This->namespaces)
2629 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2630 if (hr != S_OK) return hr;
2632 hr = cache_from_doc_ns(This->namespaces, &This->node);
2633 if (hr != S_OK)
2634 release_namespaces(This);
2637 if (This->namespaces)
2638 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2639 &IID_IXMLDOMSchemaCollection, (void**)collection);
2641 return hr;
2644 static HRESULT WINAPI domdoc_get_schemas(
2645 IXMLDOMDocument3* iface,
2646 VARIANT* schema )
2648 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2649 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2650 HRESULT hr = S_FALSE;
2652 TRACE("(%p)->(%p)\n", This, schema);
2654 V_VT(schema) = VT_NULL;
2655 /* just to reset pointer part, cause that's what application is expected to use */
2656 V_DISPATCH(schema) = NULL;
2658 if(cur_schema)
2660 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2661 if(SUCCEEDED(hr))
2662 V_VT(schema) = VT_DISPATCH;
2664 return hr;
2667 static HRESULT WINAPI domdoc_putref_schemas(
2668 IXMLDOMDocument3* iface,
2669 VARIANT schema)
2671 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2672 HRESULT hr = E_FAIL;
2673 IXMLDOMSchemaCollection2* new_schema = NULL;
2675 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2676 switch(V_VT(&schema))
2678 case VT_UNKNOWN:
2679 if (V_UNKNOWN(&schema))
2681 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2682 break;
2684 /* fallthrough */
2685 case VT_DISPATCH:
2686 if (V_DISPATCH(&schema))
2688 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2689 break;
2691 /* fallthrough */
2692 case VT_NULL:
2693 case VT_EMPTY:
2694 hr = S_OK;
2695 break;
2697 default:
2698 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2701 if(SUCCEEDED(hr))
2703 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2704 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2707 return hr;
2710 static inline BOOL is_wellformed(xmlDocPtr doc)
2712 #ifdef HAVE_XMLDOC_PROPERTIES
2713 return doc->properties & XML_DOC_WELLFORMED;
2714 #else
2715 /* Not a full check, but catches the worst violations */
2716 xmlNodePtr child;
2717 int root = 0;
2719 for (child = doc->children; child != NULL; child = child->next)
2721 switch (child->type)
2723 case XML_ELEMENT_NODE:
2724 if (++root > 1)
2725 return FALSE;
2726 break;
2727 case XML_TEXT_NODE:
2728 case XML_CDATA_SECTION_NODE:
2729 return FALSE;
2730 break;
2731 default:
2732 break;
2736 return root == 1;
2737 #endif
2740 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2742 va_list ap;
2743 va_start(ap, msg);
2744 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2745 va_end(ap);
2748 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2750 va_list ap;
2751 va_start(ap, msg);
2752 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2753 va_end(ap);
2756 static HRESULT WINAPI domdoc_validateNode(
2757 IXMLDOMDocument3* iface,
2758 IXMLDOMNode* node,
2759 IXMLDOMParseError** err)
2761 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2762 LONG state, err_code = 0;
2763 HRESULT hr = S_OK;
2764 int validated = 0;
2766 TRACE("(%p)->(%p, %p)\n", This, node, err);
2767 IXMLDOMDocument3_get_readyState(iface, &state);
2768 if (state != READYSTATE_COMPLETE)
2770 if (err)
2771 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2772 return E_PENDING;
2775 if (!node)
2777 if (err)
2778 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2779 return E_POINTER;
2782 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2784 if (err)
2785 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2786 return E_FAIL;
2789 if (!is_wellformed(get_doc(This)))
2791 ERR("doc not well-formed\n");
2792 if (err)
2793 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2794 return S_FALSE;
2797 /* DTD validation */
2798 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2800 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2801 vctx->error = validate_error;
2802 vctx->warning = validate_warning;
2803 ++validated;
2805 if (!((node == (IXMLDOMNode*)iface)?
2806 xmlValidateDocument(vctx, get_doc(This)) :
2807 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2809 /* TODO: get a real error code here */
2810 TRACE("DTD validation failed\n");
2811 err_code = E_XML_INVALID;
2812 hr = S_FALSE;
2814 xmlFreeValidCtxt(vctx);
2817 /* Schema validation */
2818 if (hr == S_OK && This->properties->schemaCache != NULL)
2821 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2822 if (SUCCEEDED(hr))
2824 ++validated;
2825 /* TODO: get a real error code here */
2826 if (hr == S_OK)
2828 TRACE("schema validation succeeded\n");
2830 else
2832 ERR("schema validation failed\n");
2833 err_code = E_XML_INVALID;
2836 else
2838 /* not really OK, just didn't find a schema for the ns */
2839 hr = S_OK;
2843 if (!validated)
2845 ERR("no DTD or schema found\n");
2846 err_code = E_XML_NODTD;
2847 hr = S_FALSE;
2850 if (err)
2851 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2853 return hr;
2856 static HRESULT WINAPI domdoc_validate(
2857 IXMLDOMDocument3* iface,
2858 IXMLDOMParseError** err)
2860 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2861 TRACE("(%p)->(%p)\n", This, err);
2862 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2865 static HRESULT WINAPI domdoc_setProperty(
2866 IXMLDOMDocument3* iface,
2867 BSTR p,
2868 VARIANT value)
2870 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2872 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2874 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2876 VARIANT varStr;
2877 HRESULT hr;
2878 BSTR bstr;
2880 V_VT(&varStr) = VT_EMPTY;
2881 if (V_VT(&value) != VT_BSTR)
2883 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2884 return hr;
2885 bstr = V_BSTR(&varStr);
2887 else
2888 bstr = V_BSTR(&value);
2890 hr = S_OK;
2891 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2892 This->properties->XPath = TRUE;
2893 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2894 This->properties->XPath = FALSE;
2895 else
2896 hr = E_FAIL;
2898 VariantClear(&varStr);
2899 return hr;
2901 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2903 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2904 struct list *pNsList;
2905 VARIANT varStr;
2906 HRESULT hr;
2907 BSTR bstr;
2909 V_VT(&varStr) = VT_EMPTY;
2910 if (V_VT(&value) != VT_BSTR)
2912 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2913 return hr;
2914 bstr = V_BSTR(&varStr);
2916 else
2917 bstr = V_BSTR(&value);
2919 hr = S_OK;
2921 pNsList = &(This->properties->selectNsList);
2922 clear_selectNsList(pNsList);
2923 heap_free(nsStr);
2924 nsStr = xmlchar_from_wchar(bstr);
2926 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2928 This->properties->selectNsStr = nsStr;
2929 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2930 if (bstr && *bstr)
2932 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2933 select_ns_entry* ns_entry = NULL;
2934 xmlXPathContextPtr ctx;
2936 ctx = xmlXPathNewContext(This->node.node->doc);
2937 pTokBegin = nsStr;
2939 /* skip leading spaces */
2940 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2941 *pTokBegin == '\t' || *pTokBegin == '\r')
2942 ++pTokBegin;
2944 for (; *pTokBegin; pTokBegin = pTokEnd)
2946 if (ns_entry)
2947 memset(ns_entry, 0, sizeof(select_ns_entry));
2948 else
2949 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2951 while (*pTokBegin == ' ')
2952 ++pTokBegin;
2953 pTokEnd = pTokBegin;
2954 while (*pTokEnd != ' ' && *pTokEnd != 0)
2955 ++pTokEnd;
2957 /* so it failed to advance which means we've got some trailing spaces */
2958 if (pTokEnd == pTokBegin) break;
2960 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2962 hr = E_FAIL;
2963 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2964 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2965 continue;
2968 pTokBegin += 5;
2969 if (*pTokBegin == '=')
2971 /*valid for XSLPattern?*/
2972 FIXME("Setting default xmlns not supported - skipping.\n");
2973 continue;
2975 else if (*pTokBegin == ':')
2977 ns_entry->prefix = ++pTokBegin;
2978 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2981 if (pTokInner == pTokEnd)
2983 hr = E_FAIL;
2984 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2985 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2986 continue;
2989 ns_entry->prefix_end = *pTokInner;
2990 *pTokInner = 0;
2991 ++pTokInner;
2993 if (pTokEnd-pTokInner > 1 &&
2994 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2995 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2997 ns_entry->href = ++pTokInner;
2998 ns_entry->href_end = *(pTokEnd-1);
2999 *(pTokEnd-1) = 0;
3000 list_add_tail(pNsList, &ns_entry->entry);
3001 /*let libxml figure out if they're valid from here ;)*/
3002 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3004 hr = E_FAIL;
3006 ns_entry = NULL;
3007 continue;
3009 else
3011 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3012 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3013 list_add_tail(pNsList, &ns_entry->entry);
3015 ns_entry = NULL;
3016 hr = E_FAIL;
3017 continue;
3020 else
3022 hr = E_FAIL;
3023 continue;
3026 heap_free(ns_entry);
3027 xmlXPathFreeContext(ctx);
3030 VariantClear(&varStr);
3031 return hr;
3033 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3034 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3035 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
3037 /* Ignore */
3038 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3039 return S_OK;
3042 FIXME("Unknown property %s\n", debugstr_w(p));
3043 return E_FAIL;
3046 static HRESULT WINAPI domdoc_getProperty(
3047 IXMLDOMDocument3* iface,
3048 BSTR p,
3049 VARIANT* var)
3051 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3053 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3055 if (!var)
3056 return E_INVALIDARG;
3058 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3060 V_VT(var) = VT_BSTR;
3061 V_BSTR(var) = This->properties->XPath ?
3062 SysAllocString(PropValueXPathW) :
3063 SysAllocString(PropValueXSLPatternW);
3064 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3066 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3068 int lenA, lenW;
3069 BSTR rebuiltStr, cur;
3070 const xmlChar *nsStr;
3071 struct list *pNsList;
3072 select_ns_entry* pNsEntry;
3074 V_VT(var) = VT_BSTR;
3075 nsStr = This->properties->selectNsStr;
3076 pNsList = &This->properties->selectNsList;
3077 lenA = This->properties->selectNsStr_len;
3078 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3079 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3080 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3081 cur = rebuiltStr;
3082 /* this is fine because all of the chars that end tokens are ASCII*/
3083 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3085 while (*cur != 0) ++cur;
3086 if (pNsEntry->prefix_end)
3088 *cur = pNsEntry->prefix_end;
3089 while (*cur != 0) ++cur;
3092 if (pNsEntry->href_end)
3094 *cur = pNsEntry->href_end;
3097 V_BSTR(var) = SysAllocString(rebuiltStr);
3098 heap_free(rebuiltStr);
3099 return S_OK;
3102 FIXME("Unknown property %s\n", debugstr_w(p));
3103 return E_FAIL;
3106 static HRESULT WINAPI domdoc_importNode(
3107 IXMLDOMDocument3* iface,
3108 IXMLDOMNode* node,
3109 VARIANT_BOOL deep,
3110 IXMLDOMNode** clone)
3112 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3113 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3114 return E_NOTIMPL;
3117 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3119 domdoc_QueryInterface,
3120 domdoc_AddRef,
3121 domdoc_Release,
3122 domdoc_GetTypeInfoCount,
3123 domdoc_GetTypeInfo,
3124 domdoc_GetIDsOfNames,
3125 domdoc_Invoke,
3126 domdoc_get_nodeName,
3127 domdoc_get_nodeValue,
3128 domdoc_put_nodeValue,
3129 domdoc_get_nodeType,
3130 domdoc_get_parentNode,
3131 domdoc_get_childNodes,
3132 domdoc_get_firstChild,
3133 domdoc_get_lastChild,
3134 domdoc_get_previousSibling,
3135 domdoc_get_nextSibling,
3136 domdoc_get_attributes,
3137 domdoc_insertBefore,
3138 domdoc_replaceChild,
3139 domdoc_removeChild,
3140 domdoc_appendChild,
3141 domdoc_hasChildNodes,
3142 domdoc_get_ownerDocument,
3143 domdoc_cloneNode,
3144 domdoc_get_nodeTypeString,
3145 domdoc_get_text,
3146 domdoc_put_text,
3147 domdoc_get_specified,
3148 domdoc_get_definition,
3149 domdoc_get_nodeTypedValue,
3150 domdoc_put_nodeTypedValue,
3151 domdoc_get_dataType,
3152 domdoc_put_dataType,
3153 domdoc_get_xml,
3154 domdoc_transformNode,
3155 domdoc_selectNodes,
3156 domdoc_selectSingleNode,
3157 domdoc_get_parsed,
3158 domdoc_get_namespaceURI,
3159 domdoc_get_prefix,
3160 domdoc_get_baseName,
3161 domdoc_transformNodeToObject,
3162 domdoc_get_doctype,
3163 domdoc_get_implementation,
3164 domdoc_get_documentElement,
3165 domdoc_put_documentElement,
3166 domdoc_createElement,
3167 domdoc_createDocumentFragment,
3168 domdoc_createTextNode,
3169 domdoc_createComment,
3170 domdoc_createCDATASection,
3171 domdoc_createProcessingInstruction,
3172 domdoc_createAttribute,
3173 domdoc_createEntityReference,
3174 domdoc_getElementsByTagName,
3175 domdoc_createNode,
3176 domdoc_nodeFromID,
3177 domdoc_load,
3178 domdoc_get_readyState,
3179 domdoc_get_parseError,
3180 domdoc_get_url,
3181 domdoc_get_async,
3182 domdoc_put_async,
3183 domdoc_abort,
3184 domdoc_loadXML,
3185 domdoc_save,
3186 domdoc_get_validateOnParse,
3187 domdoc_put_validateOnParse,
3188 domdoc_get_resolveExternals,
3189 domdoc_put_resolveExternals,
3190 domdoc_get_preserveWhiteSpace,
3191 domdoc_put_preserveWhiteSpace,
3192 domdoc_put_onreadystatechange,
3193 domdoc_put_onDataAvailable,
3194 domdoc_put_onTransformNode,
3195 domdoc_get_namespaces,
3196 domdoc_get_schemas,
3197 domdoc_putref_schemas,
3198 domdoc_validate,
3199 domdoc_setProperty,
3200 domdoc_getProperty,
3201 domdoc_validateNode,
3202 domdoc_importNode
3205 /* IConnectionPointContainer */
3206 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3207 REFIID riid, void **ppv)
3209 domdoc *This = impl_from_IConnectionPointContainer(iface);
3210 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3213 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3215 domdoc *This = impl_from_IConnectionPointContainer(iface);
3216 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3219 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3221 domdoc *This = impl_from_IConnectionPointContainer(iface);
3222 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3225 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3226 IEnumConnectionPoints **ppEnum)
3228 domdoc *This = impl_from_IConnectionPointContainer(iface);
3229 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3230 return E_NOTIMPL;
3233 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3234 REFIID riid, IConnectionPoint **cp)
3236 domdoc *This = impl_from_IConnectionPointContainer(iface);
3237 ConnectionPoint *iter;
3239 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3241 *cp = NULL;
3243 for(iter = This->cp_list; iter; iter = iter->next)
3245 if (IsEqualGUID(iter->iid, riid))
3246 *cp = &iter->IConnectionPoint_iface;
3249 if (*cp)
3251 IConnectionPoint_AddRef(*cp);
3252 return S_OK;
3255 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3256 return CONNECT_E_NOCONNECTION;
3260 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3262 ConnectionPointContainer_QueryInterface,
3263 ConnectionPointContainer_AddRef,
3264 ConnectionPointContainer_Release,
3265 ConnectionPointContainer_EnumConnectionPoints,
3266 ConnectionPointContainer_FindConnectionPoint
3269 /* IConnectionPoint */
3270 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3271 REFIID riid, void **ppv)
3273 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3275 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3277 *ppv = NULL;
3279 if (IsEqualGUID(&IID_IUnknown, riid) ||
3280 IsEqualGUID(&IID_IConnectionPoint, riid))
3282 *ppv = iface;
3285 if (*ppv)
3287 IConnectionPoint_AddRef(iface);
3288 return S_OK;
3291 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3292 return E_NOINTERFACE;
3295 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3297 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3298 return IConnectionPointContainer_AddRef(This->container);
3301 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3303 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3304 return IConnectionPointContainer_Release(This->container);
3307 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3309 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3311 TRACE("(%p)->(%p)\n", This, iid);
3313 if (!iid) return E_POINTER;
3315 *iid = *This->iid;
3316 return S_OK;
3319 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3320 IConnectionPointContainer **container)
3322 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3324 TRACE("(%p)->(%p)\n", This, container);
3326 if (!container) return E_POINTER;
3328 *container = This->container;
3329 IConnectionPointContainer_AddRef(*container);
3330 return S_OK;
3333 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3334 DWORD *cookie)
3336 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3337 IUnknown *sink;
3338 HRESULT hr;
3339 DWORD i;
3341 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3343 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3344 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3345 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3346 if(FAILED(hr))
3347 return CONNECT_E_CANNOTCONNECT;
3349 if(This->sinks)
3351 for (i = 0; i < This->sinks_size; i++)
3352 if (!This->sinks[i].unk)
3353 break;
3355 if (i == This->sinks_size)
3356 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3358 else
3360 This->sinks = heap_alloc(sizeof(*This->sinks));
3361 This->sinks_size = 1;
3362 i = 0;
3365 This->sinks[i].unk = sink;
3366 if (cookie)
3367 *cookie = i+1;
3369 return S_OK;
3372 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3374 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3376 TRACE("(%p)->(%d)\n", This, cookie);
3378 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3379 return CONNECT_E_NOCONNECTION;
3381 IUnknown_Release(This->sinks[cookie-1].unk);
3382 This->sinks[cookie-1].unk = NULL;
3384 return S_OK;
3387 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3388 IEnumConnections **ppEnum)
3390 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3391 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3392 return E_NOTIMPL;
3395 static const IConnectionPointVtbl ConnectionPointVtbl =
3397 ConnectionPoint_QueryInterface,
3398 ConnectionPoint_AddRef,
3399 ConnectionPoint_Release,
3400 ConnectionPoint_GetConnectionInterface,
3401 ConnectionPoint_GetConnectionPointContainer,
3402 ConnectionPoint_Advise,
3403 ConnectionPoint_Unadvise,
3404 ConnectionPoint_EnumConnections
3407 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3409 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3410 cp->doc = doc;
3411 cp->iid = riid;
3412 cp->sinks = NULL;
3413 cp->sinks_size = 0;
3415 cp->next = doc->cp_list;
3416 doc->cp_list = cp;
3418 cp->container = &doc->IConnectionPointContainer_iface;
3421 /* domdoc implementation of IObjectWithSite */
3422 static HRESULT WINAPI
3423 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3425 domdoc *This = impl_from_IObjectWithSite(iface);
3426 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3429 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3431 domdoc *This = impl_from_IObjectWithSite(iface);
3432 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3435 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3437 domdoc *This = impl_from_IObjectWithSite(iface);
3438 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3441 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3443 domdoc *This = impl_from_IObjectWithSite(iface);
3445 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3447 if ( !This->site )
3448 return E_FAIL;
3450 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3453 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3455 domdoc *This = impl_from_IObjectWithSite(iface);
3457 TRACE("(%p)->(%p)\n", iface, punk);
3459 if(!punk)
3461 if(This->site)
3463 IUnknown_Release( This->site );
3464 This->site = NULL;
3467 return S_OK;
3470 IUnknown_AddRef( punk );
3472 if(This->site)
3473 IUnknown_Release( This->site );
3475 This->site = punk;
3477 return S_OK;
3480 static const IObjectWithSiteVtbl domdocObjectSite =
3482 domdoc_ObjectWithSite_QueryInterface,
3483 domdoc_ObjectWithSite_AddRef,
3484 domdoc_ObjectWithSite_Release,
3485 domdoc_ObjectWithSite_SetSite,
3486 domdoc_ObjectWithSite_GetSite
3489 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3491 domdoc *This = impl_from_IObjectSafety(iface);
3492 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3495 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3497 domdoc *This = impl_from_IObjectSafety(iface);
3498 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3501 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3503 domdoc *This = impl_from_IObjectSafety(iface);
3504 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3507 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3509 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3510 DWORD *supported, DWORD *enabled)
3512 domdoc *This = impl_from_IObjectSafety(iface);
3514 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3516 if(!supported || !enabled) return E_POINTER;
3518 *supported = SAFETY_SUPPORTED_OPTIONS;
3519 *enabled = This->safeopt;
3521 return S_OK;
3524 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3525 DWORD mask, DWORD enabled)
3527 domdoc *This = impl_from_IObjectSafety(iface);
3528 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3530 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3531 return E_FAIL;
3533 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3535 return S_OK;
3538 #undef SAFETY_SUPPORTED_OPTIONS
3540 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3541 domdoc_Safety_QueryInterface,
3542 domdoc_Safety_AddRef,
3543 domdoc_Safety_Release,
3544 domdoc_Safety_GetInterfaceSafetyOptions,
3545 domdoc_Safety_SetInterfaceSafetyOptions
3548 static const tid_t domdoc_iface_tids[] = {
3549 IXMLDOMDocument3_tid,
3553 static dispex_static_data_t domdoc_dispex = {
3554 NULL,
3555 IXMLDOMDocument3_tid,
3556 NULL,
3557 domdoc_iface_tids
3560 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3562 domdoc *doc;
3564 doc = heap_alloc( sizeof (*doc) );
3565 if( !doc )
3566 return E_OUTOFMEMORY;
3568 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3569 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3570 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3571 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3572 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3573 doc->ref = 1;
3574 doc->async = VARIANT_TRUE;
3575 doc->validating = 0;
3576 doc->resolving = 0;
3577 doc->properties = properties_from_xmlDocPtr(xmldoc);
3578 doc->error = S_OK;
3579 doc->site = NULL;
3580 doc->safeopt = 0;
3581 doc->cp_list = NULL;
3582 doc->namespaces = NULL;
3583 memset(doc->events, 0, sizeof(doc->events));
3585 /* events connection points */
3586 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3587 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3588 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3590 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3591 &domdoc_dispex);
3593 *document = &doc->IXMLDOMDocument3_iface;
3595 TRACE("returning iface %p\n", *document);
3596 return S_OK;
3599 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3601 xmlDocPtr xmldoc;
3602 HRESULT hr;
3604 TRACE("(%d, %p)\n", version, ppObj);
3606 xmldoc = xmlNewDoc(NULL);
3607 if(!xmldoc)
3608 return E_OUTOFMEMORY;
3610 xmldoc_init(xmldoc, version);
3612 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3613 if(FAILED(hr))
3615 free_properties(properties_from_xmlDocPtr(xmldoc));
3616 heap_free(xmldoc->_private);
3617 xmlFreeDoc(xmldoc);
3618 return hr;
3621 return hr;
3624 IUnknown* create_domdoc( xmlNodePtr document )
3626 void* pObj = NULL;
3627 HRESULT hr;
3629 TRACE("(%p)\n", document);
3631 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3632 if (FAILED(hr))
3633 return NULL;
3635 return pObj;
3638 #else
3640 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3642 MESSAGE("This program tried to use a DOMDocument object, but\n"
3643 "libxml2 support was not present at compile time.\n");
3644 return E_NOTIMPL;
3647 #endif