TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blobe9f2504a0ceba440bcbc75b83b210353b53a82bf
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
24 #include "config.h"
26 #include <stdarg.h>
27 #include <assert.h>
28 #ifdef HAVE_LIBXML2
29 # include <libxml/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/xpathInternals.h>
32 # include <libxml/xmlsave.h>
33 # include <libxml/SAX2.h>
34 # include <libxml/parserInternals.h>
35 #endif
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "winnls.h"
41 #include "ole2.h"
42 #include "olectl.h"
43 #include "msxml6.h"
44 #include "wininet.h"
45 #include "winreg.h"
46 #include "shlwapi.h"
47 #include "ocidl.h"
48 #include "objsafe.h"
50 #include "wine/debug.h"
52 #include "msxml_private.h"
54 #ifdef HAVE_LIBXML2
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 /* not defined in older versions */
59 #define XML_SAVE_FORMAT 1
60 #define XML_SAVE_NO_DECL 2
61 #define XML_SAVE_NO_EMPTY 4
62 #define XML_SAVE_NO_XHTML 8
63 #define XML_SAVE_XHTML 16
64 #define XML_SAVE_AS_XML 32
65 #define XML_SAVE_AS_HTML 64
67 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
68 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
69 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
70 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
71 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
72 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
73 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
75 /* Anything that passes the test_get_ownerDocument()
76 * tests can go here (data shared between all instances).
77 * We need to preserve this when reloading a document,
78 * and also need access to it from the libxml backend. */
79 typedef struct {
80 MSXML_VERSION version;
81 VARIANT_BOOL preserving;
82 IXMLDOMSchemaCollection2* schemaCache;
83 struct list selectNsList;
84 xmlChar const* selectNsStr;
85 LONG selectNsStr_len;
86 BOOL XPath;
87 WCHAR *url;
88 } domdoc_properties;
90 typedef struct ConnectionPoint ConnectionPoint;
91 typedef struct domdoc domdoc;
93 struct ConnectionPoint
95 IConnectionPoint IConnectionPoint_iface;
96 const IID *iid;
98 ConnectionPoint *next;
99 IConnectionPointContainer *container;
100 domdoc *doc;
102 union
104 IUnknown *unk;
105 IDispatch *disp;
106 IPropertyNotifySink *propnotif;
107 } *sinks;
108 DWORD sinks_size;
111 typedef enum {
112 EVENTID_READYSTATECHANGE = 0,
113 EVENTID_DATAAVAILABLE,
114 EVENTID_TRANSFORMNODE,
115 EVENTID_LAST
116 } eventid_t;
118 struct domdoc
120 xmlnode node;
121 IXMLDOMDocument3 IXMLDOMDocument3_iface;
122 IPersistStreamInit IPersistStreamInit_iface;
123 IObjectWithSite IObjectWithSite_iface;
124 IObjectSafety IObjectSafety_iface;
125 IConnectionPointContainer IConnectionPointContainer_iface;
126 LONG ref;
127 VARIANT_BOOL async;
128 VARIANT_BOOL validating;
129 VARIANT_BOOL resolving;
130 domdoc_properties* properties;
131 HRESULT error;
133 /* IObjectWithSite */
134 IUnknown *site;
136 /* IObjectSafety */
137 DWORD safeopt;
139 /* connection list */
140 ConnectionPoint *cp_list;
141 ConnectionPoint cp_domdocevents;
142 ConnectionPoint cp_propnotif;
143 ConnectionPoint cp_dispatch;
145 /* events */
146 IDispatch *events[EVENTID_LAST];
148 IXMLDOMSchemaCollection2 *namespaces;
151 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
153 IDispatch *disp;
155 switch (V_VT(v))
157 case VT_UNKNOWN:
158 if (V_UNKNOWN(v))
159 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
160 else
161 disp = NULL;
162 break;
163 case VT_DISPATCH:
164 disp = V_DISPATCH(v);
165 if (disp) IDispatch_AddRef(disp);
166 break;
167 default:
168 return DISP_E_TYPEMISMATCH;
171 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
172 doc->events[eid] = disp;
174 return S_OK;
177 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
179 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
183 In native windows, the whole lifetime management of XMLDOMNodes is
184 managed automatically using reference counts. Wine emulates that by
185 maintaining a reference count to the document that is increased for
186 each IXMLDOMNode pointer passed out for this document. If all these
187 pointers are gone, the document is unreachable and gets freed, that
188 is, all nodes in the tree of the document get freed.
190 You are able to create nodes that are associated to a document (in
191 fact, in msxml's XMLDOM model, all nodes are associated to a document),
192 but not in the tree of that document, for example using the createFoo
193 functions from IXMLDOMDocument. These nodes do not get cleaned up
194 by libxml, so we have to do it ourselves.
196 To catch these nodes, a list of "orphan nodes" is introduced.
197 It contains pointers to all roots of node trees that are
198 associated with the document without being part of the document
199 tree. All nodes with parent==NULL (except for the document root nodes)
200 should be in the orphan node list of their document. All orphan nodes
201 get freed together with the document itself.
204 typedef struct _xmldoc_priv {
205 LONG refs;
206 struct list orphans;
207 domdoc_properties* properties;
208 } xmldoc_priv;
210 typedef struct _orphan_entry {
211 struct list entry;
212 xmlNode * node;
213 } orphan_entry;
215 typedef struct _select_ns_entry {
216 struct list entry;
217 xmlChar const* prefix;
218 xmlChar prefix_end;
219 xmlChar const* href;
220 xmlChar href_end;
221 } select_ns_entry;
223 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
225 return doc->_private;
228 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
230 return priv_from_xmlDocPtr(doc)->properties;
233 BOOL is_xpathmode(const xmlDocPtr doc)
235 return properties_from_xmlDocPtr(doc)->XPath;
238 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
240 properties_from_xmlDocPtr(doc)->XPath = xpath;
243 int registerNamespaces(xmlXPathContextPtr ctxt)
245 int n = 0;
246 const select_ns_entry* ns = NULL;
247 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
249 TRACE("(%p)\n", ctxt);
251 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
253 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
254 ++n;
257 return n;
260 static inline void clear_selectNsList(struct list* pNsList)
262 select_ns_entry *ns, *ns2;
263 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
265 heap_free( ns );
267 list_init(pNsList);
270 static xmldoc_priv * create_priv(void)
272 xmldoc_priv *priv;
273 priv = heap_alloc( sizeof (*priv) );
275 if (priv)
277 priv->refs = 0;
278 list_init( &priv->orphans );
279 priv->properties = NULL;
282 return priv;
285 static domdoc_properties *create_properties(MSXML_VERSION version)
287 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
289 list_init(&properties->selectNsList);
290 properties->preserving = VARIANT_FALSE;
291 properties->schemaCache = NULL;
292 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
293 properties->selectNsStr_len = 0;
295 /* properties that are dependent on object versions */
296 properties->version = version;
297 properties->XPath = (version == MSXML4 || version == MSXML6);
299 /* document url */
300 properties->url = NULL;
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);
336 if (properties->url)
338 int len = strlenW(properties->url);
340 pcopy->url = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
341 memcpy(pcopy->url, properties->url, len*sizeof(WCHAR));
342 pcopy->url[len] = 0;
344 else
345 pcopy->url = NULL;
348 return pcopy;
351 static void free_properties(domdoc_properties* properties)
353 if (properties)
355 if (properties->schemaCache)
356 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
357 clear_selectNsList(&properties->selectNsList);
358 heap_free((xmlChar*)properties->selectNsStr);
359 CoTaskMemFree(properties->url);
360 heap_free(properties);
364 static void release_namespaces(domdoc *This)
366 if (This->namespaces)
368 IXMLDOMSchemaCollection2_Release(This->namespaces);
369 This->namespaces = NULL;
373 /* links a "<?xml" node as a first child */
374 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
376 assert(doc != NULL);
377 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
380 /* unlinks a first "<?xml" child if it was created */
381 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
383 static const xmlChar xmlA[] = "xml";
384 xmlNodePtr node, first_child;
386 assert(doc != NULL);
388 /* xml declaration node could be created automatically after parsing or added
389 to a tree later */
390 first_child = doc->children;
391 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
393 node = first_child;
394 xmlUnlinkNode( node );
396 else
397 node = NULL;
399 return node;
402 BOOL is_preserving_whitespace(xmlNodePtr node)
404 domdoc_properties* properties = NULL;
405 /* during parsing the xmlDoc._private stuff is not there */
406 if (priv_from_xmlDocPtr(node->doc))
407 properties = properties_from_xmlDocPtr(node->doc);
408 return ((properties && properties->preserving == VARIANT_TRUE) ||
409 xmlNodeGetSpacePreserve(node) == 1);
412 static inline BOOL strn_isspace(xmlChar const* str, int len)
414 for (; str && len > 0 && *str; ++str, --len)
415 if (!isspace(*str))
416 break;
418 return len == 0;
421 static void sax_characters(void *ctx, const xmlChar *ch, int len)
423 xmlParserCtxtPtr ctxt;
424 const domdoc *This;
426 ctxt = (xmlParserCtxtPtr) ctx;
427 This = (const domdoc*) ctxt->_private;
429 if (ctxt->node)
431 xmlChar cur = *(ctxt->input->cur);
433 /* Characters are reported with multiple calls, for example each charref is reported with a separate
434 call and then parser appends it to a single text node or creates a new node if not created.
435 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
436 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
437 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
438 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
439 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
440 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
441 a text node it's safe to ignore.
443 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
445 if (!This->properties->preserving &&
446 !is_preserving_whitespace(ctxt->node) &&
447 strn_isspace(ch, len) &&
448 (!ctxt->node->last ||
449 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
452 /* Keep information about ignorable whitespace text node in previous or parent node */
453 if (ctxt->node->last)
454 *(DWORD*)&ctxt->node->last->_private |= NODE_PRIV_TRAILING_IGNORABLE_WS;
455 else if (ctxt->node->type != XML_DOCUMENT_NODE)
456 *(DWORD*)&ctxt->node->_private |= NODE_PRIV_CHILD_IGNORABLE_WS;
457 return;
461 xmlSAX2Characters(ctxt, ch, len);
464 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
466 va_list ap;
467 va_start(ap, msg);
468 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
469 va_end(ap);
472 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
474 va_list ap;
475 va_start(ap, msg);
476 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
477 va_end(ap);
480 static void sax_serror(void* ctx, xmlErrorPtr err)
482 LIBXML2_CALLBACK_SERROR(doparse, err);
485 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
487 xmlDocPtr doc = NULL;
488 xmlParserCtxtPtr pctx;
489 static xmlSAXHandler sax_handler = {
490 xmlSAX2InternalSubset, /* internalSubset */
491 xmlSAX2IsStandalone, /* isStandalone */
492 xmlSAX2HasInternalSubset, /* hasInternalSubset */
493 xmlSAX2HasExternalSubset, /* hasExternalSubset */
494 xmlSAX2ResolveEntity, /* resolveEntity */
495 xmlSAX2GetEntity, /* getEntity */
496 xmlSAX2EntityDecl, /* entityDecl */
497 xmlSAX2NotationDecl, /* notationDecl */
498 xmlSAX2AttributeDecl, /* attributeDecl */
499 xmlSAX2ElementDecl, /* elementDecl */
500 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
501 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
502 xmlSAX2StartDocument, /* startDocument */
503 xmlSAX2EndDocument, /* endDocument */
504 xmlSAX2StartElement, /* startElement */
505 xmlSAX2EndElement, /* endElement */
506 xmlSAX2Reference, /* reference */
507 sax_characters, /* characters */
508 sax_characters, /* ignorableWhitespace */
509 xmlSAX2ProcessingInstruction, /* processingInstruction */
510 xmlSAX2Comment, /* comment */
511 sax_warning, /* warning */
512 sax_error, /* error */
513 sax_error, /* fatalError */
514 xmlSAX2GetParameterEntity, /* getParameterEntity */
515 xmlSAX2CDataBlock, /* cdataBlock */
516 xmlSAX2ExternalSubset, /* externalSubset */
517 0, /* initialized */
518 NULL, /* _private */
519 xmlSAX2StartElementNs, /* startElementNs */
520 xmlSAX2EndElementNs, /* endElementNs */
521 sax_serror /* serror */
524 pctx = xmlCreateMemoryParserCtxt(ptr, len);
525 if (!pctx)
527 ERR("Failed to create parser context\n");
528 return NULL;
531 if (pctx->sax) xmlFree(pctx->sax);
532 pctx->sax = &sax_handler;
533 pctx->_private = This;
534 pctx->recovery = 0;
536 if (encoding != XML_CHAR_ENCODING_NONE)
537 xmlSwitchEncoding(pctx, encoding);
539 xmlParseDocument(pctx);
541 if (pctx->wellFormed)
543 doc = pctx->myDoc;
545 else
547 xmlFreeDoc(pctx->myDoc);
548 pctx->myDoc = NULL;
550 pctx->sax = NULL;
551 xmlFreeParserCtxt(pctx);
553 /* TODO: put this in one of the SAX callbacks */
554 /* create first child as a <?xml...?> */
555 if (doc && doc->standalone != -1)
557 xmlNodePtr node;
558 char buff[30];
559 xmlChar *xmlbuff = (xmlChar*)buff;
561 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
563 /* version attribute can't be omitted */
564 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
565 xmlNodeAddContent( node, xmlbuff );
567 if (doc->encoding)
569 sprintf(buff, " encoding=\"%s\"", doc->encoding);
570 xmlNodeAddContent( node, xmlbuff );
573 if (doc->standalone != -2)
575 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
576 xmlNodeAddContent( node, xmlbuff );
579 xmldoc_link_xmldecl( doc, node );
582 return doc;
585 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
587 doc->_private = create_priv();
588 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
591 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
593 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
594 TRACE("(%p)->(%d)\n", doc, ref);
595 return ref;
598 LONG xmldoc_add_ref(xmlDocPtr doc)
600 return xmldoc_add_refs(doc, 1);
603 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
605 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
606 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
607 TRACE("(%p)->(%d)\n", doc, ref);
609 if (ref < 0)
610 WARN("negative refcount, expect troubles\n");
612 if (ref == 0)
614 orphan_entry *orphan, *orphan2;
615 TRACE("freeing docptr %p\n", doc);
617 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
619 xmlFreeNode( orphan->node );
620 heap_free( orphan );
622 free_properties(priv->properties);
623 heap_free(doc->_private);
625 xmlFreeDoc(doc);
628 return ref;
631 LONG xmldoc_release(xmlDocPtr doc)
633 return xmldoc_release_refs(doc, 1);
636 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
638 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
639 orphan_entry *entry;
641 entry = heap_alloc( sizeof (*entry) );
642 if(!entry)
643 return E_OUTOFMEMORY;
645 entry->node = node;
646 list_add_head( &priv->orphans, &entry->entry );
647 return S_OK;
650 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
652 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
653 orphan_entry *entry, *entry2;
655 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
657 if( entry->node == node )
659 list_remove( &entry->entry );
660 heap_free( entry );
661 return S_OK;
665 return S_FALSE;
668 static inline xmlDocPtr get_doc( domdoc *This )
670 return This->node.node->doc;
673 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
675 release_namespaces(This);
677 if(This->node.node)
679 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
680 if (xmldoc_release(get_doc(This)) != 0)
681 priv_from_xmlDocPtr(get_doc(This))->properties =
682 copy_properties(This->properties);
685 This->node.node = (xmlNodePtr) xml;
687 if(This->node.node)
689 xmldoc_add_ref(get_doc(This));
690 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
693 return S_OK;
696 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
698 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
701 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
703 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
706 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
708 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
711 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
713 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
716 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
718 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
721 /************************************************************************
722 * domdoc implementation of IPersistStream.
724 static HRESULT WINAPI PersistStreamInit_QueryInterface(
725 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
727 domdoc* This = impl_from_IPersistStreamInit(iface);
728 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
731 static ULONG WINAPI PersistStreamInit_AddRef(
732 IPersistStreamInit *iface)
734 domdoc* This = impl_from_IPersistStreamInit(iface);
735 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
738 static ULONG WINAPI PersistStreamInit_Release(
739 IPersistStreamInit *iface)
741 domdoc* This = impl_from_IPersistStreamInit(iface);
742 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
745 static HRESULT WINAPI PersistStreamInit_GetClassID(
746 IPersistStreamInit *iface, CLSID *classid)
748 domdoc* This = impl_from_IPersistStreamInit(iface);
749 TRACE("(%p)->(%p)\n", This, classid);
751 if(!classid)
752 return E_POINTER;
754 *classid = *DOMDocument_version(This->properties->version);
756 return S_OK;
759 static HRESULT WINAPI PersistStreamInit_IsDirty(
760 IPersistStreamInit *iface)
762 domdoc *This = impl_from_IPersistStreamInit(iface);
763 FIXME("(%p): stub!\n", This);
764 return S_FALSE;
767 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
769 DWORD read, written, len;
770 xmlDocPtr xmldoc = NULL;
771 IStream *hstream;
772 HGLOBAL hglobal;
773 BYTE buf[4096];
774 HRESULT hr;
775 char *ptr;
777 hstream = NULL;
778 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
779 if (FAILED(hr))
780 return hr;
784 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
785 hr = IStream_Write(hstream, buf, read, &written);
786 } while(SUCCEEDED(hr) && written != 0 && read != 0);
788 if (FAILED(hr))
790 ERR("failed to copy stream 0x%08x\n", hr);
791 IStream_Release(hstream);
792 return hr;
795 hr = GetHGlobalFromStream(hstream, &hglobal);
796 if (FAILED(hr))
797 return hr;
799 len = GlobalSize(hglobal);
800 ptr = GlobalLock(hglobal);
801 if (len)
802 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
803 GlobalUnlock(hglobal);
805 if (!xmldoc)
807 ERR("Failed to parse xml\n");
808 return E_FAIL;
811 xmldoc->_private = create_priv();
813 return attach_xmldoc(doc, xmldoc);
816 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
818 domdoc *This = impl_from_IPersistStreamInit(iface);
820 TRACE("(%p)->(%p)\n", This, stream);
822 if (!stream)
823 return E_INVALIDARG;
825 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
828 static HRESULT WINAPI PersistStreamInit_Save(
829 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
831 domdoc *This = impl_from_IPersistStreamInit(iface);
832 BSTR xmlString;
833 HRESULT hr;
835 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
837 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
838 if(hr == S_OK)
840 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
842 hr = IStream_Write( stream, xmlString, len, NULL );
843 SysFreeString(xmlString);
846 TRACE("ret 0x%08x\n", hr);
848 return hr;
851 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
852 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
854 domdoc *This = impl_from_IPersistStreamInit(iface);
855 TRACE("(%p)->(%p)\n", This, pcbSize);
856 return E_NOTIMPL;
859 static HRESULT WINAPI PersistStreamInit_InitNew(
860 IPersistStreamInit *iface)
862 domdoc *This = impl_from_IPersistStreamInit(iface);
863 TRACE("(%p)\n", This);
864 return S_OK;
867 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
869 PersistStreamInit_QueryInterface,
870 PersistStreamInit_AddRef,
871 PersistStreamInit_Release,
872 PersistStreamInit_GetClassID,
873 PersistStreamInit_IsDirty,
874 PersistStreamInit_Load,
875 PersistStreamInit_Save,
876 PersistStreamInit_GetSizeMax,
877 PersistStreamInit_InitNew
880 /* IXMLDOMDocument3 interface */
882 static const tid_t domdoc_se_tids[] = {
883 IXMLDOMNode_tid,
884 IXMLDOMDocument_tid,
885 IXMLDOMDocument2_tid,
886 IXMLDOMDocument3_tid,
887 NULL_tid
890 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
892 domdoc *This = impl_from_IXMLDOMDocument3( iface );
894 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
896 *ppvObject = NULL;
898 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
899 IsEqualGUID( riid, &IID_IDispatch ) ||
900 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
901 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
902 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
903 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
905 *ppvObject = iface;
907 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
908 IsEqualGUID(&IID_IPersistStreamInit, riid))
910 *ppvObject = &This->IPersistStreamInit_iface;
912 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
914 *ppvObject = &This->IObjectWithSite_iface;
916 else if (IsEqualGUID(&IID_IObjectSafety, riid))
918 *ppvObject = &This->IObjectSafety_iface;
920 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
922 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
924 else if(node_query_interface(&This->node, riid, ppvObject))
926 return *ppvObject ? S_OK : E_NOINTERFACE;
928 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
930 *ppvObject = &This->IConnectionPointContainer_iface;
932 else
934 TRACE("interface %s not implemented\n", debugstr_guid(riid));
935 return E_NOINTERFACE;
938 IUnknown_AddRef((IUnknown*)*ppvObject);
940 return S_OK;
943 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
945 domdoc *This = impl_from_IXMLDOMDocument3( iface );
946 ULONG ref = InterlockedIncrement( &This->ref );
947 TRACE("(%p)->(%d)\n", This, ref );
948 return ref;
951 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
953 domdoc *This = impl_from_IXMLDOMDocument3( iface );
954 LONG ref = InterlockedDecrement( &This->ref );
956 TRACE("(%p)->(%d)\n", This, ref );
958 if ( ref == 0 )
960 int eid;
962 if (This->site)
963 IUnknown_Release( This->site );
964 destroy_xmlnode(&This->node);
966 for (eid = 0; eid < EVENTID_LAST; eid++)
967 if (This->events[eid]) IDispatch_Release(This->events[eid]);
969 release_namespaces(This);
970 heap_free(This);
973 return ref;
976 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
978 domdoc *This = impl_from_IXMLDOMDocument3( iface );
979 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
982 static HRESULT WINAPI domdoc_GetTypeInfo(
983 IXMLDOMDocument3 *iface,
984 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
986 domdoc *This = impl_from_IXMLDOMDocument3( iface );
987 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
990 static HRESULT WINAPI domdoc_GetIDsOfNames(
991 IXMLDOMDocument3 *iface,
992 REFIID riid,
993 LPOLESTR* rgszNames,
994 UINT cNames,
995 LCID lcid,
996 DISPID* rgDispId)
998 domdoc *This = impl_from_IXMLDOMDocument3( iface );
999 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
1000 riid, rgszNames, cNames, lcid, rgDispId);
1003 static HRESULT WINAPI domdoc_Invoke(
1004 IXMLDOMDocument3 *iface,
1005 DISPID dispIdMember,
1006 REFIID riid,
1007 LCID lcid,
1008 WORD wFlags,
1009 DISPPARAMS* pDispParams,
1010 VARIANT* pVarResult,
1011 EXCEPINFO* pExcepInfo,
1012 UINT* puArgErr)
1014 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1015 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1016 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1019 static HRESULT WINAPI domdoc_get_nodeName(
1020 IXMLDOMDocument3 *iface,
1021 BSTR* name )
1023 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1025 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1027 TRACE("(%p)->(%p)\n", This, name);
1029 return return_bstr(documentW, name);
1033 static HRESULT WINAPI domdoc_get_nodeValue(
1034 IXMLDOMDocument3 *iface,
1035 VARIANT* value )
1037 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1039 TRACE("(%p)->(%p)\n", This, value);
1041 if(!value)
1042 return E_INVALIDARG;
1044 V_VT(value) = VT_NULL;
1045 V_BSTR(value) = NULL; /* tests show that we should do this */
1046 return S_FALSE;
1050 static HRESULT WINAPI domdoc_put_nodeValue(
1051 IXMLDOMDocument3 *iface,
1052 VARIANT value)
1054 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1055 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1056 return E_FAIL;
1060 static HRESULT WINAPI domdoc_get_nodeType(
1061 IXMLDOMDocument3 *iface,
1062 DOMNodeType* type )
1064 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1066 TRACE("(%p)->(%p)\n", This, type);
1068 *type = NODE_DOCUMENT;
1069 return S_OK;
1073 static HRESULT WINAPI domdoc_get_parentNode(
1074 IXMLDOMDocument3 *iface,
1075 IXMLDOMNode** parent )
1077 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1079 TRACE("(%p)->(%p)\n", This, parent);
1081 return node_get_parent(&This->node, parent);
1085 static HRESULT WINAPI domdoc_get_childNodes(
1086 IXMLDOMDocument3 *iface,
1087 IXMLDOMNodeList** childList )
1089 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1091 TRACE("(%p)->(%p)\n", This, childList);
1093 return node_get_child_nodes(&This->node, childList);
1097 static HRESULT WINAPI domdoc_get_firstChild(
1098 IXMLDOMDocument3 *iface,
1099 IXMLDOMNode** firstChild )
1101 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1103 TRACE("(%p)->(%p)\n", This, firstChild);
1105 return node_get_first_child(&This->node, firstChild);
1109 static HRESULT WINAPI domdoc_get_lastChild(
1110 IXMLDOMDocument3 *iface,
1111 IXMLDOMNode** lastChild )
1113 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1115 TRACE("(%p)->(%p)\n", This, lastChild);
1117 return node_get_last_child(&This->node, lastChild);
1121 static HRESULT WINAPI domdoc_get_previousSibling(
1122 IXMLDOMDocument3 *iface,
1123 IXMLDOMNode** previousSibling )
1125 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1127 TRACE("(%p)->(%p)\n", This, previousSibling);
1129 return return_null_node(previousSibling);
1133 static HRESULT WINAPI domdoc_get_nextSibling(
1134 IXMLDOMDocument3 *iface,
1135 IXMLDOMNode** nextSibling )
1137 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1139 TRACE("(%p)->(%p)\n", This, nextSibling);
1141 return return_null_node(nextSibling);
1145 static HRESULT WINAPI domdoc_get_attributes(
1146 IXMLDOMDocument3 *iface,
1147 IXMLDOMNamedNodeMap** attributeMap )
1149 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1151 TRACE("(%p)->(%p)\n", This, attributeMap);
1153 return return_null_ptr((void**)attributeMap);
1157 static HRESULT WINAPI domdoc_insertBefore(
1158 IXMLDOMDocument3 *iface,
1159 IXMLDOMNode* newChild,
1160 VARIANT refChild,
1161 IXMLDOMNode** outNewChild )
1163 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1164 DOMNodeType type;
1165 HRESULT hr;
1167 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1169 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1170 if (hr != S_OK) return hr;
1172 TRACE("new node type %d\n", type);
1173 switch (type)
1175 case NODE_ATTRIBUTE:
1176 case NODE_DOCUMENT:
1177 case NODE_CDATA_SECTION:
1178 if (outNewChild) *outNewChild = NULL;
1179 return E_FAIL;
1180 default:
1181 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1185 static HRESULT WINAPI domdoc_replaceChild(
1186 IXMLDOMDocument3 *iface,
1187 IXMLDOMNode* newChild,
1188 IXMLDOMNode* oldChild,
1189 IXMLDOMNode** outOldChild)
1191 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1193 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1195 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1199 static HRESULT WINAPI domdoc_removeChild(
1200 IXMLDOMDocument3 *iface,
1201 IXMLDOMNode *child,
1202 IXMLDOMNode **oldChild)
1204 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1205 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1206 return node_remove_child(&This->node, child, oldChild);
1210 static HRESULT WINAPI domdoc_appendChild(
1211 IXMLDOMDocument3 *iface,
1212 IXMLDOMNode *child,
1213 IXMLDOMNode **outChild)
1215 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1216 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1217 return node_append_child(&This->node, child, outChild);
1221 static HRESULT WINAPI domdoc_hasChildNodes(
1222 IXMLDOMDocument3 *iface,
1223 VARIANT_BOOL *ret)
1225 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1226 TRACE("(%p)->(%p)\n", This, ret);
1227 return node_has_childnodes(&This->node, ret);
1231 static HRESULT WINAPI domdoc_get_ownerDocument(
1232 IXMLDOMDocument3 *iface,
1233 IXMLDOMDocument **doc)
1235 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1236 TRACE("(%p)->(%p)\n", This, doc);
1237 return node_get_owner_doc(&This->node, doc);
1241 static HRESULT WINAPI domdoc_cloneNode(
1242 IXMLDOMDocument3 *iface,
1243 VARIANT_BOOL deep,
1244 IXMLDOMNode** outNode)
1246 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1247 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1248 return node_clone( &This->node, deep, outNode );
1252 static HRESULT WINAPI domdoc_get_nodeTypeString(
1253 IXMLDOMDocument3 *iface,
1254 BSTR *p)
1256 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1257 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1259 TRACE("(%p)->(%p)\n", This, p);
1261 return return_bstr(documentW, p);
1265 static HRESULT WINAPI domdoc_get_text(
1266 IXMLDOMDocument3 *iface,
1267 BSTR *p)
1269 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1270 TRACE("(%p)->(%p)\n", This, p);
1271 return node_get_text(&This->node, p);
1275 static HRESULT WINAPI domdoc_put_text(
1276 IXMLDOMDocument3 *iface,
1277 BSTR text )
1279 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1280 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1281 return E_FAIL;
1285 static HRESULT WINAPI domdoc_get_specified(
1286 IXMLDOMDocument3 *iface,
1287 VARIANT_BOOL* isSpecified )
1289 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1290 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1291 *isSpecified = VARIANT_TRUE;
1292 return S_OK;
1296 static HRESULT WINAPI domdoc_get_definition(
1297 IXMLDOMDocument3 *iface,
1298 IXMLDOMNode** definitionNode )
1300 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1301 FIXME("(%p)->(%p)\n", This, definitionNode);
1302 return E_NOTIMPL;
1306 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1307 IXMLDOMDocument3 *iface,
1308 VARIANT* v )
1310 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1311 TRACE("(%p)->(%p)\n", This, v);
1312 return return_null_var(v);
1315 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1316 IXMLDOMDocument3 *iface,
1317 VARIANT typedValue )
1319 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1320 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1321 return E_NOTIMPL;
1325 static HRESULT WINAPI domdoc_get_dataType(
1326 IXMLDOMDocument3 *iface,
1327 VARIANT* typename )
1329 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1330 TRACE("(%p)->(%p)\n", This, typename);
1331 return return_null_var( typename );
1335 static HRESULT WINAPI domdoc_put_dataType(
1336 IXMLDOMDocument3 *iface,
1337 BSTR dataTypeName )
1339 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1341 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1343 if(!dataTypeName)
1344 return E_INVALIDARG;
1346 return E_FAIL;
1349 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1351 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1354 static HRESULT WINAPI domdoc_get_xml(
1355 IXMLDOMDocument3 *iface,
1356 BSTR* p)
1358 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1359 xmlSaveCtxtPtr ctxt;
1360 xmlBufferPtr buf;
1361 int options;
1362 long ret;
1364 TRACE("(%p)->(%p)\n", This, p);
1366 if(!p)
1367 return E_INVALIDARG;
1369 *p = NULL;
1371 buf = xmlBufferCreate();
1372 if(!buf)
1373 return E_OUTOFMEMORY;
1375 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1376 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1378 if(!ctxt)
1380 xmlBufferFree(buf);
1381 return E_OUTOFMEMORY;
1384 ret = xmlSaveDoc(ctxt, get_doc(This));
1385 /* flushes on close */
1386 xmlSaveClose(ctxt);
1388 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1389 if(ret != -1 && xmlBufferLength(buf) > 0)
1391 BSTR content;
1393 content = bstr_from_xmlChar(xmlBufferContent(buf));
1394 content = EnsureCorrectEOL(content);
1396 *p = content;
1398 else
1400 *p = SysAllocStringLen(NULL, 0);
1403 xmlBufferFree(buf);
1405 return *p ? S_OK : E_OUTOFMEMORY;
1409 static HRESULT WINAPI domdoc_transformNode(
1410 IXMLDOMDocument3 *iface,
1411 IXMLDOMNode *node,
1412 BSTR *p)
1414 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1415 TRACE("(%p)->(%p %p)\n", This, node, p);
1416 return node_transform_node(&This->node, node, p);
1420 static HRESULT WINAPI domdoc_selectNodes(
1421 IXMLDOMDocument3 *iface,
1422 BSTR p,
1423 IXMLDOMNodeList **outList)
1425 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1426 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1427 return node_select_nodes(&This->node, p, outList);
1431 static HRESULT WINAPI domdoc_selectSingleNode(
1432 IXMLDOMDocument3 *iface,
1433 BSTR p,
1434 IXMLDOMNode **outNode)
1436 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1437 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1438 return node_select_singlenode(&This->node, p, outNode);
1442 static HRESULT WINAPI domdoc_get_parsed(
1443 IXMLDOMDocument3 *iface,
1444 VARIANT_BOOL* isParsed )
1446 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1447 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1448 *isParsed = VARIANT_TRUE;
1449 return S_OK;
1452 static HRESULT WINAPI domdoc_get_namespaceURI(
1453 IXMLDOMDocument3 *iface,
1454 BSTR* namespaceURI )
1456 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1457 TRACE("(%p)->(%p)\n", This, namespaceURI);
1458 return return_null_bstr( namespaceURI );
1461 static HRESULT WINAPI domdoc_get_prefix(
1462 IXMLDOMDocument3 *iface,
1463 BSTR* prefix )
1465 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1466 TRACE("(%p)->(%p)\n", This, prefix);
1467 return return_null_bstr( prefix );
1471 static HRESULT WINAPI domdoc_get_baseName(
1472 IXMLDOMDocument3 *iface,
1473 BSTR* name )
1475 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1476 TRACE("(%p)->(%p)\n", This, name);
1477 return return_null_bstr( name );
1481 static HRESULT WINAPI domdoc_transformNodeToObject(
1482 IXMLDOMDocument3 *iface,
1483 IXMLDOMNode* stylesheet,
1484 VARIANT outputObject)
1486 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1487 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1488 return E_NOTIMPL;
1492 static HRESULT WINAPI domdoc_get_doctype(
1493 IXMLDOMDocument3 *iface,
1494 IXMLDOMDocumentType** doctype )
1496 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1497 IXMLDOMNode *node;
1498 xmlDtdPtr dtd;
1499 HRESULT hr;
1501 TRACE("(%p)->(%p)\n", This, doctype);
1503 if (!doctype) return E_INVALIDARG;
1505 *doctype = NULL;
1507 dtd = xmlGetIntSubset(get_doc(This));
1508 if (!dtd) return S_FALSE;
1510 node = create_node((xmlNodePtr)dtd);
1511 if (!node) return S_FALSE;
1513 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1514 IXMLDOMNode_Release(node);
1516 return hr;
1520 static HRESULT WINAPI domdoc_get_implementation(
1521 IXMLDOMDocument3 *iface,
1522 IXMLDOMImplementation** impl )
1524 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1526 TRACE("(%p)->(%p)\n", This, impl);
1528 if(!impl)
1529 return E_INVALIDARG;
1531 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1533 return S_OK;
1536 static HRESULT WINAPI domdoc_get_documentElement(
1537 IXMLDOMDocument3 *iface,
1538 IXMLDOMElement** DOMElement )
1540 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1541 IXMLDOMNode *element_node;
1542 xmlNodePtr root;
1543 HRESULT hr;
1545 TRACE("(%p)->(%p)\n", This, DOMElement);
1547 if(!DOMElement)
1548 return E_INVALIDARG;
1550 *DOMElement = NULL;
1552 root = xmlDocGetRootElement( get_doc(This) );
1553 if ( !root )
1554 return S_FALSE;
1556 element_node = create_node( root );
1557 if(!element_node) return S_FALSE;
1559 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1560 IXMLDOMNode_Release(element_node);
1562 return hr;
1566 static HRESULT WINAPI domdoc_put_documentElement(
1567 IXMLDOMDocument3 *iface,
1568 IXMLDOMElement* DOMElement )
1570 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1571 IXMLDOMNode *elementNode;
1572 xmlNodePtr oldRoot;
1573 xmlDocPtr old_doc;
1574 xmlnode *xmlNode;
1575 int refcount = 0;
1576 HRESULT hr;
1578 TRACE("(%p)->(%p)\n", This, DOMElement);
1580 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1581 if(FAILED(hr))
1582 return hr;
1584 xmlNode = get_node_obj( elementNode );
1585 if(!xmlNode) return E_FAIL;
1587 if(!xmlNode->node->parent)
1588 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1589 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1591 old_doc = xmlNode->node->doc;
1592 if (old_doc != get_doc(This))
1593 refcount = xmlnode_get_inst_cnt(xmlNode);
1595 /* old root is still orphaned by its document, update refcount from new root */
1596 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1597 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1598 if (refcount) xmldoc_release_refs(old_doc, refcount);
1599 IXMLDOMNode_Release( elementNode );
1601 if(oldRoot)
1602 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1604 return S_OK;
1608 static HRESULT WINAPI domdoc_createElement(
1609 IXMLDOMDocument3 *iface,
1610 BSTR tagname,
1611 IXMLDOMElement** element )
1613 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1614 IXMLDOMNode *node;
1615 VARIANT type;
1616 HRESULT hr;
1618 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1620 if (!element || !tagname) return E_INVALIDARG;
1622 V_VT(&type) = VT_I1;
1623 V_I1(&type) = NODE_ELEMENT;
1625 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1626 if (hr == S_OK)
1628 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1629 IXMLDOMNode_Release(node);
1632 return hr;
1636 static HRESULT WINAPI domdoc_createDocumentFragment(
1637 IXMLDOMDocument3 *iface,
1638 IXMLDOMDocumentFragment** frag )
1640 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1641 IXMLDOMNode *node;
1642 VARIANT type;
1643 HRESULT hr;
1645 TRACE("(%p)->(%p)\n", This, frag);
1647 if (!frag) return E_INVALIDARG;
1649 *frag = NULL;
1651 V_VT(&type) = VT_I1;
1652 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1654 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1655 if (hr == S_OK)
1657 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1658 IXMLDOMNode_Release(node);
1661 return hr;
1665 static HRESULT WINAPI domdoc_createTextNode(
1666 IXMLDOMDocument3 *iface,
1667 BSTR data,
1668 IXMLDOMText** text )
1670 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1671 IXMLDOMNode *node;
1672 VARIANT type;
1673 HRESULT hr;
1675 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1677 if (!text) return E_INVALIDARG;
1679 *text = NULL;
1681 V_VT(&type) = VT_I1;
1682 V_I1(&type) = NODE_TEXT;
1684 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1685 if (hr == S_OK)
1687 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1688 IXMLDOMNode_Release(node);
1689 hr = IXMLDOMText_put_data(*text, data);
1692 return hr;
1696 static HRESULT WINAPI domdoc_createComment(
1697 IXMLDOMDocument3 *iface,
1698 BSTR data,
1699 IXMLDOMComment** comment )
1701 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1702 VARIANT type;
1703 HRESULT hr;
1704 IXMLDOMNode *node;
1706 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1708 if (!comment) return E_INVALIDARG;
1710 *comment = NULL;
1712 V_VT(&type) = VT_I1;
1713 V_I1(&type) = NODE_COMMENT;
1715 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1716 if (hr == S_OK)
1718 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1719 IXMLDOMNode_Release(node);
1720 hr = IXMLDOMComment_put_data(*comment, data);
1723 return hr;
1727 static HRESULT WINAPI domdoc_createCDATASection(
1728 IXMLDOMDocument3 *iface,
1729 BSTR data,
1730 IXMLDOMCDATASection** cdata )
1732 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1733 IXMLDOMNode *node;
1734 VARIANT type;
1735 HRESULT hr;
1737 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1739 if (!cdata) return E_INVALIDARG;
1741 *cdata = NULL;
1743 V_VT(&type) = VT_I1;
1744 V_I1(&type) = NODE_CDATA_SECTION;
1746 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1747 if (hr == S_OK)
1749 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1750 IXMLDOMNode_Release(node);
1751 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1754 return hr;
1758 static HRESULT WINAPI domdoc_createProcessingInstruction(
1759 IXMLDOMDocument3 *iface,
1760 BSTR target,
1761 BSTR data,
1762 IXMLDOMProcessingInstruction** pi )
1764 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1765 IXMLDOMNode *node;
1766 VARIANT type;
1767 HRESULT hr;
1769 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1771 if (!pi) return E_INVALIDARG;
1773 *pi = NULL;
1775 V_VT(&type) = VT_I1;
1776 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1778 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1779 if (hr == S_OK)
1781 xmlnode *node_obj;
1783 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1784 node_obj = get_node_obj(node);
1785 hr = node_set_content(node_obj, data);
1787 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1788 IXMLDOMNode_Release(node);
1791 return hr;
1795 static HRESULT WINAPI domdoc_createAttribute(
1796 IXMLDOMDocument3 *iface,
1797 BSTR name,
1798 IXMLDOMAttribute** attribute )
1800 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1801 IXMLDOMNode *node;
1802 VARIANT type;
1803 HRESULT hr;
1805 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1807 if (!attribute || !name) return E_INVALIDARG;
1809 V_VT(&type) = VT_I1;
1810 V_I1(&type) = NODE_ATTRIBUTE;
1812 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1813 if (hr == S_OK)
1815 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1816 IXMLDOMNode_Release(node);
1819 return hr;
1823 static HRESULT WINAPI domdoc_createEntityReference(
1824 IXMLDOMDocument3 *iface,
1825 BSTR name,
1826 IXMLDOMEntityReference** entityref )
1828 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1829 IXMLDOMNode *node;
1830 VARIANT type;
1831 HRESULT hr;
1833 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1835 if (!entityref) return E_INVALIDARG;
1837 *entityref = NULL;
1839 V_VT(&type) = VT_I1;
1840 V_I1(&type) = NODE_ENTITY_REFERENCE;
1842 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1843 if (hr == S_OK)
1845 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1846 IXMLDOMNode_Release(node);
1849 return hr;
1852 xmlChar* tagName_to_XPath(const BSTR tagName)
1854 xmlChar *query, *tmp;
1855 static const xmlChar everything[] = "/descendant::node()";
1856 static const xmlChar mod_pre[] = "*[local-name()='";
1857 static const xmlChar mod_post[] = "']";
1858 static const xmlChar prefix[] = "descendant::";
1859 const WCHAR *tokBegin, *tokEnd;
1860 int len;
1862 /* Special case - empty tagname - means select all nodes,
1863 except document itself. */
1864 if (!*tagName)
1865 return xmlStrdup(everything);
1867 query = xmlStrdup(prefix);
1869 tokBegin = tagName;
1870 while (tokBegin && *tokBegin)
1872 switch (*tokBegin)
1874 case '/':
1875 query = xmlStrcat(query, BAD_CAST "/");
1876 ++tokBegin;
1877 break;
1878 case '*':
1879 query = xmlStrcat(query, BAD_CAST "*");
1880 ++tokBegin;
1881 break;
1882 default:
1883 query = xmlStrcat(query, mod_pre);
1884 tokEnd = tokBegin;
1885 while (*tokEnd && *tokEnd != '/')
1886 ++tokEnd;
1887 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1888 tmp = xmlMalloc(len);
1889 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1890 query = xmlStrncat(query, tmp, len);
1891 xmlFree(tmp);
1892 tokBegin = tokEnd;
1893 query = xmlStrcat(query, mod_post);
1897 return query;
1900 static HRESULT WINAPI domdoc_getElementsByTagName(
1901 IXMLDOMDocument3 *iface,
1902 BSTR tagName,
1903 IXMLDOMNodeList** resultList )
1905 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1906 xmlChar *query;
1907 HRESULT hr;
1908 BOOL XPath;
1910 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1912 if (!tagName || !resultList) return E_INVALIDARG;
1914 XPath = This->properties->XPath;
1915 This->properties->XPath = TRUE;
1916 query = tagName_to_XPath(tagName);
1917 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1918 xmlFree(query);
1919 This->properties->XPath = XPath;
1921 return hr;
1924 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1926 VARIANT tmp;
1927 HRESULT hr;
1929 VariantInit(&tmp);
1930 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1931 if(FAILED(hr))
1932 return E_INVALIDARG;
1934 *type = V_I4(&tmp);
1936 return S_OK;
1939 static HRESULT WINAPI domdoc_createNode(
1940 IXMLDOMDocument3 *iface,
1941 VARIANT Type,
1942 BSTR name,
1943 BSTR namespaceURI,
1944 IXMLDOMNode** node )
1946 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1947 DOMNodeType node_type;
1948 xmlNodePtr xmlnode;
1949 xmlChar *xml_name, *href;
1950 HRESULT hr;
1952 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1954 if(!node) return E_INVALIDARG;
1956 hr = get_node_type(Type, &node_type);
1957 if(FAILED(hr)) return hr;
1959 TRACE("node_type %d\n", node_type);
1961 /* exit earlier for types that need name */
1962 switch(node_type)
1964 case NODE_ELEMENT:
1965 case NODE_ATTRIBUTE:
1966 case NODE_ENTITY_REFERENCE:
1967 case NODE_PROCESSING_INSTRUCTION:
1968 if (!name || *name == 0) return E_FAIL;
1969 break;
1970 default:
1971 break;
1974 xml_name = xmlchar_from_wchar(name);
1975 /* prevent empty href from being allocated */
1976 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1978 switch(node_type)
1980 case NODE_ELEMENT:
1982 xmlChar *local, *prefix;
1984 local = xmlSplitQName2(xml_name, &prefix);
1986 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1988 /* allow creating the default namespace xmlns= */
1989 if (local || (href && *href))
1991 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1992 xmlSetNs(xmlnode, ns);
1995 xmlFree(local);
1996 xmlFree(prefix);
1998 break;
2000 case NODE_ATTRIBUTE:
2002 xmlChar *local, *prefix;
2004 local = xmlSplitQName2(xml_name, &prefix);
2006 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2008 if (local || (href && *href))
2010 /* we need a floating namespace here, it can't be created linked to attribute from
2011 a start */
2012 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2013 xmlSetNs(xmlnode, ns);
2016 xmlFree(local);
2017 xmlFree(prefix);
2019 break;
2021 case NODE_TEXT:
2022 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2023 break;
2024 case NODE_CDATA_SECTION:
2025 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2026 break;
2027 case NODE_ENTITY_REFERENCE:
2028 xmlnode = xmlNewReference(get_doc(This), xml_name);
2029 break;
2030 case NODE_PROCESSING_INSTRUCTION:
2031 #ifdef HAVE_XMLNEWDOCPI
2032 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2033 #else
2034 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2035 xmlnode = NULL;
2036 #endif
2037 break;
2038 case NODE_COMMENT:
2039 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2040 break;
2041 case NODE_DOCUMENT_FRAGMENT:
2042 xmlnode = xmlNewDocFragment(get_doc(This));
2043 break;
2044 /* unsupported types */
2045 case NODE_DOCUMENT:
2046 case NODE_DOCUMENT_TYPE:
2047 case NODE_ENTITY:
2048 case NODE_NOTATION:
2049 heap_free(xml_name);
2050 return E_INVALIDARG;
2051 default:
2052 FIXME("unhandled node type %d\n", node_type);
2053 xmlnode = NULL;
2054 break;
2057 *node = create_node(xmlnode);
2058 heap_free(xml_name);
2059 heap_free(href);
2061 if(*node)
2063 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2064 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2065 return S_OK;
2068 return E_FAIL;
2071 static HRESULT WINAPI domdoc_nodeFromID(
2072 IXMLDOMDocument3 *iface,
2073 BSTR idString,
2074 IXMLDOMNode** node )
2076 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2077 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2078 return E_NOTIMPL;
2081 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2083 domdoc *This = obj;
2084 xmlDocPtr xmldoc;
2086 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2087 if(xmldoc) {
2088 xmldoc->_private = create_priv();
2089 return attach_xmldoc(This, xmldoc);
2092 return E_FAIL;
2095 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2097 bsc_t *bsc;
2098 HRESULT hr;
2100 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2101 if(FAILED(hr))
2102 return hr;
2104 return detach_bsc(bsc);
2107 static HRESULT WINAPI domdoc_load(
2108 IXMLDOMDocument3 *iface,
2109 VARIANT source,
2110 VARIANT_BOOL* isSuccessful )
2112 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2113 LPWSTR filename = NULL;
2114 HRESULT hr = S_FALSE;
2115 xmlDocPtr xmldoc;
2117 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2119 if (!isSuccessful)
2120 return E_POINTER;
2121 *isSuccessful = VARIANT_FALSE;
2123 assert( &This->node );
2125 switch( V_VT(&source) )
2127 case VT_BSTR:
2128 filename = V_BSTR(&source);
2129 break;
2130 case VT_BSTR|VT_BYREF:
2131 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2132 filename = *V_BSTRREF(&source);
2133 break;
2134 case VT_ARRAY|VT_UI1:
2136 SAFEARRAY *psa = V_ARRAY(&source);
2137 char *str;
2138 LONG len;
2139 UINT dim = SafeArrayGetDim(psa);
2141 switch (dim)
2143 case 0:
2144 ERR("SAFEARRAY == NULL\n");
2145 hr = This->error = E_INVALIDARG;
2146 break;
2147 case 1:
2148 /* Only takes UTF-8 strings.
2149 * NOT NULL-terminated. */
2150 hr = SafeArrayAccessData(psa, (void**)&str);
2151 if (FAILED(hr))
2153 This->error = hr;
2154 WARN("failed to access array data, 0x%08x\n", hr);
2155 break;
2157 SafeArrayGetUBound(psa, 1, &len);
2159 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2161 hr = This->error = S_OK;
2162 *isSuccessful = VARIANT_TRUE;
2163 TRACE("parsed document %p\n", xmldoc);
2165 else
2167 This->error = E_FAIL;
2168 TRACE("failed to parse document\n");
2171 SafeArrayUnaccessData(psa);
2173 if(xmldoc)
2175 xmldoc->_private = create_priv();
2176 return attach_xmldoc(This, xmldoc);
2178 break;
2179 default:
2180 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2181 hr = This->error = E_NOTIMPL;
2184 break;
2185 case VT_UNKNOWN:
2187 ISequentialStream *stream = NULL;
2188 IXMLDOMDocument3 *newdoc = NULL;
2190 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2192 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2193 if(hr == S_OK)
2195 if(newdoc)
2197 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2199 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2200 xmldoc->_private = create_priv();
2201 hr = attach_xmldoc(This, xmldoc);
2203 if(SUCCEEDED(hr))
2204 *isSuccessful = VARIANT_TRUE;
2206 return hr;
2210 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2211 if (FAILED(hr))
2212 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2214 if (hr == S_OK)
2216 hr = domdoc_load_from_stream(This, stream);
2217 if (hr == S_OK)
2218 *isSuccessful = VARIANT_TRUE;
2219 ISequentialStream_Release(stream);
2220 return hr;
2223 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2224 break;
2226 default:
2227 FIXME("VT type not supported (%d)\n", V_VT(&source));
2230 if ( filename )
2232 IMoniker *mon;
2234 CoTaskMemFree(This->properties->url);
2235 This->properties->url = NULL;
2237 hr = create_moniker_from_url( filename, &mon);
2238 if ( SUCCEEDED(hr) )
2240 hr = domdoc_load_moniker( This, mon );
2241 if (hr == S_OK)
2242 IMoniker_GetDisplayName(mon, NULL, NULL, &This->properties->url);
2243 IMoniker_Release(mon);
2246 if ( FAILED(hr) )
2247 This->error = E_FAIL;
2248 else
2250 hr = This->error = S_OK;
2251 *isSuccessful = VARIANT_TRUE;
2255 if(!filename || FAILED(hr)) {
2256 xmldoc = xmlNewDoc(NULL);
2257 xmldoc->_private = create_priv();
2258 hr = attach_xmldoc(This, xmldoc);
2259 if(SUCCEEDED(hr))
2260 hr = S_FALSE;
2263 TRACE("ret (%d)\n", hr);
2265 return hr;
2269 static HRESULT WINAPI domdoc_get_readyState(
2270 IXMLDOMDocument3 *iface,
2271 LONG *value )
2273 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2274 FIXME("stub! (%p)->(%p)\n", This, value);
2276 if (!value)
2277 return E_INVALIDARG;
2279 *value = READYSTATE_COMPLETE;
2280 return S_OK;
2284 static HRESULT WINAPI domdoc_get_parseError(
2285 IXMLDOMDocument3 *iface,
2286 IXMLDOMParseError** errorObj )
2288 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2289 static const WCHAR err[] = {'e','r','r','o','r',0};
2290 BSTR error_string = NULL;
2292 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2294 if(This->error)
2295 error_string = SysAllocString(err);
2297 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2298 if(!*errorObj) return E_OUTOFMEMORY;
2299 return S_OK;
2303 static HRESULT WINAPI domdoc_get_url(
2304 IXMLDOMDocument3 *iface,
2305 BSTR* url )
2307 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2309 TRACE("(%p)->(%p)\n", This, url);
2311 if (!url)
2312 return E_INVALIDARG;
2314 if (This->properties->url)
2316 *url = SysAllocString(This->properties->url);
2317 if (!*url)
2318 return E_OUTOFMEMORY;
2320 return S_OK;
2322 else
2323 return return_null_bstr(url);
2327 static HRESULT WINAPI domdoc_get_async(
2328 IXMLDOMDocument3 *iface,
2329 VARIANT_BOOL* isAsync )
2331 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2333 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2334 *isAsync = This->async;
2335 return S_OK;
2339 static HRESULT WINAPI domdoc_put_async(
2340 IXMLDOMDocument3 *iface,
2341 VARIANT_BOOL isAsync )
2343 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2345 TRACE("(%p)->(%d)\n", This, isAsync);
2346 This->async = isAsync;
2347 return S_OK;
2351 static HRESULT WINAPI domdoc_abort(
2352 IXMLDOMDocument3 *iface )
2354 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2355 FIXME("%p\n", This);
2356 return E_NOTIMPL;
2359 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2360 static HRESULT WINAPI domdoc_loadXML(
2361 IXMLDOMDocument3 *iface,
2362 BSTR data,
2363 VARIANT_BOOL* isSuccessful )
2365 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2366 xmlDocPtr xmldoc = NULL;
2367 HRESULT hr = S_FALSE, hr2;
2369 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2371 assert ( &This->node );
2373 if ( isSuccessful )
2375 *isSuccessful = VARIANT_FALSE;
2377 if (data)
2379 WCHAR *ptr = data;
2381 /* skip leading spaces if needed */
2382 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2383 while (*ptr && isspaceW(*ptr)) ptr++;
2385 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2386 if ( !xmldoc )
2388 This->error = E_FAIL;
2389 TRACE("failed to parse document\n");
2391 else
2393 hr = This->error = S_OK;
2394 *isSuccessful = VARIANT_TRUE;
2395 TRACE("parsed document %p\n", xmldoc);
2400 if(!xmldoc)
2401 xmldoc = xmlNewDoc(NULL);
2402 xmldoc->_private = create_priv();
2403 hr2 = attach_xmldoc(This, xmldoc);
2404 if( FAILED(hr2) )
2405 hr = hr2;
2407 return hr;
2410 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2412 DWORD written = -1;
2414 if(!WriteFile(ctx, buffer, len, &written, NULL))
2416 WARN("write error\n");
2417 return -1;
2419 else
2420 return written;
2423 static int XMLCALL domdoc_save_closecallback(void *ctx)
2425 return CloseHandle(ctx) ? 0 : -1;
2428 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2430 ULONG written = 0;
2431 HRESULT hr;
2433 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2434 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2435 if (hr != S_OK)
2437 WARN("stream write error: 0x%08x\n", hr);
2438 return -1;
2440 else
2441 return len;
2444 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2446 IStream_Release((IStream*)ctx);
2447 return 0;
2450 static HRESULT WINAPI domdoc_save(
2451 IXMLDOMDocument3 *iface,
2452 VARIANT destination )
2454 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2455 xmlSaveCtxtPtr ctx = NULL;
2456 xmlNodePtr xmldecl;
2457 HRESULT ret = S_OK;
2459 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2461 switch (V_VT(&destination))
2463 case VT_UNKNOWN:
2465 IUnknown *pUnk = V_UNKNOWN(&destination);
2466 IXMLDOMDocument3 *document;
2467 IStream *stream;
2469 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2470 if(ret == S_OK)
2472 VARIANT_BOOL success;
2473 BSTR xml;
2475 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2476 if(ret == S_OK)
2478 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2479 SysFreeString(xml);
2482 IXMLDOMDocument3_Release(document);
2483 return ret;
2486 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2487 if(ret == S_OK)
2489 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2490 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2491 domdoc_stream_save_closecallback, stream, NULL, options);
2493 if(!ctx)
2495 IStream_Release(stream);
2496 return E_FAIL;
2500 break;
2502 case VT_BSTR:
2503 case VT_BSTR | VT_BYREF:
2505 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2507 /* save with file path */
2508 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2509 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2510 if( handle == INVALID_HANDLE_VALUE )
2512 WARN("failed to create file\n");
2513 return E_FAIL;
2516 /* disable top XML declaration */
2517 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2518 handle, NULL, options);
2519 if (!ctx)
2521 CloseHandle(handle);
2522 return E_FAIL;
2525 break;
2527 default:
2528 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2529 return S_FALSE;
2532 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2533 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2534 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2536 /* will release resources through close callback */
2537 xmlSaveClose(ctx);
2539 return ret;
2542 static HRESULT WINAPI domdoc_get_validateOnParse(
2543 IXMLDOMDocument3 *iface,
2544 VARIANT_BOOL* isValidating )
2546 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2547 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2548 *isValidating = This->validating;
2549 return S_OK;
2553 static HRESULT WINAPI domdoc_put_validateOnParse(
2554 IXMLDOMDocument3 *iface,
2555 VARIANT_BOOL isValidating )
2557 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2558 TRACE("(%p)->(%d)\n", This, isValidating);
2559 This->validating = isValidating;
2560 return S_OK;
2564 static HRESULT WINAPI domdoc_get_resolveExternals(
2565 IXMLDOMDocument3 *iface,
2566 VARIANT_BOOL* isResolving )
2568 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2569 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2570 *isResolving = This->resolving;
2571 return S_OK;
2575 static HRESULT WINAPI domdoc_put_resolveExternals(
2576 IXMLDOMDocument3 *iface,
2577 VARIANT_BOOL isResolving )
2579 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2580 TRACE("(%p)->(%d)\n", This, isResolving);
2581 This->resolving = isResolving;
2582 return S_OK;
2586 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2587 IXMLDOMDocument3 *iface,
2588 VARIANT_BOOL* isPreserving )
2590 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2591 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2592 *isPreserving = This->properties->preserving;
2593 return S_OK;
2597 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2598 IXMLDOMDocument3 *iface,
2599 VARIANT_BOOL isPreserving )
2601 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2602 TRACE("(%p)->(%d)\n", This, isPreserving);
2603 This->properties->preserving = isPreserving;
2604 return S_OK;
2608 static HRESULT WINAPI domdoc_put_onreadystatechange(
2609 IXMLDOMDocument3 *iface,
2610 VARIANT event )
2612 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2614 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2615 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2619 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2621 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2622 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2623 return E_NOTIMPL;
2626 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2628 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2629 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2630 return E_NOTIMPL;
2633 static HRESULT WINAPI domdoc_get_namespaces(
2634 IXMLDOMDocument3* iface,
2635 IXMLDOMSchemaCollection** collection )
2637 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2638 HRESULT hr;
2640 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2642 if (!collection) return E_POINTER;
2644 if (!This->namespaces)
2646 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2647 if (hr != S_OK) return hr;
2649 hr = cache_from_doc_ns(This->namespaces, &This->node);
2650 if (hr != S_OK)
2651 release_namespaces(This);
2654 if (This->namespaces)
2655 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2656 &IID_IXMLDOMSchemaCollection, (void**)collection);
2658 return hr;
2661 static HRESULT WINAPI domdoc_get_schemas(
2662 IXMLDOMDocument3* iface,
2663 VARIANT* schema )
2665 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2666 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2667 HRESULT hr = S_FALSE;
2669 TRACE("(%p)->(%p)\n", This, schema);
2671 V_VT(schema) = VT_NULL;
2672 /* just to reset pointer part, cause that's what application is expected to use */
2673 V_DISPATCH(schema) = NULL;
2675 if(cur_schema)
2677 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2678 if(SUCCEEDED(hr))
2679 V_VT(schema) = VT_DISPATCH;
2681 return hr;
2684 static HRESULT WINAPI domdoc_putref_schemas(
2685 IXMLDOMDocument3* iface,
2686 VARIANT schema)
2688 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2689 HRESULT hr = E_FAIL;
2690 IXMLDOMSchemaCollection2* new_schema = NULL;
2692 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2693 switch(V_VT(&schema))
2695 case VT_UNKNOWN:
2696 if (V_UNKNOWN(&schema))
2698 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2699 break;
2701 /* fallthrough */
2702 case VT_DISPATCH:
2703 if (V_DISPATCH(&schema))
2705 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2706 break;
2708 /* fallthrough */
2709 case VT_NULL:
2710 case VT_EMPTY:
2711 hr = S_OK;
2712 break;
2714 default:
2715 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2718 if(SUCCEEDED(hr))
2720 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2721 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2724 return hr;
2727 static inline BOOL is_wellformed(xmlDocPtr doc)
2729 #ifdef HAVE_XMLDOC_PROPERTIES
2730 return doc->properties & XML_DOC_WELLFORMED;
2731 #else
2732 /* Not a full check, but catches the worst violations */
2733 xmlNodePtr child;
2734 int root = 0;
2736 for (child = doc->children; child != NULL; child = child->next)
2738 switch (child->type)
2740 case XML_ELEMENT_NODE:
2741 if (++root > 1)
2742 return FALSE;
2743 break;
2744 case XML_TEXT_NODE:
2745 case XML_CDATA_SECTION_NODE:
2746 return FALSE;
2747 break;
2748 default:
2749 break;
2753 return root == 1;
2754 #endif
2757 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2759 va_list ap;
2760 va_start(ap, msg);
2761 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2762 va_end(ap);
2765 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2767 va_list ap;
2768 va_start(ap, msg);
2769 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2770 va_end(ap);
2773 static HRESULT WINAPI domdoc_validateNode(
2774 IXMLDOMDocument3* iface,
2775 IXMLDOMNode* node,
2776 IXMLDOMParseError** err)
2778 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2779 LONG state, err_code = 0;
2780 HRESULT hr = S_OK;
2781 int validated = 0;
2783 TRACE("(%p)->(%p, %p)\n", This, node, err);
2784 IXMLDOMDocument3_get_readyState(iface, &state);
2785 if (state != READYSTATE_COMPLETE)
2787 if (err)
2788 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2789 return E_PENDING;
2792 if (!node)
2794 if (err)
2795 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2796 return E_POINTER;
2799 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2801 if (err)
2802 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2803 return E_FAIL;
2806 if (!is_wellformed(get_doc(This)))
2808 ERR("doc not well-formed\n");
2809 if (err)
2810 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2811 return S_FALSE;
2814 /* DTD validation */
2815 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2817 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2818 vctx->error = validate_error;
2819 vctx->warning = validate_warning;
2820 ++validated;
2822 if (!((node == (IXMLDOMNode*)iface)?
2823 xmlValidateDocument(vctx, get_doc(This)) :
2824 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2826 /* TODO: get a real error code here */
2827 TRACE("DTD validation failed\n");
2828 err_code = E_XML_INVALID;
2829 hr = S_FALSE;
2831 xmlFreeValidCtxt(vctx);
2834 /* Schema validation */
2835 if (hr == S_OK && This->properties->schemaCache != NULL)
2838 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2839 if (SUCCEEDED(hr))
2841 ++validated;
2842 /* TODO: get a real error code here */
2843 if (hr == S_OK)
2845 TRACE("schema validation succeeded\n");
2847 else
2849 ERR("schema validation failed\n");
2850 err_code = E_XML_INVALID;
2853 else
2855 /* not really OK, just didn't find a schema for the ns */
2856 hr = S_OK;
2860 if (!validated)
2862 ERR("no DTD or schema found\n");
2863 err_code = E_XML_NODTD;
2864 hr = S_FALSE;
2867 if (err)
2868 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2870 return hr;
2873 static HRESULT WINAPI domdoc_validate(
2874 IXMLDOMDocument3* iface,
2875 IXMLDOMParseError** err)
2877 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2878 TRACE("(%p)->(%p)\n", This, err);
2879 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2882 static HRESULT WINAPI domdoc_setProperty(
2883 IXMLDOMDocument3* iface,
2884 BSTR p,
2885 VARIANT value)
2887 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2889 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2891 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
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;
2908 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2909 This->properties->XPath = TRUE;
2910 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2911 This->properties->XPath = FALSE;
2912 else
2913 hr = E_FAIL;
2915 VariantClear(&varStr);
2916 return hr;
2918 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2920 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2921 struct list *pNsList;
2922 VARIANT varStr;
2923 HRESULT hr;
2924 BSTR bstr;
2926 V_VT(&varStr) = VT_EMPTY;
2927 if (V_VT(&value) != VT_BSTR)
2929 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2930 return hr;
2931 bstr = V_BSTR(&varStr);
2933 else
2934 bstr = V_BSTR(&value);
2936 hr = S_OK;
2938 pNsList = &(This->properties->selectNsList);
2939 clear_selectNsList(pNsList);
2940 heap_free(nsStr);
2941 nsStr = xmlchar_from_wchar(bstr);
2943 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2945 This->properties->selectNsStr = nsStr;
2946 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2947 if (bstr && *bstr)
2949 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2950 select_ns_entry* ns_entry = NULL;
2951 xmlXPathContextPtr ctx;
2953 ctx = xmlXPathNewContext(This->node.node->doc);
2954 pTokBegin = nsStr;
2956 /* skip leading spaces */
2957 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2958 *pTokBegin == '\t' || *pTokBegin == '\r')
2959 ++pTokBegin;
2961 for (; *pTokBegin; pTokBegin = pTokEnd)
2963 if (ns_entry)
2964 memset(ns_entry, 0, sizeof(select_ns_entry));
2965 else
2966 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2968 while (*pTokBegin == ' ')
2969 ++pTokBegin;
2970 pTokEnd = pTokBegin;
2971 while (*pTokEnd != ' ' && *pTokEnd != 0)
2972 ++pTokEnd;
2974 /* so it failed to advance which means we've got some trailing spaces */
2975 if (pTokEnd == pTokBegin) break;
2977 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2979 hr = E_FAIL;
2980 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2981 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2982 continue;
2985 pTokBegin += 5;
2986 if (*pTokBegin == '=')
2988 /*valid for XSLPattern?*/
2989 FIXME("Setting default xmlns not supported - skipping.\n");
2990 continue;
2992 else if (*pTokBegin == ':')
2994 ns_entry->prefix = ++pTokBegin;
2995 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2998 if (pTokInner == pTokEnd)
3000 hr = E_FAIL;
3001 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3002 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3003 continue;
3006 ns_entry->prefix_end = *pTokInner;
3007 *pTokInner = 0;
3008 ++pTokInner;
3010 if (pTokEnd-pTokInner > 1 &&
3011 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3012 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3014 ns_entry->href = ++pTokInner;
3015 ns_entry->href_end = *(pTokEnd-1);
3016 *(pTokEnd-1) = 0;
3017 list_add_tail(pNsList, &ns_entry->entry);
3018 /*let libxml figure out if they're valid from here ;)*/
3019 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3021 hr = E_FAIL;
3023 ns_entry = NULL;
3024 continue;
3026 else
3028 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3029 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3030 list_add_tail(pNsList, &ns_entry->entry);
3032 ns_entry = NULL;
3033 hr = E_FAIL;
3034 continue;
3037 else
3039 hr = E_FAIL;
3040 continue;
3043 heap_free(ns_entry);
3044 xmlXPathFreeContext(ctx);
3047 VariantClear(&varStr);
3048 return hr;
3050 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3051 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3052 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
3054 /* Ignore */
3055 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3056 return S_OK;
3059 FIXME("Unknown property %s\n", debugstr_w(p));
3060 return E_FAIL;
3063 static HRESULT WINAPI domdoc_getProperty(
3064 IXMLDOMDocument3* iface,
3065 BSTR p,
3066 VARIANT* var)
3068 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3070 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3072 if (!var)
3073 return E_INVALIDARG;
3075 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3077 V_VT(var) = VT_BSTR;
3078 V_BSTR(var) = This->properties->XPath ?
3079 SysAllocString(PropValueXPathW) :
3080 SysAllocString(PropValueXSLPatternW);
3081 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3083 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3085 int lenA, lenW;
3086 BSTR rebuiltStr, cur;
3087 const xmlChar *nsStr;
3088 struct list *pNsList;
3089 select_ns_entry* pNsEntry;
3091 V_VT(var) = VT_BSTR;
3092 nsStr = This->properties->selectNsStr;
3093 pNsList = &This->properties->selectNsList;
3094 lenA = This->properties->selectNsStr_len;
3095 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3096 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3097 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3098 cur = rebuiltStr;
3099 /* this is fine because all of the chars that end tokens are ASCII*/
3100 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3102 while (*cur != 0) ++cur;
3103 if (pNsEntry->prefix_end)
3105 *cur = pNsEntry->prefix_end;
3106 while (*cur != 0) ++cur;
3109 if (pNsEntry->href_end)
3111 *cur = pNsEntry->href_end;
3114 V_BSTR(var) = SysAllocString(rebuiltStr);
3115 heap_free(rebuiltStr);
3116 return S_OK;
3119 FIXME("Unknown property %s\n", debugstr_w(p));
3120 return E_FAIL;
3123 static HRESULT WINAPI domdoc_importNode(
3124 IXMLDOMDocument3* iface,
3125 IXMLDOMNode* node,
3126 VARIANT_BOOL deep,
3127 IXMLDOMNode** clone)
3129 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3130 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3131 return E_NOTIMPL;
3134 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3136 domdoc_QueryInterface,
3137 domdoc_AddRef,
3138 domdoc_Release,
3139 domdoc_GetTypeInfoCount,
3140 domdoc_GetTypeInfo,
3141 domdoc_GetIDsOfNames,
3142 domdoc_Invoke,
3143 domdoc_get_nodeName,
3144 domdoc_get_nodeValue,
3145 domdoc_put_nodeValue,
3146 domdoc_get_nodeType,
3147 domdoc_get_parentNode,
3148 domdoc_get_childNodes,
3149 domdoc_get_firstChild,
3150 domdoc_get_lastChild,
3151 domdoc_get_previousSibling,
3152 domdoc_get_nextSibling,
3153 domdoc_get_attributes,
3154 domdoc_insertBefore,
3155 domdoc_replaceChild,
3156 domdoc_removeChild,
3157 domdoc_appendChild,
3158 domdoc_hasChildNodes,
3159 domdoc_get_ownerDocument,
3160 domdoc_cloneNode,
3161 domdoc_get_nodeTypeString,
3162 domdoc_get_text,
3163 domdoc_put_text,
3164 domdoc_get_specified,
3165 domdoc_get_definition,
3166 domdoc_get_nodeTypedValue,
3167 domdoc_put_nodeTypedValue,
3168 domdoc_get_dataType,
3169 domdoc_put_dataType,
3170 domdoc_get_xml,
3171 domdoc_transformNode,
3172 domdoc_selectNodes,
3173 domdoc_selectSingleNode,
3174 domdoc_get_parsed,
3175 domdoc_get_namespaceURI,
3176 domdoc_get_prefix,
3177 domdoc_get_baseName,
3178 domdoc_transformNodeToObject,
3179 domdoc_get_doctype,
3180 domdoc_get_implementation,
3181 domdoc_get_documentElement,
3182 domdoc_put_documentElement,
3183 domdoc_createElement,
3184 domdoc_createDocumentFragment,
3185 domdoc_createTextNode,
3186 domdoc_createComment,
3187 domdoc_createCDATASection,
3188 domdoc_createProcessingInstruction,
3189 domdoc_createAttribute,
3190 domdoc_createEntityReference,
3191 domdoc_getElementsByTagName,
3192 domdoc_createNode,
3193 domdoc_nodeFromID,
3194 domdoc_load,
3195 domdoc_get_readyState,
3196 domdoc_get_parseError,
3197 domdoc_get_url,
3198 domdoc_get_async,
3199 domdoc_put_async,
3200 domdoc_abort,
3201 domdoc_loadXML,
3202 domdoc_save,
3203 domdoc_get_validateOnParse,
3204 domdoc_put_validateOnParse,
3205 domdoc_get_resolveExternals,
3206 domdoc_put_resolveExternals,
3207 domdoc_get_preserveWhiteSpace,
3208 domdoc_put_preserveWhiteSpace,
3209 domdoc_put_onreadystatechange,
3210 domdoc_put_onDataAvailable,
3211 domdoc_put_onTransformNode,
3212 domdoc_get_namespaces,
3213 domdoc_get_schemas,
3214 domdoc_putref_schemas,
3215 domdoc_validate,
3216 domdoc_setProperty,
3217 domdoc_getProperty,
3218 domdoc_validateNode,
3219 domdoc_importNode
3222 /* IConnectionPointContainer */
3223 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3224 REFIID riid, void **ppv)
3226 domdoc *This = impl_from_IConnectionPointContainer(iface);
3227 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3230 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3232 domdoc *This = impl_from_IConnectionPointContainer(iface);
3233 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3236 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3238 domdoc *This = impl_from_IConnectionPointContainer(iface);
3239 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3242 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3243 IEnumConnectionPoints **ppEnum)
3245 domdoc *This = impl_from_IConnectionPointContainer(iface);
3246 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3247 return E_NOTIMPL;
3250 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3251 REFIID riid, IConnectionPoint **cp)
3253 domdoc *This = impl_from_IConnectionPointContainer(iface);
3254 ConnectionPoint *iter;
3256 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3258 *cp = NULL;
3260 for(iter = This->cp_list; iter; iter = iter->next)
3262 if (IsEqualGUID(iter->iid, riid))
3263 *cp = &iter->IConnectionPoint_iface;
3266 if (*cp)
3268 IConnectionPoint_AddRef(*cp);
3269 return S_OK;
3272 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3273 return CONNECT_E_NOCONNECTION;
3277 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3279 ConnectionPointContainer_QueryInterface,
3280 ConnectionPointContainer_AddRef,
3281 ConnectionPointContainer_Release,
3282 ConnectionPointContainer_EnumConnectionPoints,
3283 ConnectionPointContainer_FindConnectionPoint
3286 /* IConnectionPoint */
3287 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3288 REFIID riid, void **ppv)
3290 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3292 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3294 *ppv = NULL;
3296 if (IsEqualGUID(&IID_IUnknown, riid) ||
3297 IsEqualGUID(&IID_IConnectionPoint, riid))
3299 *ppv = iface;
3302 if (*ppv)
3304 IConnectionPoint_AddRef(iface);
3305 return S_OK;
3308 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3309 return E_NOINTERFACE;
3312 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3314 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3315 return IConnectionPointContainer_AddRef(This->container);
3318 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3320 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3321 return IConnectionPointContainer_Release(This->container);
3324 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3326 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3328 TRACE("(%p)->(%p)\n", This, iid);
3330 if (!iid) return E_POINTER;
3332 *iid = *This->iid;
3333 return S_OK;
3336 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3337 IConnectionPointContainer **container)
3339 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3341 TRACE("(%p)->(%p)\n", This, container);
3343 if (!container) return E_POINTER;
3345 *container = This->container;
3346 IConnectionPointContainer_AddRef(*container);
3347 return S_OK;
3350 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3351 DWORD *cookie)
3353 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3354 IUnknown *sink;
3355 HRESULT hr;
3356 DWORD i;
3358 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3360 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3361 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3362 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3363 if(FAILED(hr))
3364 return CONNECT_E_CANNOTCONNECT;
3366 if(This->sinks)
3368 for (i = 0; i < This->sinks_size; i++)
3369 if (!This->sinks[i].unk)
3370 break;
3372 if (i == This->sinks_size)
3373 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3375 else
3377 This->sinks = heap_alloc(sizeof(*This->sinks));
3378 This->sinks_size = 1;
3379 i = 0;
3382 This->sinks[i].unk = sink;
3383 if (cookie)
3384 *cookie = i+1;
3386 return S_OK;
3389 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3391 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3393 TRACE("(%p)->(%d)\n", This, cookie);
3395 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3396 return CONNECT_E_NOCONNECTION;
3398 IUnknown_Release(This->sinks[cookie-1].unk);
3399 This->sinks[cookie-1].unk = NULL;
3401 return S_OK;
3404 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3405 IEnumConnections **ppEnum)
3407 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3408 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3409 return E_NOTIMPL;
3412 static const IConnectionPointVtbl ConnectionPointVtbl =
3414 ConnectionPoint_QueryInterface,
3415 ConnectionPoint_AddRef,
3416 ConnectionPoint_Release,
3417 ConnectionPoint_GetConnectionInterface,
3418 ConnectionPoint_GetConnectionPointContainer,
3419 ConnectionPoint_Advise,
3420 ConnectionPoint_Unadvise,
3421 ConnectionPoint_EnumConnections
3424 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3426 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3427 cp->doc = doc;
3428 cp->iid = riid;
3429 cp->sinks = NULL;
3430 cp->sinks_size = 0;
3432 cp->next = doc->cp_list;
3433 doc->cp_list = cp;
3435 cp->container = &doc->IConnectionPointContainer_iface;
3438 /* domdoc implementation of IObjectWithSite */
3439 static HRESULT WINAPI
3440 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3442 domdoc *This = impl_from_IObjectWithSite(iface);
3443 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3446 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3448 domdoc *This = impl_from_IObjectWithSite(iface);
3449 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3452 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3454 domdoc *This = impl_from_IObjectWithSite(iface);
3455 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3458 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3460 domdoc *This = impl_from_IObjectWithSite(iface);
3462 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3464 if ( !This->site )
3465 return E_FAIL;
3467 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3470 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3472 domdoc *This = impl_from_IObjectWithSite(iface);
3474 TRACE("(%p)->(%p)\n", iface, punk);
3476 if(!punk)
3478 if(This->site)
3480 IUnknown_Release( This->site );
3481 This->site = NULL;
3484 return S_OK;
3487 IUnknown_AddRef( punk );
3489 if(This->site)
3490 IUnknown_Release( This->site );
3492 This->site = punk;
3494 return S_OK;
3497 static const IObjectWithSiteVtbl domdocObjectSite =
3499 domdoc_ObjectWithSite_QueryInterface,
3500 domdoc_ObjectWithSite_AddRef,
3501 domdoc_ObjectWithSite_Release,
3502 domdoc_ObjectWithSite_SetSite,
3503 domdoc_ObjectWithSite_GetSite
3506 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3508 domdoc *This = impl_from_IObjectSafety(iface);
3509 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3512 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3514 domdoc *This = impl_from_IObjectSafety(iface);
3515 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3518 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3520 domdoc *This = impl_from_IObjectSafety(iface);
3521 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3524 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3526 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3527 DWORD *supported, DWORD *enabled)
3529 domdoc *This = impl_from_IObjectSafety(iface);
3531 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3533 if(!supported || !enabled) return E_POINTER;
3535 *supported = SAFETY_SUPPORTED_OPTIONS;
3536 *enabled = This->safeopt;
3538 return S_OK;
3541 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3542 DWORD mask, DWORD enabled)
3544 domdoc *This = impl_from_IObjectSafety(iface);
3545 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3547 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3548 return E_FAIL;
3550 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3552 return S_OK;
3555 #undef SAFETY_SUPPORTED_OPTIONS
3557 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3558 domdoc_Safety_QueryInterface,
3559 domdoc_Safety_AddRef,
3560 domdoc_Safety_Release,
3561 domdoc_Safety_GetInterfaceSafetyOptions,
3562 domdoc_Safety_SetInterfaceSafetyOptions
3565 static const tid_t domdoc_iface_tids[] = {
3566 IXMLDOMDocument3_tid,
3570 static dispex_static_data_t domdoc_dispex = {
3571 NULL,
3572 IXMLDOMDocument3_tid,
3573 NULL,
3574 domdoc_iface_tids
3577 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3579 domdoc *doc;
3581 doc = heap_alloc( sizeof (*doc) );
3582 if( !doc )
3583 return E_OUTOFMEMORY;
3585 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3586 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3587 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3588 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3589 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3590 doc->ref = 1;
3591 doc->async = VARIANT_TRUE;
3592 doc->validating = 0;
3593 doc->resolving = 0;
3594 doc->properties = properties_from_xmlDocPtr(xmldoc);
3595 doc->error = S_OK;
3596 doc->site = NULL;
3597 doc->safeopt = 0;
3598 doc->cp_list = NULL;
3599 doc->namespaces = NULL;
3600 memset(doc->events, 0, sizeof(doc->events));
3602 /* events connection points */
3603 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3604 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3605 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3607 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3608 &domdoc_dispex);
3610 *document = &doc->IXMLDOMDocument3_iface;
3612 TRACE("returning iface %p\n", *document);
3613 return S_OK;
3616 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3618 xmlDocPtr xmldoc;
3619 HRESULT hr;
3621 TRACE("(%d, %p)\n", version, ppObj);
3623 xmldoc = xmlNewDoc(NULL);
3624 if(!xmldoc)
3625 return E_OUTOFMEMORY;
3627 xmldoc_init(xmldoc, version);
3629 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3630 if(FAILED(hr))
3632 free_properties(properties_from_xmlDocPtr(xmldoc));
3633 heap_free(xmldoc->_private);
3634 xmlFreeDoc(xmldoc);
3635 return hr;
3638 return hr;
3641 IUnknown* create_domdoc( xmlNodePtr document )
3643 void* pObj = NULL;
3644 HRESULT hr;
3646 TRACE("(%p)\n", document);
3648 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3649 if (FAILED(hr))
3650 return NULL;
3652 return pObj;
3655 #else
3657 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3659 MESSAGE("This program tried to use a DOMDocument object, but\n"
3660 "libxml2 support was not present at compile time.\n");
3661 return E_NOTIMPL;
3664 #endif