opengl32: Fix some style issues.
[wine.git] / dlls / msxml3 / domdoc.c
blobe3dd7922ff7aeae10d67a3fe9102c83d2f0ddc92
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 HRESULT error;
134 WCHAR *url;
136 /* IObjectWithSite */
137 IUnknown *site;
139 /* IObjectSafety */
140 DWORD safeopt;
142 /* connection list */
143 ConnectionPoint *cp_list;
144 ConnectionPoint cp_domdocevents;
145 ConnectionPoint cp_propnotif;
146 ConnectionPoint cp_dispatch;
148 /* events */
149 IDispatch *events[EVENTID_LAST];
151 IXMLDOMSchemaCollection2 *namespaces;
154 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
156 IDispatch *disp;
158 switch (V_VT(v))
160 case VT_UNKNOWN:
161 if (V_UNKNOWN(v))
162 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
163 else
164 disp = NULL;
165 break;
166 case VT_DISPATCH:
167 disp = V_DISPATCH(v);
168 if (disp) IDispatch_AddRef(disp);
169 break;
170 default:
171 return DISP_E_TYPEMISMATCH;
174 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
175 doc->events[eid] = disp;
177 return S_OK;
180 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
182 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
186 In native windows, the whole lifetime management of XMLDOMNodes is
187 managed automatically using reference counts. Wine emulates that by
188 maintaining a reference count to the document that is increased for
189 each IXMLDOMNode pointer passed out for this document. If all these
190 pointers are gone, the document is unreachable and gets freed, that
191 is, all nodes in the tree of the document get freed.
193 You are able to create nodes that are associated to a document (in
194 fact, in msxml's XMLDOM model, all nodes are associated to a document),
195 but not in the tree of that document, for example using the createFoo
196 functions from IXMLDOMDocument. These nodes do not get cleaned up
197 by libxml, so we have to do it ourselves.
199 To catch these nodes, a list of "orphan nodes" is introduced.
200 It contains pointers to all roots of node trees that are
201 associated with the document without being part of the document
202 tree. All nodes with parent==NULL (except for the document root nodes)
203 should be in the orphan node list of their document. All orphan nodes
204 get freed together with the document itself.
207 typedef struct _xmldoc_priv {
208 LONG refs;
209 struct list orphans;
210 domdoc_properties* properties;
211 } xmldoc_priv;
213 typedef struct _orphan_entry {
214 struct list entry;
215 xmlNode * node;
216 } orphan_entry;
218 typedef struct _select_ns_entry {
219 struct list entry;
220 xmlChar const* prefix;
221 xmlChar prefix_end;
222 xmlChar const* href;
223 xmlChar href_end;
224 } select_ns_entry;
226 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
228 return doc->_private;
231 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
233 return priv_from_xmlDocPtr(doc)->properties;
236 BOOL is_xpathmode(const xmlDocPtr doc)
238 return properties_from_xmlDocPtr(doc)->XPath;
241 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
243 properties_from_xmlDocPtr(doc)->XPath = xpath;
246 int registerNamespaces(xmlXPathContextPtr ctxt)
248 int n = 0;
249 const select_ns_entry* ns = NULL;
250 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
252 TRACE("(%p)\n", ctxt);
254 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
256 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
257 ++n;
260 return n;
263 static inline void clear_selectNsList(struct list* pNsList)
265 select_ns_entry *ns, *ns2;
266 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
268 heap_free( ns );
270 list_init(pNsList);
273 static xmldoc_priv * create_priv(void)
275 xmldoc_priv *priv;
276 priv = heap_alloc( sizeof (*priv) );
278 if (priv)
280 priv->refs = 0;
281 list_init( &priv->orphans );
282 priv->properties = NULL;
285 return priv;
288 static domdoc_properties *create_properties(MSXML_VERSION version)
290 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
292 list_init(&properties->selectNsList);
293 properties->preserving = VARIANT_FALSE;
294 properties->schemaCache = NULL;
295 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
296 properties->selectNsStr_len = 0;
298 /* properties that are dependent on object versions */
299 properties->version = version;
300 properties->XPath = (version == MSXML4 || version == MSXML6);
302 return properties;
305 static domdoc_properties* copy_properties(domdoc_properties const* properties)
307 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
308 select_ns_entry const* ns = NULL;
309 select_ns_entry* new_ns = NULL;
310 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
311 ptrdiff_t offset;
313 if (pcopy)
315 pcopy->version = properties->version;
316 pcopy->preserving = properties->preserving;
317 pcopy->schemaCache = properties->schemaCache;
318 if (pcopy->schemaCache)
319 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
320 pcopy->XPath = properties->XPath;
321 pcopy->selectNsStr_len = properties->selectNsStr_len;
322 list_init( &pcopy->selectNsList );
323 pcopy->selectNsStr = heap_alloc(len);
324 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
325 offset = pcopy->selectNsStr - properties->selectNsStr;
327 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
329 new_ns = heap_alloc(sizeof(select_ns_entry));
330 memcpy(new_ns, ns, sizeof(select_ns_entry));
331 new_ns->href += offset;
332 new_ns->prefix += offset;
333 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
338 return pcopy;
341 static void free_properties(domdoc_properties* properties)
343 if (properties)
345 if (properties->schemaCache)
346 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
347 clear_selectNsList(&properties->selectNsList);
348 heap_free((xmlChar*)properties->selectNsStr);
349 heap_free(properties);
353 static void release_namespaces(domdoc *This)
355 if (This->namespaces)
357 IXMLDOMSchemaCollection2_Release(This->namespaces);
358 This->namespaces = NULL;
362 /* links a "<?xml" node as a first child */
363 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
365 assert(doc != NULL);
366 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
369 /* unlinks a first "<?xml" child if it was created */
370 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
372 static const xmlChar xmlA[] = "xml";
373 xmlNodePtr node, first_child;
375 assert(doc != NULL);
377 /* xml declaration node could be created automatically after parsing or added
378 to a tree later */
379 first_child = doc->children;
380 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
382 node = first_child;
383 xmlUnlinkNode( node );
385 else
386 node = NULL;
388 return node;
391 BOOL is_preserving_whitespace(xmlNodePtr node)
393 domdoc_properties* properties = NULL;
394 /* during parsing the xmlDoc._private stuff is not there */
395 if (priv_from_xmlDocPtr(node->doc))
396 properties = properties_from_xmlDocPtr(node->doc);
397 return ((properties && properties->preserving == VARIANT_TRUE) ||
398 xmlNodeGetSpacePreserve(node) == 1);
401 static inline BOOL strn_isspace(xmlChar const* str, int len)
403 for (; str && len > 0 && *str; ++str, --len)
404 if (!isspace(*str))
405 break;
407 return len == 0;
410 static void sax_characters(void *ctx, const xmlChar *ch, int len)
412 xmlParserCtxtPtr ctxt;
413 const domdoc *This;
415 ctxt = (xmlParserCtxtPtr) ctx;
416 This = (const domdoc*) ctxt->_private;
418 if (ctxt->node)
420 xmlChar cur = *(ctxt->input->cur);
422 /* Characters are reported with multiple calls, for example each charref is reported with a separate
423 call and then parser appends it to a single text node or creates a new node if not created.
424 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
425 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
426 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
427 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
428 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
429 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
430 a text node it's safe to ignore.
432 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
434 if (!This->properties->preserving &&
435 !is_preserving_whitespace(ctxt->node) &&
436 strn_isspace(ch, len) &&
437 (!ctxt->node->last ||
438 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
440 return;
443 xmlSAX2Characters(ctxt, ch, len);
446 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
448 va_list ap;
449 va_start(ap, msg);
450 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
451 va_end(ap);
454 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
456 va_list ap;
457 va_start(ap, msg);
458 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
459 va_end(ap);
462 static void sax_serror(void* ctx, xmlErrorPtr err)
464 LIBXML2_CALLBACK_SERROR(doparse, err);
467 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
469 xmlDocPtr doc = NULL;
470 xmlParserCtxtPtr pctx;
471 static xmlSAXHandler sax_handler = {
472 xmlSAX2InternalSubset, /* internalSubset */
473 xmlSAX2IsStandalone, /* isStandalone */
474 xmlSAX2HasInternalSubset, /* hasInternalSubset */
475 xmlSAX2HasExternalSubset, /* hasExternalSubset */
476 xmlSAX2ResolveEntity, /* resolveEntity */
477 xmlSAX2GetEntity, /* getEntity */
478 xmlSAX2EntityDecl, /* entityDecl */
479 xmlSAX2NotationDecl, /* notationDecl */
480 xmlSAX2AttributeDecl, /* attributeDecl */
481 xmlSAX2ElementDecl, /* elementDecl */
482 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
483 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
484 xmlSAX2StartDocument, /* startDocument */
485 xmlSAX2EndDocument, /* endDocument */
486 xmlSAX2StartElement, /* startElement */
487 xmlSAX2EndElement, /* endElement */
488 xmlSAX2Reference, /* reference */
489 sax_characters, /* characters */
490 sax_characters, /* ignorableWhitespace */
491 xmlSAX2ProcessingInstruction, /* processingInstruction */
492 xmlSAX2Comment, /* comment */
493 sax_warning, /* warning */
494 sax_error, /* error */
495 sax_error, /* fatalError */
496 xmlSAX2GetParameterEntity, /* getParameterEntity */
497 xmlSAX2CDataBlock, /* cdataBlock */
498 xmlSAX2ExternalSubset, /* externalSubset */
499 0, /* initialized */
500 NULL, /* _private */
501 xmlSAX2StartElementNs, /* startElementNs */
502 xmlSAX2EndElementNs, /* endElementNs */
503 sax_serror /* serror */
506 pctx = xmlCreateMemoryParserCtxt(ptr, len);
507 if (!pctx)
509 ERR("Failed to create parser context\n");
510 return NULL;
513 if (pctx->sax) xmlFree(pctx->sax);
514 pctx->sax = &sax_handler;
515 pctx->_private = This;
516 pctx->recovery = 0;
518 if (encoding != XML_CHAR_ENCODING_NONE)
519 xmlSwitchEncoding(pctx, encoding);
521 xmlParseDocument(pctx);
523 if (pctx->wellFormed)
525 doc = pctx->myDoc;
527 else
529 xmlFreeDoc(pctx->myDoc);
530 pctx->myDoc = NULL;
532 pctx->sax = NULL;
533 xmlFreeParserCtxt(pctx);
535 /* TODO: put this in one of the SAX callbacks */
536 /* create first child as a <?xml...?> */
537 if (doc && doc->standalone != -1)
539 xmlNodePtr node;
540 char buff[30];
541 xmlChar *xmlbuff = (xmlChar*)buff;
543 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
545 /* version attribute can't be omitted */
546 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
547 xmlNodeAddContent( node, xmlbuff );
549 if (doc->encoding)
551 sprintf(buff, " encoding=\"%s\"", doc->encoding);
552 xmlNodeAddContent( node, xmlbuff );
555 if (doc->standalone != -2)
557 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
558 xmlNodeAddContent( node, xmlbuff );
561 xmldoc_link_xmldecl( doc, node );
564 return doc;
567 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
569 doc->_private = create_priv();
570 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
573 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
575 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
576 TRACE("(%p)->(%d)\n", doc, ref);
577 return ref;
580 LONG xmldoc_add_ref(xmlDocPtr doc)
582 return xmldoc_add_refs(doc, 1);
585 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
587 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
588 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
589 TRACE("(%p)->(%d)\n", doc, ref);
591 if (ref < 0)
592 WARN("negative refcount, expect troubles\n");
594 if (ref == 0)
596 orphan_entry *orphan, *orphan2;
597 TRACE("freeing docptr %p\n", doc);
599 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
601 xmlFreeNode( orphan->node );
602 heap_free( orphan );
604 free_properties(priv->properties);
605 heap_free(doc->_private);
607 xmlFreeDoc(doc);
610 return ref;
613 LONG xmldoc_release(xmlDocPtr doc)
615 return xmldoc_release_refs(doc, 1);
618 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
620 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
621 orphan_entry *entry;
623 entry = heap_alloc( sizeof (*entry) );
624 if(!entry)
625 return E_OUTOFMEMORY;
627 entry->node = node;
628 list_add_head( &priv->orphans, &entry->entry );
629 return S_OK;
632 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
634 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
635 orphan_entry *entry, *entry2;
637 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
639 if( entry->node == node )
641 list_remove( &entry->entry );
642 heap_free( entry );
643 return S_OK;
647 return S_FALSE;
650 static inline xmlDocPtr get_doc( domdoc *This )
652 return This->node.node->doc;
655 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
657 release_namespaces(This);
659 if(This->node.node)
661 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
662 if (xmldoc_release(get_doc(This)) != 0)
663 priv_from_xmlDocPtr(get_doc(This))->properties =
664 copy_properties(This->properties);
667 This->node.node = (xmlNodePtr) xml;
669 if(This->node.node)
671 xmldoc_add_ref(get_doc(This));
672 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
675 return S_OK;
678 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
680 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
683 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
685 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
688 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
690 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
693 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
695 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
698 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
700 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
703 /************************************************************************
704 * domdoc implementation of IPersistStream.
706 static HRESULT WINAPI PersistStreamInit_QueryInterface(
707 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
709 domdoc* This = impl_from_IPersistStreamInit(iface);
710 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
713 static ULONG WINAPI PersistStreamInit_AddRef(
714 IPersistStreamInit *iface)
716 domdoc* This = impl_from_IPersistStreamInit(iface);
717 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
720 static ULONG WINAPI PersistStreamInit_Release(
721 IPersistStreamInit *iface)
723 domdoc* This = impl_from_IPersistStreamInit(iface);
724 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
727 static HRESULT WINAPI PersistStreamInit_GetClassID(
728 IPersistStreamInit *iface, CLSID *classid)
730 domdoc* This = impl_from_IPersistStreamInit(iface);
731 TRACE("(%p)->(%p)\n", This, classid);
733 if(!classid)
734 return E_POINTER;
736 *classid = *DOMDocument_version(This->properties->version);
738 return S_OK;
741 static HRESULT WINAPI PersistStreamInit_IsDirty(
742 IPersistStreamInit *iface)
744 domdoc *This = impl_from_IPersistStreamInit(iface);
745 FIXME("(%p): stub!\n", This);
746 return S_FALSE;
749 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
751 DWORD read, written, len;
752 xmlDocPtr xmldoc = NULL;
753 IStream *hstream;
754 HGLOBAL hglobal;
755 BYTE buf[4096];
756 HRESULT hr;
757 char *ptr;
759 hstream = NULL;
760 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
761 if (FAILED(hr))
762 return hr;
766 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
767 hr = IStream_Write(hstream, buf, read, &written);
768 } while(SUCCEEDED(hr) && written != 0 && read != 0);
770 if (FAILED(hr))
772 ERR("failed to copy stream 0x%08x\n", hr);
773 IStream_Release(hstream);
774 return hr;
777 hr = GetHGlobalFromStream(hstream, &hglobal);
778 if (FAILED(hr))
779 return hr;
781 len = GlobalSize(hglobal);
782 ptr = GlobalLock(hglobal);
783 if (len)
784 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
785 GlobalUnlock(hglobal);
787 if (!xmldoc)
789 ERR("Failed to parse xml\n");
790 return E_FAIL;
793 xmldoc->_private = create_priv();
795 return attach_xmldoc(doc, xmldoc);
798 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
800 domdoc *This = impl_from_IPersistStreamInit(iface);
802 TRACE("(%p)->(%p)\n", This, stream);
804 if (!stream)
805 return E_INVALIDARG;
807 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
810 static HRESULT WINAPI PersistStreamInit_Save(
811 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
813 domdoc *This = impl_from_IPersistStreamInit(iface);
814 BSTR xmlString;
815 HRESULT hr;
817 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
819 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
820 if(hr == S_OK)
822 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
824 hr = IStream_Write( stream, xmlString, len, NULL );
825 SysFreeString(xmlString);
828 TRACE("ret 0x%08x\n", hr);
830 return hr;
833 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
834 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
836 domdoc *This = impl_from_IPersistStreamInit(iface);
837 TRACE("(%p)->(%p)\n", This, pcbSize);
838 return E_NOTIMPL;
841 static HRESULT WINAPI PersistStreamInit_InitNew(
842 IPersistStreamInit *iface)
844 domdoc *This = impl_from_IPersistStreamInit(iface);
845 TRACE("(%p)\n", This);
846 return S_OK;
849 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
851 PersistStreamInit_QueryInterface,
852 PersistStreamInit_AddRef,
853 PersistStreamInit_Release,
854 PersistStreamInit_GetClassID,
855 PersistStreamInit_IsDirty,
856 PersistStreamInit_Load,
857 PersistStreamInit_Save,
858 PersistStreamInit_GetSizeMax,
859 PersistStreamInit_InitNew
862 /* IXMLDOMDocument3 interface */
864 static const tid_t domdoc_se_tids[] = {
865 IXMLDOMNode_tid,
866 IXMLDOMDocument_tid,
867 IXMLDOMDocument2_tid,
868 IXMLDOMDocument3_tid,
869 NULL_tid
872 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
874 domdoc *This = impl_from_IXMLDOMDocument3( iface );
876 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
878 *ppvObject = NULL;
880 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
881 IsEqualGUID( riid, &IID_IDispatch ) ||
882 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
883 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
884 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
885 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
887 *ppvObject = iface;
889 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
890 IsEqualGUID(&IID_IPersistStreamInit, riid))
892 *ppvObject = &This->IPersistStreamInit_iface;
894 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
896 *ppvObject = &This->IObjectWithSite_iface;
898 else if (IsEqualGUID(&IID_IObjectSafety, riid))
900 *ppvObject = &This->IObjectSafety_iface;
902 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
904 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
906 else if(node_query_interface(&This->node, riid, ppvObject))
908 return *ppvObject ? S_OK : E_NOINTERFACE;
910 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
912 *ppvObject = &This->IConnectionPointContainer_iface;
914 else
916 TRACE("interface %s not implemented\n", debugstr_guid(riid));
917 return E_NOINTERFACE;
920 IUnknown_AddRef((IUnknown*)*ppvObject);
922 return S_OK;
925 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
927 domdoc *This = impl_from_IXMLDOMDocument3( iface );
928 ULONG ref = InterlockedIncrement( &This->ref );
929 TRACE("(%p)->(%d)\n", This, ref );
930 return ref;
933 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
935 domdoc *This = impl_from_IXMLDOMDocument3( iface );
936 LONG ref = InterlockedDecrement( &This->ref );
938 TRACE("(%p)->(%d)\n", This, ref );
940 if ( ref == 0 )
942 int eid;
944 if (This->site)
945 IUnknown_Release( This->site );
946 destroy_xmlnode(&This->node);
948 for (eid = 0; eid < EVENTID_LAST; eid++)
949 if (This->events[eid]) IDispatch_Release(This->events[eid]);
951 CoTaskMemFree(This->url);
952 release_namespaces(This);
953 heap_free(This);
956 return ref;
959 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
961 domdoc *This = impl_from_IXMLDOMDocument3( iface );
962 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
965 static HRESULT WINAPI domdoc_GetTypeInfo(
966 IXMLDOMDocument3 *iface,
967 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
969 domdoc *This = impl_from_IXMLDOMDocument3( iface );
970 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
973 static HRESULT WINAPI domdoc_GetIDsOfNames(
974 IXMLDOMDocument3 *iface,
975 REFIID riid,
976 LPOLESTR* rgszNames,
977 UINT cNames,
978 LCID lcid,
979 DISPID* rgDispId)
981 domdoc *This = impl_from_IXMLDOMDocument3( iface );
982 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
983 riid, rgszNames, cNames, lcid, rgDispId);
986 static HRESULT WINAPI domdoc_Invoke(
987 IXMLDOMDocument3 *iface,
988 DISPID dispIdMember,
989 REFIID riid,
990 LCID lcid,
991 WORD wFlags,
992 DISPPARAMS* pDispParams,
993 VARIANT* pVarResult,
994 EXCEPINFO* pExcepInfo,
995 UINT* puArgErr)
997 domdoc *This = impl_from_IXMLDOMDocument3( iface );
998 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
999 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1002 static HRESULT WINAPI domdoc_get_nodeName(
1003 IXMLDOMDocument3 *iface,
1004 BSTR* name )
1006 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1008 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1010 TRACE("(%p)->(%p)\n", This, name);
1012 return return_bstr(documentW, name);
1016 static HRESULT WINAPI domdoc_get_nodeValue(
1017 IXMLDOMDocument3 *iface,
1018 VARIANT* value )
1020 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1022 TRACE("(%p)->(%p)\n", This, value);
1024 if(!value)
1025 return E_INVALIDARG;
1027 V_VT(value) = VT_NULL;
1028 V_BSTR(value) = NULL; /* tests show that we should do this */
1029 return S_FALSE;
1033 static HRESULT WINAPI domdoc_put_nodeValue(
1034 IXMLDOMDocument3 *iface,
1035 VARIANT value)
1037 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1038 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1039 return E_FAIL;
1043 static HRESULT WINAPI domdoc_get_nodeType(
1044 IXMLDOMDocument3 *iface,
1045 DOMNodeType* type )
1047 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1049 TRACE("(%p)->(%p)\n", This, type);
1051 *type = NODE_DOCUMENT;
1052 return S_OK;
1056 static HRESULT WINAPI domdoc_get_parentNode(
1057 IXMLDOMDocument3 *iface,
1058 IXMLDOMNode** parent )
1060 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1062 TRACE("(%p)->(%p)\n", This, parent);
1064 return node_get_parent(&This->node, parent);
1068 static HRESULT WINAPI domdoc_get_childNodes(
1069 IXMLDOMDocument3 *iface,
1070 IXMLDOMNodeList** childList )
1072 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1074 TRACE("(%p)->(%p)\n", This, childList);
1076 return node_get_child_nodes(&This->node, childList);
1080 static HRESULT WINAPI domdoc_get_firstChild(
1081 IXMLDOMDocument3 *iface,
1082 IXMLDOMNode** firstChild )
1084 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1086 TRACE("(%p)->(%p)\n", This, firstChild);
1088 return node_get_first_child(&This->node, firstChild);
1092 static HRESULT WINAPI domdoc_get_lastChild(
1093 IXMLDOMDocument3 *iface,
1094 IXMLDOMNode** lastChild )
1096 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1098 TRACE("(%p)->(%p)\n", This, lastChild);
1100 return node_get_last_child(&This->node, lastChild);
1104 static HRESULT WINAPI domdoc_get_previousSibling(
1105 IXMLDOMDocument3 *iface,
1106 IXMLDOMNode** previousSibling )
1108 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1110 TRACE("(%p)->(%p)\n", This, previousSibling);
1112 return return_null_node(previousSibling);
1116 static HRESULT WINAPI domdoc_get_nextSibling(
1117 IXMLDOMDocument3 *iface,
1118 IXMLDOMNode** nextSibling )
1120 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1122 TRACE("(%p)->(%p)\n", This, nextSibling);
1124 return return_null_node(nextSibling);
1128 static HRESULT WINAPI domdoc_get_attributes(
1129 IXMLDOMDocument3 *iface,
1130 IXMLDOMNamedNodeMap** attributeMap )
1132 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1134 TRACE("(%p)->(%p)\n", This, attributeMap);
1136 return return_null_ptr((void**)attributeMap);
1140 static HRESULT WINAPI domdoc_insertBefore(
1141 IXMLDOMDocument3 *iface,
1142 IXMLDOMNode* newChild,
1143 VARIANT refChild,
1144 IXMLDOMNode** outNewChild )
1146 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1147 DOMNodeType type;
1148 HRESULT hr;
1150 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1152 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1153 if (hr != S_OK) return hr;
1155 TRACE("new node type %d\n", type);
1156 switch (type)
1158 case NODE_ATTRIBUTE:
1159 case NODE_DOCUMENT:
1160 case NODE_CDATA_SECTION:
1161 if (outNewChild) *outNewChild = NULL;
1162 return E_FAIL;
1163 default:
1164 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1168 static HRESULT WINAPI domdoc_replaceChild(
1169 IXMLDOMDocument3 *iface,
1170 IXMLDOMNode* newChild,
1171 IXMLDOMNode* oldChild,
1172 IXMLDOMNode** outOldChild)
1174 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1176 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1178 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1182 static HRESULT WINAPI domdoc_removeChild(
1183 IXMLDOMDocument3 *iface,
1184 IXMLDOMNode *child,
1185 IXMLDOMNode **oldChild)
1187 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1188 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1189 return node_remove_child(&This->node, child, oldChild);
1193 static HRESULT WINAPI domdoc_appendChild(
1194 IXMLDOMDocument3 *iface,
1195 IXMLDOMNode *child,
1196 IXMLDOMNode **outChild)
1198 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1199 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1200 return node_append_child(&This->node, child, outChild);
1204 static HRESULT WINAPI domdoc_hasChildNodes(
1205 IXMLDOMDocument3 *iface,
1206 VARIANT_BOOL *ret)
1208 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1209 TRACE("(%p)->(%p)\n", This, ret);
1210 return node_has_childnodes(&This->node, ret);
1214 static HRESULT WINAPI domdoc_get_ownerDocument(
1215 IXMLDOMDocument3 *iface,
1216 IXMLDOMDocument **doc)
1218 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1219 TRACE("(%p)->(%p)\n", This, doc);
1220 return node_get_owner_doc(&This->node, doc);
1224 static HRESULT WINAPI domdoc_cloneNode(
1225 IXMLDOMDocument3 *iface,
1226 VARIANT_BOOL deep,
1227 IXMLDOMNode** outNode)
1229 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1230 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1231 return node_clone( &This->node, deep, outNode );
1235 static HRESULT WINAPI domdoc_get_nodeTypeString(
1236 IXMLDOMDocument3 *iface,
1237 BSTR *p)
1239 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1240 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1242 TRACE("(%p)->(%p)\n", This, p);
1244 return return_bstr(documentW, p);
1248 static HRESULT WINAPI domdoc_get_text(
1249 IXMLDOMDocument3 *iface,
1250 BSTR *p)
1252 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1253 TRACE("(%p)->(%p)\n", This, p);
1254 return node_get_text(&This->node, p);
1258 static HRESULT WINAPI domdoc_put_text(
1259 IXMLDOMDocument3 *iface,
1260 BSTR text )
1262 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1263 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1264 return E_FAIL;
1268 static HRESULT WINAPI domdoc_get_specified(
1269 IXMLDOMDocument3 *iface,
1270 VARIANT_BOOL* isSpecified )
1272 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1273 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1274 *isSpecified = VARIANT_TRUE;
1275 return S_OK;
1279 static HRESULT WINAPI domdoc_get_definition(
1280 IXMLDOMDocument3 *iface,
1281 IXMLDOMNode** definitionNode )
1283 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1284 FIXME("(%p)->(%p)\n", This, definitionNode);
1285 return E_NOTIMPL;
1289 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1290 IXMLDOMDocument3 *iface,
1291 VARIANT* v )
1293 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1294 TRACE("(%p)->(%p)\n", This, v);
1295 return return_null_var(v);
1298 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1299 IXMLDOMDocument3 *iface,
1300 VARIANT typedValue )
1302 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1303 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1304 return E_NOTIMPL;
1308 static HRESULT WINAPI domdoc_get_dataType(
1309 IXMLDOMDocument3 *iface,
1310 VARIANT* typename )
1312 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1313 TRACE("(%p)->(%p)\n", This, typename);
1314 return return_null_var( typename );
1318 static HRESULT WINAPI domdoc_put_dataType(
1319 IXMLDOMDocument3 *iface,
1320 BSTR dataTypeName )
1322 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1324 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1326 if(!dataTypeName)
1327 return E_INVALIDARG;
1329 return E_FAIL;
1332 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1334 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1337 static HRESULT WINAPI domdoc_get_xml(
1338 IXMLDOMDocument3 *iface,
1339 BSTR* p)
1341 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1342 xmlSaveCtxtPtr ctxt;
1343 xmlBufferPtr buf;
1344 int options;
1345 long ret;
1347 TRACE("(%p)->(%p)\n", This, p);
1349 if(!p)
1350 return E_INVALIDARG;
1352 *p = NULL;
1354 buf = xmlBufferCreate();
1355 if(!buf)
1356 return E_OUTOFMEMORY;
1358 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1359 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1361 if(!ctxt)
1363 xmlBufferFree(buf);
1364 return E_OUTOFMEMORY;
1367 ret = xmlSaveDoc(ctxt, get_doc(This));
1368 /* flushes on close */
1369 xmlSaveClose(ctxt);
1371 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1372 if(ret != -1 && xmlBufferLength(buf) > 0)
1374 BSTR content;
1376 content = bstr_from_xmlChar(xmlBufferContent(buf));
1377 content = EnsureCorrectEOL(content);
1379 *p = content;
1381 else
1383 *p = SysAllocStringLen(NULL, 0);
1386 xmlBufferFree(buf);
1388 return *p ? S_OK : E_OUTOFMEMORY;
1392 static HRESULT WINAPI domdoc_transformNode(
1393 IXMLDOMDocument3 *iface,
1394 IXMLDOMNode *node,
1395 BSTR *p)
1397 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1398 TRACE("(%p)->(%p %p)\n", This, node, p);
1399 return node_transform_node(&This->node, node, p);
1403 static HRESULT WINAPI domdoc_selectNodes(
1404 IXMLDOMDocument3 *iface,
1405 BSTR p,
1406 IXMLDOMNodeList **outList)
1408 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1409 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1410 return node_select_nodes(&This->node, p, outList);
1414 static HRESULT WINAPI domdoc_selectSingleNode(
1415 IXMLDOMDocument3 *iface,
1416 BSTR p,
1417 IXMLDOMNode **outNode)
1419 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1420 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1421 return node_select_singlenode(&This->node, p, outNode);
1425 static HRESULT WINAPI domdoc_get_parsed(
1426 IXMLDOMDocument3 *iface,
1427 VARIANT_BOOL* isParsed )
1429 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1430 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1431 *isParsed = VARIANT_TRUE;
1432 return S_OK;
1435 static HRESULT WINAPI domdoc_get_namespaceURI(
1436 IXMLDOMDocument3 *iface,
1437 BSTR* namespaceURI )
1439 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1440 TRACE("(%p)->(%p)\n", This, namespaceURI);
1441 return return_null_bstr( namespaceURI );
1444 static HRESULT WINAPI domdoc_get_prefix(
1445 IXMLDOMDocument3 *iface,
1446 BSTR* prefix )
1448 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1449 TRACE("(%p)->(%p)\n", This, prefix);
1450 return return_null_bstr( prefix );
1454 static HRESULT WINAPI domdoc_get_baseName(
1455 IXMLDOMDocument3 *iface,
1456 BSTR* name )
1458 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1459 TRACE("(%p)->(%p)\n", This, name);
1460 return return_null_bstr( name );
1464 static HRESULT WINAPI domdoc_transformNodeToObject(
1465 IXMLDOMDocument3 *iface,
1466 IXMLDOMNode* stylesheet,
1467 VARIANT outputObject)
1469 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1470 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1471 return E_NOTIMPL;
1475 static HRESULT WINAPI domdoc_get_doctype(
1476 IXMLDOMDocument3 *iface,
1477 IXMLDOMDocumentType** doctype )
1479 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1480 IXMLDOMNode *node;
1481 xmlDtdPtr dtd;
1482 HRESULT hr;
1484 TRACE("(%p)->(%p)\n", This, doctype);
1486 if (!doctype) return E_INVALIDARG;
1488 *doctype = NULL;
1490 dtd = xmlGetIntSubset(get_doc(This));
1491 if (!dtd) return S_FALSE;
1493 node = create_node((xmlNodePtr)dtd);
1494 if (!node) return S_FALSE;
1496 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1497 IXMLDOMNode_Release(node);
1499 return hr;
1503 static HRESULT WINAPI domdoc_get_implementation(
1504 IXMLDOMDocument3 *iface,
1505 IXMLDOMImplementation** impl )
1507 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1509 TRACE("(%p)->(%p)\n", This, impl);
1511 if(!impl)
1512 return E_INVALIDARG;
1514 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1516 return S_OK;
1519 static HRESULT WINAPI domdoc_get_documentElement(
1520 IXMLDOMDocument3 *iface,
1521 IXMLDOMElement** DOMElement )
1523 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1524 IXMLDOMNode *element_node;
1525 xmlNodePtr root;
1526 HRESULT hr;
1528 TRACE("(%p)->(%p)\n", This, DOMElement);
1530 if(!DOMElement)
1531 return E_INVALIDARG;
1533 *DOMElement = NULL;
1535 root = xmlDocGetRootElement( get_doc(This) );
1536 if ( !root )
1537 return S_FALSE;
1539 element_node = create_node( root );
1540 if(!element_node) return S_FALSE;
1542 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1543 IXMLDOMNode_Release(element_node);
1545 return hr;
1549 static HRESULT WINAPI domdoc_put_documentElement(
1550 IXMLDOMDocument3 *iface,
1551 IXMLDOMElement* DOMElement )
1553 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1554 IXMLDOMNode *elementNode;
1555 xmlNodePtr oldRoot;
1556 xmlDocPtr old_doc;
1557 xmlnode *xmlNode;
1558 int refcount = 0;
1559 HRESULT hr;
1561 TRACE("(%p)->(%p)\n", This, DOMElement);
1563 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1564 if(FAILED(hr))
1565 return hr;
1567 xmlNode = get_node_obj( elementNode );
1568 if(!xmlNode) return E_FAIL;
1570 if(!xmlNode->node->parent)
1571 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1572 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1574 old_doc = xmlNode->node->doc;
1575 if (old_doc != get_doc(This))
1576 refcount = xmlnode_get_inst_cnt(xmlNode);
1578 /* old root is still orphaned by its document, update refcount from new root */
1579 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1580 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1581 if (refcount) xmldoc_release_refs(old_doc, refcount);
1582 IXMLDOMNode_Release( elementNode );
1584 if(oldRoot)
1585 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1587 return S_OK;
1591 static HRESULT WINAPI domdoc_createElement(
1592 IXMLDOMDocument3 *iface,
1593 BSTR tagname,
1594 IXMLDOMElement** element )
1596 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1597 IXMLDOMNode *node;
1598 VARIANT type;
1599 HRESULT hr;
1601 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1603 if (!element || !tagname) return E_INVALIDARG;
1605 V_VT(&type) = VT_I1;
1606 V_I1(&type) = NODE_ELEMENT;
1608 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1609 if (hr == S_OK)
1611 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1612 IXMLDOMNode_Release(node);
1615 return hr;
1619 static HRESULT WINAPI domdoc_createDocumentFragment(
1620 IXMLDOMDocument3 *iface,
1621 IXMLDOMDocumentFragment** frag )
1623 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1624 IXMLDOMNode *node;
1625 VARIANT type;
1626 HRESULT hr;
1628 TRACE("(%p)->(%p)\n", This, frag);
1630 if (!frag) return E_INVALIDARG;
1632 *frag = NULL;
1634 V_VT(&type) = VT_I1;
1635 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1637 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1638 if (hr == S_OK)
1640 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1641 IXMLDOMNode_Release(node);
1644 return hr;
1648 static HRESULT WINAPI domdoc_createTextNode(
1649 IXMLDOMDocument3 *iface,
1650 BSTR data,
1651 IXMLDOMText** text )
1653 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1654 IXMLDOMNode *node;
1655 VARIANT type;
1656 HRESULT hr;
1658 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1660 if (!text) return E_INVALIDARG;
1662 *text = NULL;
1664 V_VT(&type) = VT_I1;
1665 V_I1(&type) = NODE_TEXT;
1667 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1668 if (hr == S_OK)
1670 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1671 IXMLDOMNode_Release(node);
1672 hr = IXMLDOMText_put_data(*text, data);
1675 return hr;
1679 static HRESULT WINAPI domdoc_createComment(
1680 IXMLDOMDocument3 *iface,
1681 BSTR data,
1682 IXMLDOMComment** comment )
1684 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1685 VARIANT type;
1686 HRESULT hr;
1687 IXMLDOMNode *node;
1689 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1691 if (!comment) return E_INVALIDARG;
1693 *comment = NULL;
1695 V_VT(&type) = VT_I1;
1696 V_I1(&type) = NODE_COMMENT;
1698 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1699 if (hr == S_OK)
1701 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1702 IXMLDOMNode_Release(node);
1703 hr = IXMLDOMComment_put_data(*comment, data);
1706 return hr;
1710 static HRESULT WINAPI domdoc_createCDATASection(
1711 IXMLDOMDocument3 *iface,
1712 BSTR data,
1713 IXMLDOMCDATASection** cdata )
1715 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1716 IXMLDOMNode *node;
1717 VARIANT type;
1718 HRESULT hr;
1720 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1722 if (!cdata) return E_INVALIDARG;
1724 *cdata = NULL;
1726 V_VT(&type) = VT_I1;
1727 V_I1(&type) = NODE_CDATA_SECTION;
1729 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1730 if (hr == S_OK)
1732 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1733 IXMLDOMNode_Release(node);
1734 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1737 return hr;
1741 static HRESULT WINAPI domdoc_createProcessingInstruction(
1742 IXMLDOMDocument3 *iface,
1743 BSTR target,
1744 BSTR data,
1745 IXMLDOMProcessingInstruction** pi )
1747 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1748 IXMLDOMNode *node;
1749 VARIANT type;
1750 HRESULT hr;
1752 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1754 if (!pi) return E_INVALIDARG;
1756 *pi = NULL;
1758 V_VT(&type) = VT_I1;
1759 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1761 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1762 if (hr == S_OK)
1764 xmlnode *node_obj;
1766 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1767 node_obj = get_node_obj(node);
1768 hr = node_set_content(node_obj, data);
1770 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1771 IXMLDOMNode_Release(node);
1774 return hr;
1778 static HRESULT WINAPI domdoc_createAttribute(
1779 IXMLDOMDocument3 *iface,
1780 BSTR name,
1781 IXMLDOMAttribute** attribute )
1783 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1784 IXMLDOMNode *node;
1785 VARIANT type;
1786 HRESULT hr;
1788 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1790 if (!attribute || !name) return E_INVALIDARG;
1792 V_VT(&type) = VT_I1;
1793 V_I1(&type) = NODE_ATTRIBUTE;
1795 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1796 if (hr == S_OK)
1798 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1799 IXMLDOMNode_Release(node);
1802 return hr;
1806 static HRESULT WINAPI domdoc_createEntityReference(
1807 IXMLDOMDocument3 *iface,
1808 BSTR name,
1809 IXMLDOMEntityReference** entityref )
1811 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1812 IXMLDOMNode *node;
1813 VARIANT type;
1814 HRESULT hr;
1816 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1818 if (!entityref) return E_INVALIDARG;
1820 *entityref = NULL;
1822 V_VT(&type) = VT_I1;
1823 V_I1(&type) = NODE_ENTITY_REFERENCE;
1825 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1826 if (hr == S_OK)
1828 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1829 IXMLDOMNode_Release(node);
1832 return hr;
1835 xmlChar* tagName_to_XPath(const BSTR tagName)
1837 xmlChar *query, *tmp;
1838 static const xmlChar mod_pre[] = "*[local-name()='";
1839 static const xmlChar mod_post[] = "']";
1840 static const xmlChar prefix[] = "descendant::";
1841 const WCHAR *tokBegin, *tokEnd;
1842 int len;
1844 query = xmlStrdup(prefix);
1846 tokBegin = tagName;
1847 while (tokBegin && *tokBegin)
1849 switch (*tokBegin)
1851 case '/':
1852 query = xmlStrcat(query, BAD_CAST "/");
1853 ++tokBegin;
1854 break;
1855 case '*':
1856 query = xmlStrcat(query, BAD_CAST "*");
1857 ++tokBegin;
1858 break;
1859 default:
1860 query = xmlStrcat(query, mod_pre);
1861 tokEnd = tokBegin;
1862 while (*tokEnd && *tokEnd != '/')
1863 ++tokEnd;
1864 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1865 tmp = xmlMalloc(len);
1866 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1867 query = xmlStrncat(query, tmp, len);
1868 xmlFree(tmp);
1869 tokBegin = tokEnd;
1870 query = xmlStrcat(query, mod_post);
1874 return query;
1877 static HRESULT WINAPI domdoc_getElementsByTagName(
1878 IXMLDOMDocument3 *iface,
1879 BSTR tagName,
1880 IXMLDOMNodeList** resultList )
1882 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1883 xmlChar *query;
1884 HRESULT hr;
1885 BOOL XPath;
1887 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1889 if (!tagName || !resultList) return E_INVALIDARG;
1891 XPath = This->properties->XPath;
1892 This->properties->XPath = TRUE;
1893 query = tagName_to_XPath(tagName);
1894 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1895 xmlFree(query);
1896 This->properties->XPath = XPath;
1898 return hr;
1901 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1903 VARIANT tmp;
1904 HRESULT hr;
1906 VariantInit(&tmp);
1907 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1908 if(FAILED(hr))
1909 return E_INVALIDARG;
1911 *type = V_I4(&tmp);
1913 return S_OK;
1916 static HRESULT WINAPI domdoc_createNode(
1917 IXMLDOMDocument3 *iface,
1918 VARIANT Type,
1919 BSTR name,
1920 BSTR namespaceURI,
1921 IXMLDOMNode** node )
1923 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1924 DOMNodeType node_type;
1925 xmlNodePtr xmlnode;
1926 xmlChar *xml_name, *href;
1927 HRESULT hr;
1929 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1931 if(!node) return E_INVALIDARG;
1933 hr = get_node_type(Type, &node_type);
1934 if(FAILED(hr)) return hr;
1936 TRACE("node_type %d\n", node_type);
1938 /* exit earlier for types that need name */
1939 switch(node_type)
1941 case NODE_ELEMENT:
1942 case NODE_ATTRIBUTE:
1943 case NODE_ENTITY_REFERENCE:
1944 case NODE_PROCESSING_INSTRUCTION:
1945 if (!name || *name == 0) return E_FAIL;
1946 break;
1947 default:
1948 break;
1951 xml_name = xmlchar_from_wchar(name);
1952 /* prevent empty href to be allocated */
1953 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1955 switch(node_type)
1957 case NODE_ELEMENT:
1959 xmlChar *local, *prefix;
1961 local = xmlSplitQName2(xml_name, &prefix);
1963 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1965 /* allow to create default namespace xmlns= */
1966 if (local || (href && *href))
1968 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1969 xmlSetNs(xmlnode, ns);
1972 xmlFree(local);
1973 xmlFree(prefix);
1975 break;
1977 case NODE_ATTRIBUTE:
1979 xmlChar *local, *prefix;
1981 local = xmlSplitQName2(xml_name, &prefix);
1983 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
1985 if (local || (href && *href))
1987 /* we need a floating namespace here, it can't be created linked to attribute from
1988 a start */
1989 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
1990 xmlSetNs(xmlnode, ns);
1993 xmlFree(local);
1994 xmlFree(prefix);
1996 break;
1998 case NODE_TEXT:
1999 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2000 break;
2001 case NODE_CDATA_SECTION:
2002 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2003 break;
2004 case NODE_ENTITY_REFERENCE:
2005 xmlnode = xmlNewReference(get_doc(This), xml_name);
2006 break;
2007 case NODE_PROCESSING_INSTRUCTION:
2008 #ifdef HAVE_XMLNEWDOCPI
2009 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2010 #else
2011 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2012 xmlnode = NULL;
2013 #endif
2014 break;
2015 case NODE_COMMENT:
2016 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2017 break;
2018 case NODE_DOCUMENT_FRAGMENT:
2019 xmlnode = xmlNewDocFragment(get_doc(This));
2020 break;
2021 /* unsupported types */
2022 case NODE_DOCUMENT:
2023 case NODE_DOCUMENT_TYPE:
2024 case NODE_ENTITY:
2025 case NODE_NOTATION:
2026 heap_free(xml_name);
2027 return E_INVALIDARG;
2028 default:
2029 FIXME("unhandled node type %d\n", node_type);
2030 xmlnode = NULL;
2031 break;
2034 *node = create_node(xmlnode);
2035 heap_free(xml_name);
2036 heap_free(href);
2038 if(*node)
2040 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2041 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2042 return S_OK;
2045 return E_FAIL;
2048 static HRESULT WINAPI domdoc_nodeFromID(
2049 IXMLDOMDocument3 *iface,
2050 BSTR idString,
2051 IXMLDOMNode** node )
2053 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2054 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2055 return E_NOTIMPL;
2058 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2060 domdoc *This = obj;
2061 xmlDocPtr xmldoc;
2063 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2064 if(xmldoc) {
2065 xmldoc->_private = create_priv();
2066 return attach_xmldoc(This, xmldoc);
2069 return E_FAIL;
2072 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2074 bsc_t *bsc;
2075 HRESULT hr;
2077 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2078 if(FAILED(hr))
2079 return hr;
2081 return detach_bsc(bsc);
2084 static HRESULT WINAPI domdoc_load(
2085 IXMLDOMDocument3 *iface,
2086 VARIANT source,
2087 VARIANT_BOOL* isSuccessful )
2089 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2090 LPWSTR filename = NULL;
2091 HRESULT hr = S_FALSE;
2092 xmlDocPtr xmldoc;
2094 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2096 if (!isSuccessful)
2097 return E_POINTER;
2098 *isSuccessful = VARIANT_FALSE;
2100 assert( &This->node );
2102 switch( V_VT(&source) )
2104 case VT_BSTR:
2105 filename = V_BSTR(&source);
2106 break;
2107 case VT_BSTR|VT_BYREF:
2108 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2109 filename = *V_BSTRREF(&source);
2110 break;
2111 case VT_ARRAY|VT_UI1:
2113 SAFEARRAY *psa = V_ARRAY(&source);
2114 char *str;
2115 LONG len;
2116 UINT dim = SafeArrayGetDim(psa);
2118 switch (dim)
2120 case 0:
2121 ERR("SAFEARRAY == NULL\n");
2122 hr = This->error = E_INVALIDARG;
2123 break;
2124 case 1:
2125 /* Only takes UTF-8 strings.
2126 * NOT NULL-terminated. */
2127 SafeArrayAccessData(psa, (void**)&str);
2128 SafeArrayGetUBound(psa, 1, &len);
2130 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2132 hr = This->error = S_OK;
2133 *isSuccessful = VARIANT_TRUE;
2134 TRACE("parsed document %p\n", xmldoc);
2136 else
2138 This->error = E_FAIL;
2139 TRACE("failed to parse document\n");
2142 SafeArrayUnaccessData(psa);
2144 if(xmldoc)
2146 xmldoc->_private = create_priv();
2147 return attach_xmldoc(This, xmldoc);
2149 break;
2150 default:
2151 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2152 hr = This->error = E_NOTIMPL;
2155 break;
2156 case VT_UNKNOWN:
2158 ISequentialStream *stream = NULL;
2159 IXMLDOMDocument3 *newdoc = NULL;
2161 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2163 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2164 if(hr == S_OK)
2166 if(newdoc)
2168 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2170 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2171 xmldoc->_private = create_priv();
2172 hr = attach_xmldoc(This, xmldoc);
2174 if(SUCCEEDED(hr))
2175 *isSuccessful = VARIANT_TRUE;
2177 return hr;
2181 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2182 if (FAILED(hr))
2183 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2185 if (hr == S_OK)
2187 hr = domdoc_load_from_stream(This, stream);
2188 if (hr == S_OK)
2189 *isSuccessful = VARIANT_TRUE;
2190 ISequentialStream_Release(stream);
2191 return hr;
2194 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2195 break;
2197 default:
2198 FIXME("VT type not supported (%d)\n", V_VT(&source));
2201 if ( filename )
2203 IMoniker *mon;
2205 CoTaskMemFree(This->url);
2206 This->url = NULL;
2208 hr = create_moniker_from_url( filename, &mon);
2209 if ( SUCCEEDED(hr) )
2211 hr = domdoc_load_moniker( This, mon );
2212 if (hr == S_OK)
2213 IMoniker_GetDisplayName(mon, NULL, NULL, &This->url);
2214 IMoniker_Release(mon);
2217 if ( FAILED(hr) )
2218 This->error = E_FAIL;
2219 else
2221 hr = This->error = S_OK;
2222 *isSuccessful = VARIANT_TRUE;
2226 if(!filename || FAILED(hr)) {
2227 xmldoc = xmlNewDoc(NULL);
2228 xmldoc->_private = create_priv();
2229 hr = attach_xmldoc(This, xmldoc);
2230 if(SUCCEEDED(hr))
2231 hr = S_FALSE;
2234 TRACE("ret (%d)\n", hr);
2236 return hr;
2240 static HRESULT WINAPI domdoc_get_readyState(
2241 IXMLDOMDocument3 *iface,
2242 LONG *value )
2244 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2245 FIXME("stub! (%p)->(%p)\n", This, value);
2247 if (!value)
2248 return E_INVALIDARG;
2250 *value = READYSTATE_COMPLETE;
2251 return S_OK;
2255 static HRESULT WINAPI domdoc_get_parseError(
2256 IXMLDOMDocument3 *iface,
2257 IXMLDOMParseError** errorObj )
2259 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2260 static const WCHAR err[] = {'e','r','r','o','r',0};
2261 BSTR error_string = NULL;
2263 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2265 if(This->error)
2266 error_string = SysAllocString(err);
2268 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2269 if(!*errorObj) return E_OUTOFMEMORY;
2270 return S_OK;
2274 static HRESULT WINAPI domdoc_get_url(
2275 IXMLDOMDocument3 *iface,
2276 BSTR* url )
2278 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2280 TRACE("(%p)->(%p)\n", This, url);
2282 if (!url)
2283 return E_INVALIDARG;
2285 if (This->url)
2287 *url = SysAllocString(This->url);
2288 if (!*url)
2289 return E_OUTOFMEMORY;
2291 return S_OK;
2293 else
2294 return return_null_bstr(url);
2298 static HRESULT WINAPI domdoc_get_async(
2299 IXMLDOMDocument3 *iface,
2300 VARIANT_BOOL* isAsync )
2302 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2304 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2305 *isAsync = This->async;
2306 return S_OK;
2310 static HRESULT WINAPI domdoc_put_async(
2311 IXMLDOMDocument3 *iface,
2312 VARIANT_BOOL isAsync )
2314 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2316 TRACE("(%p)->(%d)\n", This, isAsync);
2317 This->async = isAsync;
2318 return S_OK;
2322 static HRESULT WINAPI domdoc_abort(
2323 IXMLDOMDocument3 *iface )
2325 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2326 FIXME("%p\n", This);
2327 return E_NOTIMPL;
2330 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2331 static HRESULT WINAPI domdoc_loadXML(
2332 IXMLDOMDocument3 *iface,
2333 BSTR data,
2334 VARIANT_BOOL* isSuccessful )
2336 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2337 xmlDocPtr xmldoc = NULL;
2338 HRESULT hr = S_FALSE, hr2;
2340 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2342 assert ( &This->node );
2344 if ( isSuccessful )
2346 *isSuccessful = VARIANT_FALSE;
2348 if (data)
2350 WCHAR *ptr = data;
2352 /* skip leading spaces if needed */
2353 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2354 while (*ptr && isspaceW(*ptr)) ptr++;
2356 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2357 if ( !xmldoc )
2359 This->error = E_FAIL;
2360 TRACE("failed to parse document\n");
2362 else
2364 hr = This->error = S_OK;
2365 *isSuccessful = VARIANT_TRUE;
2366 TRACE("parsed document %p\n", xmldoc);
2371 if(!xmldoc)
2372 xmldoc = xmlNewDoc(NULL);
2373 xmldoc->_private = create_priv();
2374 hr2 = attach_xmldoc(This, xmldoc);
2375 if( FAILED(hr2) )
2376 hr = hr2;
2378 return hr;
2381 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2383 DWORD written = -1;
2385 if(!WriteFile(ctx, buffer, len, &written, NULL))
2387 WARN("write error\n");
2388 return -1;
2390 else
2391 return written;
2394 static int XMLCALL domdoc_save_closecallback(void *ctx)
2396 return CloseHandle(ctx) ? 0 : -1;
2399 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2401 ULONG written = 0;
2402 HRESULT hr;
2404 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2405 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2406 if (hr != S_OK)
2408 WARN("stream write error: 0x%08x\n", hr);
2409 return -1;
2411 else
2412 return len;
2415 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2417 IStream_Release((IStream*)ctx);
2418 return 0;
2421 static HRESULT WINAPI domdoc_save(
2422 IXMLDOMDocument3 *iface,
2423 VARIANT destination )
2425 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2426 xmlSaveCtxtPtr ctx = NULL;
2427 xmlNodePtr xmldecl;
2428 HRESULT ret = S_OK;
2430 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2432 switch (V_VT(&destination))
2434 case VT_UNKNOWN:
2436 IUnknown *pUnk = V_UNKNOWN(&destination);
2437 IXMLDOMDocument3 *document;
2438 IStream *stream;
2440 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2441 if(ret == S_OK)
2443 VARIANT_BOOL success;
2444 BSTR xml;
2446 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2447 if(ret == S_OK)
2449 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2450 SysFreeString(xml);
2453 IXMLDOMDocument3_Release(document);
2454 return ret;
2457 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2458 if(ret == S_OK)
2460 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2461 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2462 domdoc_stream_save_closecallback, stream, NULL, options);
2464 if(!ctx)
2466 IStream_Release(stream);
2467 return E_FAIL;
2471 break;
2473 case VT_BSTR:
2474 case VT_BSTR | VT_BYREF:
2476 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2478 /* save with file path */
2479 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2480 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2481 if( handle == INVALID_HANDLE_VALUE )
2483 WARN("failed to create file\n");
2484 return E_FAIL;
2487 /* disable top XML declaration */
2488 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2489 handle, NULL, options);
2490 if (!ctx)
2492 CloseHandle(handle);
2493 return E_FAIL;
2496 break;
2498 default:
2499 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2500 return S_FALSE;
2503 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2504 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2505 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2507 /* will release resources through close callback */
2508 xmlSaveClose(ctx);
2510 return ret;
2513 static HRESULT WINAPI domdoc_get_validateOnParse(
2514 IXMLDOMDocument3 *iface,
2515 VARIANT_BOOL* isValidating )
2517 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2518 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2519 *isValidating = This->validating;
2520 return S_OK;
2524 static HRESULT WINAPI domdoc_put_validateOnParse(
2525 IXMLDOMDocument3 *iface,
2526 VARIANT_BOOL isValidating )
2528 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2529 TRACE("(%p)->(%d)\n", This, isValidating);
2530 This->validating = isValidating;
2531 return S_OK;
2535 static HRESULT WINAPI domdoc_get_resolveExternals(
2536 IXMLDOMDocument3 *iface,
2537 VARIANT_BOOL* isResolving )
2539 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2540 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2541 *isResolving = This->resolving;
2542 return S_OK;
2546 static HRESULT WINAPI domdoc_put_resolveExternals(
2547 IXMLDOMDocument3 *iface,
2548 VARIANT_BOOL isResolving )
2550 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2551 TRACE("(%p)->(%d)\n", This, isResolving);
2552 This->resolving = isResolving;
2553 return S_OK;
2557 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2558 IXMLDOMDocument3 *iface,
2559 VARIANT_BOOL* isPreserving )
2561 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2562 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2563 *isPreserving = This->properties->preserving;
2564 return S_OK;
2568 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2569 IXMLDOMDocument3 *iface,
2570 VARIANT_BOOL isPreserving )
2572 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2573 TRACE("(%p)->(%d)\n", This, isPreserving);
2574 This->properties->preserving = isPreserving;
2575 return S_OK;
2579 static HRESULT WINAPI domdoc_put_onreadystatechange(
2580 IXMLDOMDocument3 *iface,
2581 VARIANT event )
2583 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2585 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2586 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2590 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2592 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2593 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2594 return E_NOTIMPL;
2597 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2599 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2600 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2601 return E_NOTIMPL;
2604 static HRESULT WINAPI domdoc_get_namespaces(
2605 IXMLDOMDocument3* iface,
2606 IXMLDOMSchemaCollection** collection )
2608 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2609 HRESULT hr;
2611 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2613 if (!collection) return E_POINTER;
2615 if (!This->namespaces)
2617 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2618 if (hr != S_OK) return hr;
2620 hr = cache_from_doc_ns(This->namespaces, &This->node);
2621 if (hr != S_OK)
2622 release_namespaces(This);
2625 if (This->namespaces)
2626 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2627 &IID_IXMLDOMSchemaCollection, (void**)collection);
2629 return hr;
2632 static HRESULT WINAPI domdoc_get_schemas(
2633 IXMLDOMDocument3* iface,
2634 VARIANT* schema )
2636 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2637 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2638 HRESULT hr = S_FALSE;
2640 TRACE("(%p)->(%p)\n", This, schema);
2642 V_VT(schema) = VT_NULL;
2643 /* just to reset pointer part, cause that's what application is expected to use */
2644 V_DISPATCH(schema) = NULL;
2646 if(cur_schema)
2648 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2649 if(SUCCEEDED(hr))
2650 V_VT(schema) = VT_DISPATCH;
2652 return hr;
2655 static HRESULT WINAPI domdoc_putref_schemas(
2656 IXMLDOMDocument3* iface,
2657 VARIANT schema)
2659 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2660 HRESULT hr = E_FAIL;
2661 IXMLDOMSchemaCollection2* new_schema = NULL;
2663 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2664 switch(V_VT(&schema))
2666 case VT_UNKNOWN:
2667 if (V_UNKNOWN(&schema))
2669 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2670 break;
2672 /* fallthrough */
2673 case VT_DISPATCH:
2674 if (V_DISPATCH(&schema))
2676 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2677 break;
2679 /* fallthrough */
2680 case VT_NULL:
2681 case VT_EMPTY:
2682 hr = S_OK;
2683 break;
2685 default:
2686 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2689 if(SUCCEEDED(hr))
2691 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2692 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2695 return hr;
2698 static inline BOOL is_wellformed(xmlDocPtr doc)
2700 #ifdef HAVE_XMLDOC_PROPERTIES
2701 return doc->properties & XML_DOC_WELLFORMED;
2702 #else
2703 /* Not a full check, but catches the worst violations */
2704 xmlNodePtr child;
2705 int root = 0;
2707 for (child = doc->children; child != NULL; child = child->next)
2709 switch (child->type)
2711 case XML_ELEMENT_NODE:
2712 if (++root > 1)
2713 return FALSE;
2714 break;
2715 case XML_TEXT_NODE:
2716 case XML_CDATA_SECTION_NODE:
2717 return FALSE;
2718 break;
2719 default:
2720 break;
2724 return root == 1;
2725 #endif
2728 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2730 va_list ap;
2731 va_start(ap, msg);
2732 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2733 va_end(ap);
2736 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2738 va_list ap;
2739 va_start(ap, msg);
2740 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2741 va_end(ap);
2744 static HRESULT WINAPI domdoc_validateNode(
2745 IXMLDOMDocument3* iface,
2746 IXMLDOMNode* node,
2747 IXMLDOMParseError** err)
2749 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2750 LONG state, err_code = 0;
2751 HRESULT hr = S_OK;
2752 int validated = 0;
2754 TRACE("(%p)->(%p, %p)\n", This, node, err);
2755 IXMLDOMDocument3_get_readyState(iface, &state);
2756 if (state != READYSTATE_COMPLETE)
2758 if (err)
2759 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2760 return E_PENDING;
2763 if (!node)
2765 if (err)
2766 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2767 return E_POINTER;
2770 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2772 if (err)
2773 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2774 return E_FAIL;
2777 if (!is_wellformed(get_doc(This)))
2779 ERR("doc not well-formed\n");
2780 if (err)
2781 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2782 return S_FALSE;
2785 /* DTD validation */
2786 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2788 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2789 vctx->error = validate_error;
2790 vctx->warning = validate_warning;
2791 ++validated;
2793 if (!((node == (IXMLDOMNode*)iface)?
2794 xmlValidateDocument(vctx, get_doc(This)) :
2795 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2797 /* TODO: get a real error code here */
2798 TRACE("DTD validation failed\n");
2799 err_code = E_XML_INVALID;
2800 hr = S_FALSE;
2802 xmlFreeValidCtxt(vctx);
2805 /* Schema validation */
2806 if (hr == S_OK && This->properties->schemaCache != NULL)
2809 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2810 if (SUCCEEDED(hr))
2812 ++validated;
2813 /* TODO: get a real error code here */
2814 if (hr == S_OK)
2816 TRACE("schema validation succeeded\n");
2818 else
2820 ERR("schema validation failed\n");
2821 err_code = E_XML_INVALID;
2824 else
2826 /* not really OK, just didn't find a schema for the ns */
2827 hr = S_OK;
2831 if (!validated)
2833 ERR("no DTD or schema found\n");
2834 err_code = E_XML_NODTD;
2835 hr = S_FALSE;
2838 if (err)
2839 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2841 return hr;
2844 static HRESULT WINAPI domdoc_validate(
2845 IXMLDOMDocument3* iface,
2846 IXMLDOMParseError** err)
2848 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2849 TRACE("(%p)->(%p)\n", This, err);
2850 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2853 static HRESULT WINAPI domdoc_setProperty(
2854 IXMLDOMDocument3* iface,
2855 BSTR p,
2856 VARIANT value)
2858 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2860 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2862 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2864 VARIANT varStr;
2865 HRESULT hr;
2866 BSTR bstr;
2868 V_VT(&varStr) = VT_EMPTY;
2869 if (V_VT(&value) != VT_BSTR)
2871 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2872 return hr;
2873 bstr = V_BSTR(&varStr);
2875 else
2876 bstr = V_BSTR(&value);
2878 hr = S_OK;
2879 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2880 This->properties->XPath = TRUE;
2881 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2882 This->properties->XPath = FALSE;
2883 else
2884 hr = E_FAIL;
2886 VariantClear(&varStr);
2887 return hr;
2889 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2891 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2892 struct list *pNsList;
2893 VARIANT varStr;
2894 HRESULT hr;
2895 BSTR bstr;
2897 V_VT(&varStr) = VT_EMPTY;
2898 if (V_VT(&value) != VT_BSTR)
2900 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2901 return hr;
2902 bstr = V_BSTR(&varStr);
2904 else
2905 bstr = V_BSTR(&value);
2907 hr = S_OK;
2909 pNsList = &(This->properties->selectNsList);
2910 clear_selectNsList(pNsList);
2911 heap_free(nsStr);
2912 nsStr = xmlchar_from_wchar(bstr);
2914 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2916 This->properties->selectNsStr = nsStr;
2917 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2918 if (bstr && *bstr)
2920 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2921 select_ns_entry* ns_entry = NULL;
2922 xmlXPathContextPtr ctx;
2924 ctx = xmlXPathNewContext(This->node.node->doc);
2925 pTokBegin = nsStr;
2927 /* skip leading spaces */
2928 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2929 *pTokBegin == '\t' || *pTokBegin == '\r')
2930 ++pTokBegin;
2932 for (; *pTokBegin; pTokBegin = pTokEnd)
2934 if (ns_entry)
2935 memset(ns_entry, 0, sizeof(select_ns_entry));
2936 else
2937 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2939 while (*pTokBegin == ' ')
2940 ++pTokBegin;
2941 pTokEnd = pTokBegin;
2942 while (*pTokEnd != ' ' && *pTokEnd != 0)
2943 ++pTokEnd;
2945 /* so it failed to advance which means we've got some trailing spaces */
2946 if (pTokEnd == pTokBegin) break;
2948 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2950 hr = E_FAIL;
2951 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2952 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2953 continue;
2956 pTokBegin += 5;
2957 if (*pTokBegin == '=')
2959 /*valid for XSLPattern?*/
2960 FIXME("Setting default xmlns not supported - skipping.\n");
2961 continue;
2963 else if (*pTokBegin == ':')
2965 ns_entry->prefix = ++pTokBegin;
2966 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2969 if (pTokInner == pTokEnd)
2971 hr = E_FAIL;
2972 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2973 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2974 continue;
2977 ns_entry->prefix_end = *pTokInner;
2978 *pTokInner = 0;
2979 ++pTokInner;
2981 if (pTokEnd-pTokInner > 1 &&
2982 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2983 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2985 ns_entry->href = ++pTokInner;
2986 ns_entry->href_end = *(pTokEnd-1);
2987 *(pTokEnd-1) = 0;
2988 list_add_tail(pNsList, &ns_entry->entry);
2989 /*let libxml figure out if they're valid from here ;)*/
2990 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2992 hr = E_FAIL;
2994 ns_entry = NULL;
2995 continue;
2997 else
2999 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3000 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3001 list_add_tail(pNsList, &ns_entry->entry);
3003 ns_entry = NULL;
3004 hr = E_FAIL;
3005 continue;
3008 else
3010 hr = E_FAIL;
3011 continue;
3014 heap_free(ns_entry);
3015 xmlXPathFreeContext(ctx);
3018 VariantClear(&varStr);
3019 return hr;
3021 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3022 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3023 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
3025 /* Ignore */
3026 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3027 return S_OK;
3030 FIXME("Unknown property %s\n", debugstr_w(p));
3031 return E_FAIL;
3034 static HRESULT WINAPI domdoc_getProperty(
3035 IXMLDOMDocument3* iface,
3036 BSTR p,
3037 VARIANT* var)
3039 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3041 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3043 if (!var)
3044 return E_INVALIDARG;
3046 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3048 V_VT(var) = VT_BSTR;
3049 V_BSTR(var) = This->properties->XPath ?
3050 SysAllocString(PropValueXPathW) :
3051 SysAllocString(PropValueXSLPatternW);
3052 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3054 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3056 int lenA, lenW;
3057 BSTR rebuiltStr, cur;
3058 const xmlChar *nsStr;
3059 struct list *pNsList;
3060 select_ns_entry* pNsEntry;
3062 V_VT(var) = VT_BSTR;
3063 nsStr = This->properties->selectNsStr;
3064 pNsList = &This->properties->selectNsList;
3065 lenA = This->properties->selectNsStr_len;
3066 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3067 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3068 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3069 cur = rebuiltStr;
3070 /* this is fine because all of the chars that end tokens are ASCII*/
3071 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3073 while (*cur != 0) ++cur;
3074 if (pNsEntry->prefix_end)
3076 *cur = pNsEntry->prefix_end;
3077 while (*cur != 0) ++cur;
3080 if (pNsEntry->href_end)
3082 *cur = pNsEntry->href_end;
3085 V_BSTR(var) = SysAllocString(rebuiltStr);
3086 heap_free(rebuiltStr);
3087 return S_OK;
3090 FIXME("Unknown property %s\n", debugstr_w(p));
3091 return E_FAIL;
3094 static HRESULT WINAPI domdoc_importNode(
3095 IXMLDOMDocument3* iface,
3096 IXMLDOMNode* node,
3097 VARIANT_BOOL deep,
3098 IXMLDOMNode** clone)
3100 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3101 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3102 return E_NOTIMPL;
3105 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3107 domdoc_QueryInterface,
3108 domdoc_AddRef,
3109 domdoc_Release,
3110 domdoc_GetTypeInfoCount,
3111 domdoc_GetTypeInfo,
3112 domdoc_GetIDsOfNames,
3113 domdoc_Invoke,
3114 domdoc_get_nodeName,
3115 domdoc_get_nodeValue,
3116 domdoc_put_nodeValue,
3117 domdoc_get_nodeType,
3118 domdoc_get_parentNode,
3119 domdoc_get_childNodes,
3120 domdoc_get_firstChild,
3121 domdoc_get_lastChild,
3122 domdoc_get_previousSibling,
3123 domdoc_get_nextSibling,
3124 domdoc_get_attributes,
3125 domdoc_insertBefore,
3126 domdoc_replaceChild,
3127 domdoc_removeChild,
3128 domdoc_appendChild,
3129 domdoc_hasChildNodes,
3130 domdoc_get_ownerDocument,
3131 domdoc_cloneNode,
3132 domdoc_get_nodeTypeString,
3133 domdoc_get_text,
3134 domdoc_put_text,
3135 domdoc_get_specified,
3136 domdoc_get_definition,
3137 domdoc_get_nodeTypedValue,
3138 domdoc_put_nodeTypedValue,
3139 domdoc_get_dataType,
3140 domdoc_put_dataType,
3141 domdoc_get_xml,
3142 domdoc_transformNode,
3143 domdoc_selectNodes,
3144 domdoc_selectSingleNode,
3145 domdoc_get_parsed,
3146 domdoc_get_namespaceURI,
3147 domdoc_get_prefix,
3148 domdoc_get_baseName,
3149 domdoc_transformNodeToObject,
3150 domdoc_get_doctype,
3151 domdoc_get_implementation,
3152 domdoc_get_documentElement,
3153 domdoc_put_documentElement,
3154 domdoc_createElement,
3155 domdoc_createDocumentFragment,
3156 domdoc_createTextNode,
3157 domdoc_createComment,
3158 domdoc_createCDATASection,
3159 domdoc_createProcessingInstruction,
3160 domdoc_createAttribute,
3161 domdoc_createEntityReference,
3162 domdoc_getElementsByTagName,
3163 domdoc_createNode,
3164 domdoc_nodeFromID,
3165 domdoc_load,
3166 domdoc_get_readyState,
3167 domdoc_get_parseError,
3168 domdoc_get_url,
3169 domdoc_get_async,
3170 domdoc_put_async,
3171 domdoc_abort,
3172 domdoc_loadXML,
3173 domdoc_save,
3174 domdoc_get_validateOnParse,
3175 domdoc_put_validateOnParse,
3176 domdoc_get_resolveExternals,
3177 domdoc_put_resolveExternals,
3178 domdoc_get_preserveWhiteSpace,
3179 domdoc_put_preserveWhiteSpace,
3180 domdoc_put_onreadystatechange,
3181 domdoc_put_onDataAvailable,
3182 domdoc_put_onTransformNode,
3183 domdoc_get_namespaces,
3184 domdoc_get_schemas,
3185 domdoc_putref_schemas,
3186 domdoc_validate,
3187 domdoc_setProperty,
3188 domdoc_getProperty,
3189 domdoc_validateNode,
3190 domdoc_importNode
3193 /* IConnectionPointContainer */
3194 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3195 REFIID riid, void **ppv)
3197 domdoc *This = impl_from_IConnectionPointContainer(iface);
3198 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3201 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3203 domdoc *This = impl_from_IConnectionPointContainer(iface);
3204 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3207 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3209 domdoc *This = impl_from_IConnectionPointContainer(iface);
3210 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3213 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3214 IEnumConnectionPoints **ppEnum)
3216 domdoc *This = impl_from_IConnectionPointContainer(iface);
3217 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3218 return E_NOTIMPL;
3221 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3222 REFIID riid, IConnectionPoint **cp)
3224 domdoc *This = impl_from_IConnectionPointContainer(iface);
3225 ConnectionPoint *iter;
3227 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3229 *cp = NULL;
3231 for(iter = This->cp_list; iter; iter = iter->next)
3233 if (IsEqualGUID(iter->iid, riid))
3234 *cp = &iter->IConnectionPoint_iface;
3237 if (*cp)
3239 IConnectionPoint_AddRef(*cp);
3240 return S_OK;
3243 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3244 return CONNECT_E_NOCONNECTION;
3248 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3250 ConnectionPointContainer_QueryInterface,
3251 ConnectionPointContainer_AddRef,
3252 ConnectionPointContainer_Release,
3253 ConnectionPointContainer_EnumConnectionPoints,
3254 ConnectionPointContainer_FindConnectionPoint
3257 /* IConnectionPoint */
3258 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3259 REFIID riid, void **ppv)
3261 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3263 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3265 *ppv = NULL;
3267 if (IsEqualGUID(&IID_IUnknown, riid) ||
3268 IsEqualGUID(&IID_IConnectionPoint, riid))
3270 *ppv = iface;
3273 if (*ppv)
3275 IConnectionPoint_AddRef(iface);
3276 return S_OK;
3279 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3280 return E_NOINTERFACE;
3283 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3285 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3286 return IConnectionPointContainer_AddRef(This->container);
3289 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3291 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3292 return IConnectionPointContainer_Release(This->container);
3295 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3297 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3299 TRACE("(%p)->(%p)\n", This, iid);
3301 if (!iid) return E_POINTER;
3303 *iid = *This->iid;
3304 return S_OK;
3307 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3308 IConnectionPointContainer **container)
3310 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3312 TRACE("(%p)->(%p)\n", This, container);
3314 if (!container) return E_POINTER;
3316 *container = This->container;
3317 IConnectionPointContainer_AddRef(*container);
3318 return S_OK;
3321 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3322 DWORD *cookie)
3324 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3325 IUnknown *sink;
3326 HRESULT hr;
3327 DWORD i;
3329 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3331 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3332 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3333 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3334 if(FAILED(hr))
3335 return CONNECT_E_CANNOTCONNECT;
3337 if(This->sinks)
3339 for (i = 0; i < This->sinks_size; i++)
3340 if (!This->sinks[i].unk)
3341 break;
3343 if (i == This->sinks_size)
3344 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3346 else
3348 This->sinks = heap_alloc(sizeof(*This->sinks));
3349 This->sinks_size = 1;
3350 i = 0;
3353 This->sinks[i].unk = sink;
3354 if (cookie)
3355 *cookie = i+1;
3357 return S_OK;
3360 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3362 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3364 TRACE("(%p)->(%d)\n", This, cookie);
3366 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3367 return CONNECT_E_NOCONNECTION;
3369 IUnknown_Release(This->sinks[cookie-1].unk);
3370 This->sinks[cookie-1].unk = NULL;
3372 return S_OK;
3375 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3376 IEnumConnections **ppEnum)
3378 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3379 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3380 return E_NOTIMPL;
3383 static const IConnectionPointVtbl ConnectionPointVtbl =
3385 ConnectionPoint_QueryInterface,
3386 ConnectionPoint_AddRef,
3387 ConnectionPoint_Release,
3388 ConnectionPoint_GetConnectionInterface,
3389 ConnectionPoint_GetConnectionPointContainer,
3390 ConnectionPoint_Advise,
3391 ConnectionPoint_Unadvise,
3392 ConnectionPoint_EnumConnections
3395 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3397 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3398 cp->doc = doc;
3399 cp->iid = riid;
3400 cp->sinks = NULL;
3401 cp->sinks_size = 0;
3403 cp->next = doc->cp_list;
3404 doc->cp_list = cp;
3406 cp->container = &doc->IConnectionPointContainer_iface;
3409 /* domdoc implementation of IObjectWithSite */
3410 static HRESULT WINAPI
3411 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3413 domdoc *This = impl_from_IObjectWithSite(iface);
3414 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3417 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3419 domdoc *This = impl_from_IObjectWithSite(iface);
3420 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3423 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3425 domdoc *This = impl_from_IObjectWithSite(iface);
3426 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3429 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3431 domdoc *This = impl_from_IObjectWithSite(iface);
3433 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3435 if ( !This->site )
3436 return E_FAIL;
3438 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3441 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3443 domdoc *This = impl_from_IObjectWithSite(iface);
3445 TRACE("(%p)->(%p)\n", iface, punk);
3447 if(!punk)
3449 if(This->site)
3451 IUnknown_Release( This->site );
3452 This->site = NULL;
3455 return S_OK;
3458 IUnknown_AddRef( punk );
3460 if(This->site)
3461 IUnknown_Release( This->site );
3463 This->site = punk;
3465 return S_OK;
3468 static const IObjectWithSiteVtbl domdocObjectSite =
3470 domdoc_ObjectWithSite_QueryInterface,
3471 domdoc_ObjectWithSite_AddRef,
3472 domdoc_ObjectWithSite_Release,
3473 domdoc_ObjectWithSite_SetSite,
3474 domdoc_ObjectWithSite_GetSite
3477 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3479 domdoc *This = impl_from_IObjectSafety(iface);
3480 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3483 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3485 domdoc *This = impl_from_IObjectSafety(iface);
3486 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3489 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3491 domdoc *This = impl_from_IObjectSafety(iface);
3492 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3495 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3497 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3498 DWORD *supported, DWORD *enabled)
3500 domdoc *This = impl_from_IObjectSafety(iface);
3502 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3504 if(!supported || !enabled) return E_POINTER;
3506 *supported = SAFETY_SUPPORTED_OPTIONS;
3507 *enabled = This->safeopt;
3509 return S_OK;
3512 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3513 DWORD mask, DWORD enabled)
3515 domdoc *This = impl_from_IObjectSafety(iface);
3516 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3518 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3519 return E_FAIL;
3521 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3523 return S_OK;
3526 #undef SAFETY_SUPPORTED_OPTIONS
3528 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3529 domdoc_Safety_QueryInterface,
3530 domdoc_Safety_AddRef,
3531 domdoc_Safety_Release,
3532 domdoc_Safety_GetInterfaceSafetyOptions,
3533 domdoc_Safety_SetInterfaceSafetyOptions
3536 static const tid_t domdoc_iface_tids[] = {
3537 IXMLDOMDocument3_tid,
3541 static dispex_static_data_t domdoc_dispex = {
3542 NULL,
3543 IXMLDOMDocument3_tid,
3544 NULL,
3545 domdoc_iface_tids
3548 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3550 domdoc *doc;
3552 doc = heap_alloc( sizeof (*doc) );
3553 if( !doc )
3554 return E_OUTOFMEMORY;
3556 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3557 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3558 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3559 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3560 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3561 doc->ref = 1;
3562 doc->async = VARIANT_TRUE;
3563 doc->validating = 0;
3564 doc->resolving = 0;
3565 doc->properties = properties_from_xmlDocPtr(xmldoc);
3566 doc->error = S_OK;
3567 doc->site = NULL;
3568 doc->safeopt = 0;
3569 doc->cp_list = NULL;
3570 doc->namespaces = NULL;
3571 doc->url = NULL;
3572 memset(doc->events, 0, sizeof(doc->events));
3574 /* events connection points */
3575 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3576 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3577 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3579 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3580 &domdoc_dispex);
3582 *document = &doc->IXMLDOMDocument3_iface;
3584 TRACE("returning iface %p\n", *document);
3585 return S_OK;
3588 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3590 xmlDocPtr xmldoc;
3591 HRESULT hr;
3593 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3595 xmldoc = xmlNewDoc(NULL);
3596 if(!xmldoc)
3597 return E_OUTOFMEMORY;
3599 xmldoc_init(xmldoc, version);
3601 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3602 if(FAILED(hr))
3604 free_properties(properties_from_xmlDocPtr(xmldoc));
3605 heap_free(xmldoc->_private);
3606 xmlFreeDoc(xmldoc);
3607 return hr;
3610 return hr;
3613 IUnknown* create_domdoc( xmlNodePtr document )
3615 void* pObj = NULL;
3616 HRESULT hr;
3618 TRACE("(%p)\n", document);
3620 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3621 if (FAILED(hr))
3622 return NULL;
3624 return pObj;
3627 #else
3629 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3631 MESSAGE("This program tried to use a DOMDocument object, but\n"
3632 "libxml2 support was not present at compile time.\n");
3633 return E_NOTIMPL;
3636 #endif