wined3d: Pass the pixel shader input signature to shader_arb_generate_vshader.
[wine.git] / dlls / msxml3 / domdoc.c
blobe98fa7262ca167bfd103bc4f1bee2fb51f59a863
1 /*
2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010-2011 Adam Martinson for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include "config.h"
27 #include <stdarg.h>
28 #include <assert.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
51 #include "wine/debug.h"
52 #include "wine/list.h"
54 #include "msxml_private.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 #ifdef HAVE_LIBXML2
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT 1
62 #define XML_SAVE_NO_DECL 2
63 #define XML_SAVE_NO_EMPTY 4
64 #define XML_SAVE_NO_XHTML 8
65 #define XML_SAVE_XHTML 16
66 #define XML_SAVE_AS_XML 32
67 #define XML_SAVE_AS_HTML 64
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77 /* Anything that passes the test_get_ownerDocument()
78 * tests can go here (data shared between all instances).
79 * We need to preserve this when reloading a document,
80 * and also need access to it from the libxml backend. */
81 typedef struct {
82 MSXML_VERSION version;
83 VARIANT_BOOL preserving;
84 IXMLDOMSchemaCollection2* schemaCache;
85 struct list selectNsList;
86 xmlChar const* selectNsStr;
87 LONG selectNsStr_len;
88 BOOL XPath;
89 } domdoc_properties;
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
94 struct ConnectionPoint
96 IConnectionPoint IConnectionPoint_iface;
97 const IID *iid;
99 ConnectionPoint *next;
100 IConnectionPointContainer *container;
101 domdoc *doc;
103 union
105 IUnknown *unk;
106 IDispatch *disp;
107 IPropertyNotifySink *propnotif;
108 } *sinks;
109 DWORD sinks_size;
112 typedef enum {
113 EVENTID_READYSTATECHANGE = 0,
114 EVENTID_DATAAVAILABLE,
115 EVENTID_TRANSFORMNODE,
116 EVENTID_LAST
117 } eventid_t;
119 struct domdoc
121 xmlnode node;
122 IXMLDOMDocument3 IXMLDOMDocument3_iface;
123 IPersistStreamInit IPersistStreamInit_iface;
124 IObjectWithSite IObjectWithSite_iface;
125 IObjectSafety IObjectSafety_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
127 LONG ref;
128 VARIANT_BOOL async;
129 VARIANT_BOOL validating;
130 VARIANT_BOOL resolving;
131 domdoc_properties* properties;
132 bsc_t *bsc;
133 HRESULT error;
135 /* IObjectWithSite*/
136 IUnknown *site;
138 /* IObjectSafety */
139 DWORD safeopt;
141 /* connection list */
142 ConnectionPoint *cp_list;
143 ConnectionPoint cp_domdocevents;
144 ConnectionPoint cp_propnotif;
145 ConnectionPoint cp_dispatch;
147 /* events */
148 IDispatch *events[EVENTID_LAST];
150 IXMLDOMSchemaCollection2 *namespaces;
153 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
155 IDispatch *disp;
157 switch (V_VT(v))
159 case VT_UNKNOWN:
160 if (V_UNKNOWN(v))
161 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
162 else
163 disp = NULL;
164 break;
165 case VT_DISPATCH:
166 disp = V_DISPATCH(v);
167 if (disp) IDispatch_AddRef(disp);
168 break;
169 default:
170 return DISP_E_TYPEMISMATCH;
173 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
174 doc->events[eid] = disp;
176 return S_OK;
179 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
181 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 In native windows, the whole lifetime management of XMLDOMNodes is
186 managed automatically using reference counts. Wine emulates that by
187 maintaining a reference count to the document that is increased for
188 each IXMLDOMNode pointer passed out for this document. If all these
189 pointers are gone, the document is unreachable and gets freed, that
190 is, all nodes in the tree of the document get freed.
192 You are able to create nodes that are associated to a document (in
193 fact, in msxml's XMLDOM model, all nodes are associated to a document),
194 but not in the tree of that document, for example using the createFoo
195 functions from IXMLDOMDocument. These nodes do not get cleaned up
196 by libxml, so we have to do it ourselves.
198 To catch these nodes, a list of "orphan nodes" is introduced.
199 It contains pointers to all roots of node trees that are
200 associated with the document without being part of the document
201 tree. All nodes with parent==NULL (except for the document root nodes)
202 should be in the orphan node list of their document. All orphan nodes
203 get freed together with the document itself.
206 typedef struct _xmldoc_priv {
207 LONG refs;
208 struct list orphans;
209 domdoc_properties* properties;
210 } xmldoc_priv;
212 typedef struct _orphan_entry {
213 struct list entry;
214 xmlNode * node;
215 } orphan_entry;
217 typedef struct _select_ns_entry {
218 struct list entry;
219 xmlChar const* prefix;
220 xmlChar prefix_end;
221 xmlChar const* href;
222 xmlChar href_end;
223 } select_ns_entry;
225 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
227 return doc->_private;
230 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
232 return priv_from_xmlDocPtr(doc)->properties;
235 BOOL is_xpathmode(const xmlDocPtr doc)
237 return properties_from_xmlDocPtr(doc)->XPath;
240 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
242 properties_from_xmlDocPtr(doc)->XPath = xpath;
245 int registerNamespaces(xmlXPathContextPtr ctxt)
247 int n = 0;
248 const select_ns_entry* ns = NULL;
249 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
251 TRACE("(%p)\n", ctxt);
253 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
255 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
256 ++n;
259 return n;
262 static inline void clear_selectNsList(struct list* pNsList)
264 select_ns_entry *ns, *ns2;
265 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
267 heap_free( ns );
269 list_init(pNsList);
272 static xmldoc_priv * create_priv(void)
274 xmldoc_priv *priv;
275 priv = heap_alloc( sizeof (*priv) );
277 if (priv)
279 priv->refs = 0;
280 list_init( &priv->orphans );
281 priv->properties = NULL;
284 return priv;
287 static domdoc_properties *create_properties(MSXML_VERSION version)
289 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
291 list_init(&properties->selectNsList);
292 properties->preserving = VARIANT_FALSE;
293 properties->schemaCache = NULL;
294 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
295 properties->selectNsStr_len = 0;
297 /* properties that are dependent on object versions */
298 properties->version = version;
299 properties->XPath = (version == MSXML4 || version == MSXML6);
301 return properties;
304 static domdoc_properties* copy_properties(domdoc_properties const* properties)
306 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
307 select_ns_entry const* ns = NULL;
308 select_ns_entry* new_ns = NULL;
309 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
310 ptrdiff_t offset;
312 if (pcopy)
314 pcopy->version = properties->version;
315 pcopy->preserving = properties->preserving;
316 pcopy->schemaCache = properties->schemaCache;
317 if (pcopy->schemaCache)
318 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
319 pcopy->XPath = properties->XPath;
320 pcopy->selectNsStr_len = properties->selectNsStr_len;
321 list_init( &pcopy->selectNsList );
322 pcopy->selectNsStr = heap_alloc(len);
323 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
324 offset = pcopy->selectNsStr - properties->selectNsStr;
326 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
328 new_ns = heap_alloc(sizeof(select_ns_entry));
329 memcpy(new_ns, ns, sizeof(select_ns_entry));
330 new_ns->href += offset;
331 new_ns->prefix += offset;
332 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
337 return pcopy;
340 static void free_properties(domdoc_properties* properties)
342 if (properties)
344 if (properties->schemaCache)
345 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
346 clear_selectNsList(&properties->selectNsList);
347 heap_free((xmlChar*)properties->selectNsStr);
348 heap_free(properties);
352 static void release_namespaces(domdoc *This)
354 if (This->namespaces)
356 IXMLDOMSchemaCollection2_Release(This->namespaces);
357 This->namespaces = NULL;
361 /* links a "<?xml" node as a first child */
362 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
364 assert(doc != NULL);
365 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
368 /* unlinks a first "<?xml" child if it was created */
369 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
371 static const xmlChar xmlA[] = "xml";
372 xmlNodePtr node, first_child;
374 assert(doc != NULL);
376 /* xml declaration node could be created automatically after parsing or added
377 to a tree later */
378 first_child = doc->children;
379 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
381 node = first_child;
382 xmlUnlinkNode( node );
384 else
385 node = NULL;
387 return node;
390 BOOL is_preserving_whitespace(xmlNodePtr node)
392 domdoc_properties* properties = NULL;
393 /* during parsing the xmlDoc._private stuff is not there */
394 if (priv_from_xmlDocPtr(node->doc))
395 properties = properties_from_xmlDocPtr(node->doc);
396 return ((properties && properties->preserving == VARIANT_TRUE) ||
397 xmlNodeGetSpacePreserve(node) == 1);
400 static inline BOOL strn_isspace(xmlChar const* str, int len)
402 for (; str && len > 0 && *str; ++str, --len)
403 if (!isspace(*str))
404 break;
406 return len == 0;
409 static void sax_characters(void *ctx, const xmlChar *ch, int len)
411 xmlParserCtxtPtr ctxt;
412 const domdoc *This;
414 ctxt = (xmlParserCtxtPtr) ctx;
415 This = (const domdoc*) ctxt->_private;
417 if (ctxt->node)
419 /* Characters are reported with multiple calls, for example each charref is reported with a separate
420 call and then parser appends it to a single text node or creates a new node if not created.
421 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
422 a space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
423 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
424 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
425 for next '<' opening bracket - similar logic is used by libxml2 itself.
427 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
428 if (!This->properties->preserving &&
429 !is_preserving_whitespace(ctxt->node) &&
430 strn_isspace(ch, len) &&
431 (!ctxt->node->last ||
432 ((ctxt->node->last && (*ctxt->input->cur) == '<'))))
433 return;
436 xmlSAX2Characters(ctxt, ch, len);
439 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
441 va_list ap;
442 va_start(ap, msg);
443 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
444 va_end(ap);
447 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
449 va_list ap;
450 va_start(ap, msg);
451 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
452 va_end(ap);
455 static void sax_serror(void* ctx, xmlErrorPtr err)
457 LIBXML2_CALLBACK_SERROR(doparse, err);
460 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
462 xmlDocPtr doc = NULL;
463 xmlParserCtxtPtr pctx;
464 static xmlSAXHandler sax_handler = {
465 xmlSAX2InternalSubset, /* internalSubset */
466 xmlSAX2IsStandalone, /* isStandalone */
467 xmlSAX2HasInternalSubset, /* hasInternalSubset */
468 xmlSAX2HasExternalSubset, /* hasExternalSubset */
469 xmlSAX2ResolveEntity, /* resolveEntity */
470 xmlSAX2GetEntity, /* getEntity */
471 xmlSAX2EntityDecl, /* entityDecl */
472 xmlSAX2NotationDecl, /* notationDecl */
473 xmlSAX2AttributeDecl, /* attributeDecl */
474 xmlSAX2ElementDecl, /* elementDecl */
475 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
476 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
477 xmlSAX2StartDocument, /* startDocument */
478 xmlSAX2EndDocument, /* endDocument */
479 xmlSAX2StartElement, /* startElement */
480 xmlSAX2EndElement, /* endElement */
481 xmlSAX2Reference, /* reference */
482 sax_characters, /* characters */
483 sax_characters, /* ignorableWhitespace */
484 xmlSAX2ProcessingInstruction, /* processingInstruction */
485 xmlSAX2Comment, /* comment */
486 sax_warning, /* warning */
487 sax_error, /* error */
488 sax_error, /* fatalError */
489 xmlSAX2GetParameterEntity, /* getParameterEntity */
490 xmlSAX2CDataBlock, /* cdataBlock */
491 xmlSAX2ExternalSubset, /* externalSubset */
492 0, /* initialized */
493 NULL, /* _private */
494 xmlSAX2StartElementNs, /* startElementNs */
495 xmlSAX2EndElementNs, /* endElementNs */
496 sax_serror /* serror */
499 pctx = xmlCreateMemoryParserCtxt(ptr, len);
500 if (!pctx)
502 ERR("Failed to create parser context\n");
503 return NULL;
506 if (pctx->sax) xmlFree(pctx->sax);
507 pctx->sax = &sax_handler;
508 pctx->_private = This;
509 pctx->recovery = 0;
511 if (encoding != XML_CHAR_ENCODING_NONE)
512 xmlSwitchEncoding(pctx, encoding);
514 xmlParseDocument(pctx);
516 if (pctx->wellFormed)
518 doc = pctx->myDoc;
520 else
522 xmlFreeDoc(pctx->myDoc);
523 pctx->myDoc = NULL;
525 pctx->sax = NULL;
526 xmlFreeParserCtxt(pctx);
528 /* TODO: put this in one of the SAX callbacks */
529 /* create first child as a <?xml...?> */
530 if (doc && doc->standalone != -1)
532 xmlNodePtr node;
533 char buff[30];
534 xmlChar *xmlbuff = (xmlChar*)buff;
536 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
538 /* version attribute can't be omitted */
539 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
540 xmlNodeAddContent( node, xmlbuff );
542 if (doc->encoding)
544 sprintf(buff, " encoding=\"%s\"", doc->encoding);
545 xmlNodeAddContent( node, xmlbuff );
548 if (doc->standalone != -2)
550 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
551 xmlNodeAddContent( node, xmlbuff );
554 xmldoc_link_xmldecl( doc, node );
557 return doc;
560 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
562 doc->_private = create_priv();
563 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
566 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
568 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
569 TRACE("(%p)->(%d)\n", doc, ref);
570 return ref;
573 LONG xmldoc_add_ref(xmlDocPtr doc)
575 return xmldoc_add_refs(doc, 1);
578 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
580 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
581 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
582 TRACE("(%p)->(%d)\n", doc, ref);
584 if (ref < 0)
585 WARN("negative refcount, expect troubles\n");
587 if (ref == 0)
589 orphan_entry *orphan, *orphan2;
590 TRACE("freeing docptr %p\n", doc);
592 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
594 xmlFreeNode( orphan->node );
595 heap_free( orphan );
597 free_properties(priv->properties);
598 heap_free(doc->_private);
600 xmlFreeDoc(doc);
603 return ref;
606 LONG xmldoc_release(xmlDocPtr doc)
608 return xmldoc_release_refs(doc, 1);
611 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
613 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
614 orphan_entry *entry;
616 entry = heap_alloc( sizeof (*entry) );
617 if(!entry)
618 return E_OUTOFMEMORY;
620 entry->node = node;
621 list_add_head( &priv->orphans, &entry->entry );
622 return S_OK;
625 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
627 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
628 orphan_entry *entry, *entry2;
630 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
632 if( entry->node == node )
634 list_remove( &entry->entry );
635 heap_free( entry );
636 return S_OK;
640 return S_FALSE;
643 static inline xmlDocPtr get_doc( domdoc *This )
645 return This->node.node->doc;
648 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
650 release_namespaces(This);
652 if(This->node.node)
654 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
655 if (xmldoc_release(get_doc(This)) != 0)
656 priv_from_xmlDocPtr(get_doc(This))->properties =
657 copy_properties(This->properties);
660 This->node.node = (xmlNodePtr) xml;
662 if(This->node.node)
664 xmldoc_add_ref(get_doc(This));
665 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
668 return S_OK;
671 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
673 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
676 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
678 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
681 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
683 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
686 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
688 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
691 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
693 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
696 /************************************************************************
697 * domdoc implementation of IPersistStream.
699 static HRESULT WINAPI PersistStreamInit_QueryInterface(
700 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
702 domdoc* This = impl_from_IPersistStreamInit(iface);
703 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
706 static ULONG WINAPI PersistStreamInit_AddRef(
707 IPersistStreamInit *iface)
709 domdoc* This = impl_from_IPersistStreamInit(iface);
710 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
713 static ULONG WINAPI PersistStreamInit_Release(
714 IPersistStreamInit *iface)
716 domdoc* This = impl_from_IPersistStreamInit(iface);
717 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
720 static HRESULT WINAPI PersistStreamInit_GetClassID(
721 IPersistStreamInit *iface, CLSID *classid)
723 domdoc* This = impl_from_IPersistStreamInit(iface);
724 TRACE("(%p)->(%p)\n", This, classid);
726 if(!classid)
727 return E_POINTER;
729 *classid = *DOMDocument_version(This->properties->version);
731 return S_OK;
734 static HRESULT WINAPI PersistStreamInit_IsDirty(
735 IPersistStreamInit *iface)
737 domdoc *This = impl_from_IPersistStreamInit(iface);
738 FIXME("(%p): stub!\n", This);
739 return S_FALSE;
742 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
744 DWORD read, written, len;
745 xmlDocPtr xmldoc = NULL;
746 IStream *hstream;
747 HGLOBAL hglobal;
748 BYTE buf[4096];
749 HRESULT hr;
750 char *ptr;
752 hstream = NULL;
753 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
754 if (FAILED(hr))
755 return hr;
759 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
760 hr = IStream_Write(hstream, buf, read, &written);
761 } while(SUCCEEDED(hr) && written != 0 && read != 0);
763 if (FAILED(hr))
765 ERR("failed to copy stream 0x%08x\n", hr);
766 IStream_Release(hstream);
767 return hr;
770 hr = GetHGlobalFromStream(hstream, &hglobal);
771 if (FAILED(hr))
772 return hr;
774 len = GlobalSize(hglobal);
775 ptr = GlobalLock(hglobal);
776 if (len)
777 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
778 GlobalUnlock(hglobal);
780 if (!xmldoc)
782 ERR("Failed to parse xml\n");
783 return E_FAIL;
786 xmldoc->_private = create_priv();
788 return attach_xmldoc(doc, xmldoc);
791 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
793 domdoc *This = impl_from_IPersistStreamInit(iface);
795 TRACE("(%p)->(%p)\n", This, stream);
797 if (!stream)
798 return E_INVALIDARG;
800 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
803 static HRESULT WINAPI PersistStreamInit_Save(
804 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
806 domdoc *This = impl_from_IPersistStreamInit(iface);
807 BSTR xmlString;
808 HRESULT hr;
810 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
812 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
813 if(hr == S_OK)
815 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
817 hr = IStream_Write( stream, xmlString, len, NULL );
818 SysFreeString(xmlString);
821 TRACE("ret 0x%08x\n", hr);
823 return hr;
826 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
827 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
829 domdoc *This = impl_from_IPersistStreamInit(iface);
830 TRACE("(%p)->(%p)\n", This, pcbSize);
831 return E_NOTIMPL;
834 static HRESULT WINAPI PersistStreamInit_InitNew(
835 IPersistStreamInit *iface)
837 domdoc *This = impl_from_IPersistStreamInit(iface);
838 TRACE("(%p)\n", This);
839 return S_OK;
842 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
844 PersistStreamInit_QueryInterface,
845 PersistStreamInit_AddRef,
846 PersistStreamInit_Release,
847 PersistStreamInit_GetClassID,
848 PersistStreamInit_IsDirty,
849 PersistStreamInit_Load,
850 PersistStreamInit_Save,
851 PersistStreamInit_GetSizeMax,
852 PersistStreamInit_InitNew
855 /* IXMLDOMDocument3 interface */
857 static const tid_t domdoc_se_tids[] = {
858 IXMLDOMNode_tid,
859 IXMLDOMDocument_tid,
860 IXMLDOMDocument2_tid,
861 IXMLDOMDocument3_tid,
862 NULL_tid
865 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
867 domdoc *This = impl_from_IXMLDOMDocument3( iface );
869 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
871 *ppvObject = NULL;
873 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
874 IsEqualGUID( riid, &IID_IDispatch ) ||
875 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
876 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
877 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
878 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
880 *ppvObject = iface;
882 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
883 IsEqualGUID(&IID_IPersistStreamInit, riid))
885 *ppvObject = &This->IPersistStreamInit_iface;
887 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
889 *ppvObject = &This->IObjectWithSite_iface;
891 else if (IsEqualGUID(&IID_IObjectSafety, riid))
893 *ppvObject = &This->IObjectSafety_iface;
895 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
897 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
899 else if(node_query_interface(&This->node, riid, ppvObject))
901 return *ppvObject ? S_OK : E_NOINTERFACE;
903 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
905 *ppvObject = &This->IConnectionPointContainer_iface;
907 else
909 TRACE("interface %s not implemented\n", debugstr_guid(riid));
910 return E_NOINTERFACE;
913 IUnknown_AddRef((IUnknown*)*ppvObject);
915 return S_OK;
918 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
920 domdoc *This = impl_from_IXMLDOMDocument3( iface );
921 ULONG ref = InterlockedIncrement( &This->ref );
922 TRACE("(%p)->(%d)\n", This, ref );
923 return ref;
926 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
928 domdoc *This = impl_from_IXMLDOMDocument3( iface );
929 LONG ref = InterlockedDecrement( &This->ref );
931 TRACE("(%p)->(%d)\n", This, ref );
933 if ( ref == 0 )
935 int eid;
937 if(This->bsc)
938 detach_bsc(This->bsc);
940 if (This->site)
941 IUnknown_Release( This->site );
942 destroy_xmlnode(&This->node);
944 for (eid = 0; eid < EVENTID_LAST; eid++)
945 if (This->events[eid]) IDispatch_Release(This->events[eid]);
947 release_namespaces(This);
948 heap_free(This);
951 return ref;
954 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
956 domdoc *This = impl_from_IXMLDOMDocument3( iface );
957 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
960 static HRESULT WINAPI domdoc_GetTypeInfo(
961 IXMLDOMDocument3 *iface,
962 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
964 domdoc *This = impl_from_IXMLDOMDocument3( iface );
965 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
968 static HRESULT WINAPI domdoc_GetIDsOfNames(
969 IXMLDOMDocument3 *iface,
970 REFIID riid,
971 LPOLESTR* rgszNames,
972 UINT cNames,
973 LCID lcid,
974 DISPID* rgDispId)
976 domdoc *This = impl_from_IXMLDOMDocument3( iface );
977 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
978 riid, rgszNames, cNames, lcid, rgDispId);
981 static HRESULT WINAPI domdoc_Invoke(
982 IXMLDOMDocument3 *iface,
983 DISPID dispIdMember,
984 REFIID riid,
985 LCID lcid,
986 WORD wFlags,
987 DISPPARAMS* pDispParams,
988 VARIANT* pVarResult,
989 EXCEPINFO* pExcepInfo,
990 UINT* puArgErr)
992 domdoc *This = impl_from_IXMLDOMDocument3( iface );
993 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
994 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
997 static HRESULT WINAPI domdoc_get_nodeName(
998 IXMLDOMDocument3 *iface,
999 BSTR* name )
1001 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1003 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1005 TRACE("(%p)->(%p)\n", This, name);
1007 return return_bstr(documentW, name);
1011 static HRESULT WINAPI domdoc_get_nodeValue(
1012 IXMLDOMDocument3 *iface,
1013 VARIANT* value )
1015 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1017 TRACE("(%p)->(%p)\n", This, value);
1019 if(!value)
1020 return E_INVALIDARG;
1022 V_VT(value) = VT_NULL;
1023 V_BSTR(value) = NULL; /* tests show that we should do this */
1024 return S_FALSE;
1028 static HRESULT WINAPI domdoc_put_nodeValue(
1029 IXMLDOMDocument3 *iface,
1030 VARIANT value)
1032 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1033 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1034 return E_FAIL;
1038 static HRESULT WINAPI domdoc_get_nodeType(
1039 IXMLDOMDocument3 *iface,
1040 DOMNodeType* type )
1042 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1044 TRACE("(%p)->(%p)\n", This, type);
1046 *type = NODE_DOCUMENT;
1047 return S_OK;
1051 static HRESULT WINAPI domdoc_get_parentNode(
1052 IXMLDOMDocument3 *iface,
1053 IXMLDOMNode** parent )
1055 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1057 TRACE("(%p)->(%p)\n", This, parent);
1059 return node_get_parent(&This->node, parent);
1063 static HRESULT WINAPI domdoc_get_childNodes(
1064 IXMLDOMDocument3 *iface,
1065 IXMLDOMNodeList** childList )
1067 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1069 TRACE("(%p)->(%p)\n", This, childList);
1071 return node_get_child_nodes(&This->node, childList);
1075 static HRESULT WINAPI domdoc_get_firstChild(
1076 IXMLDOMDocument3 *iface,
1077 IXMLDOMNode** firstChild )
1079 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1081 TRACE("(%p)->(%p)\n", This, firstChild);
1083 return node_get_first_child(&This->node, firstChild);
1087 static HRESULT WINAPI domdoc_get_lastChild(
1088 IXMLDOMDocument3 *iface,
1089 IXMLDOMNode** lastChild )
1091 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1093 TRACE("(%p)->(%p)\n", This, lastChild);
1095 return node_get_last_child(&This->node, lastChild);
1099 static HRESULT WINAPI domdoc_get_previousSibling(
1100 IXMLDOMDocument3 *iface,
1101 IXMLDOMNode** previousSibling )
1103 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1105 TRACE("(%p)->(%p)\n", This, previousSibling);
1107 return return_null_node(previousSibling);
1111 static HRESULT WINAPI domdoc_get_nextSibling(
1112 IXMLDOMDocument3 *iface,
1113 IXMLDOMNode** nextSibling )
1115 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1117 TRACE("(%p)->(%p)\n", This, nextSibling);
1119 return return_null_node(nextSibling);
1123 static HRESULT WINAPI domdoc_get_attributes(
1124 IXMLDOMDocument3 *iface,
1125 IXMLDOMNamedNodeMap** attributeMap )
1127 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1129 TRACE("(%p)->(%p)\n", This, attributeMap);
1131 return return_null_ptr((void**)attributeMap);
1135 static HRESULT WINAPI domdoc_insertBefore(
1136 IXMLDOMDocument3 *iface,
1137 IXMLDOMNode* newChild,
1138 VARIANT refChild,
1139 IXMLDOMNode** outNewChild )
1141 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1142 DOMNodeType type;
1143 HRESULT hr;
1145 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1147 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1148 if (hr != S_OK) return hr;
1150 TRACE("new node type %d\n", type);
1151 switch (type)
1153 case NODE_ATTRIBUTE:
1154 case NODE_DOCUMENT:
1155 case NODE_CDATA_SECTION:
1156 if (outNewChild) *outNewChild = NULL;
1157 return E_FAIL;
1158 default:
1159 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1163 static HRESULT WINAPI domdoc_replaceChild(
1164 IXMLDOMDocument3 *iface,
1165 IXMLDOMNode* newChild,
1166 IXMLDOMNode* oldChild,
1167 IXMLDOMNode** outOldChild)
1169 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1171 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1173 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1177 static HRESULT WINAPI domdoc_removeChild(
1178 IXMLDOMDocument3 *iface,
1179 IXMLDOMNode *child,
1180 IXMLDOMNode **oldChild)
1182 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1183 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1184 return node_remove_child(&This->node, child, oldChild);
1188 static HRESULT WINAPI domdoc_appendChild(
1189 IXMLDOMDocument3 *iface,
1190 IXMLDOMNode *child,
1191 IXMLDOMNode **outChild)
1193 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1194 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1195 return node_append_child(&This->node, child, outChild);
1199 static HRESULT WINAPI domdoc_hasChildNodes(
1200 IXMLDOMDocument3 *iface,
1201 VARIANT_BOOL *ret)
1203 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1204 TRACE("(%p)->(%p)\n", This, ret);
1205 return node_has_childnodes(&This->node, ret);
1209 static HRESULT WINAPI domdoc_get_ownerDocument(
1210 IXMLDOMDocument3 *iface,
1211 IXMLDOMDocument **doc)
1213 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1214 TRACE("(%p)->(%p)\n", This, doc);
1215 return node_get_owner_doc(&This->node, doc);
1219 static HRESULT WINAPI domdoc_cloneNode(
1220 IXMLDOMDocument3 *iface,
1221 VARIANT_BOOL deep,
1222 IXMLDOMNode** outNode)
1224 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1225 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1226 return node_clone( &This->node, deep, outNode );
1230 static HRESULT WINAPI domdoc_get_nodeTypeString(
1231 IXMLDOMDocument3 *iface,
1232 BSTR *p)
1234 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1235 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1237 TRACE("(%p)->(%p)\n", This, p);
1239 return return_bstr(documentW, p);
1243 static HRESULT WINAPI domdoc_get_text(
1244 IXMLDOMDocument3 *iface,
1245 BSTR *p)
1247 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1248 TRACE("(%p)->(%p)\n", This, p);
1249 return node_get_text(&This->node, p);
1253 static HRESULT WINAPI domdoc_put_text(
1254 IXMLDOMDocument3 *iface,
1255 BSTR text )
1257 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1258 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1259 return E_FAIL;
1263 static HRESULT WINAPI domdoc_get_specified(
1264 IXMLDOMDocument3 *iface,
1265 VARIANT_BOOL* isSpecified )
1267 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1268 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1269 *isSpecified = VARIANT_TRUE;
1270 return S_OK;
1274 static HRESULT WINAPI domdoc_get_definition(
1275 IXMLDOMDocument3 *iface,
1276 IXMLDOMNode** definitionNode )
1278 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1279 FIXME("(%p)->(%p)\n", This, definitionNode);
1280 return E_NOTIMPL;
1284 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1285 IXMLDOMDocument3 *iface,
1286 VARIANT* v )
1288 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1289 TRACE("(%p)->(%p)\n", This, v);
1290 return return_null_var(v);
1293 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1294 IXMLDOMDocument3 *iface,
1295 VARIANT typedValue )
1297 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1298 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1299 return E_NOTIMPL;
1303 static HRESULT WINAPI domdoc_get_dataType(
1304 IXMLDOMDocument3 *iface,
1305 VARIANT* typename )
1307 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1308 TRACE("(%p)->(%p)\n", This, typename);
1309 return return_null_var( typename );
1313 static HRESULT WINAPI domdoc_put_dataType(
1314 IXMLDOMDocument3 *iface,
1315 BSTR dataTypeName )
1317 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1319 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1321 if(!dataTypeName)
1322 return E_INVALIDARG;
1324 return E_FAIL;
1327 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1329 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1332 static HRESULT WINAPI domdoc_get_xml(
1333 IXMLDOMDocument3 *iface,
1334 BSTR* p)
1336 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1337 xmlSaveCtxtPtr ctxt;
1338 xmlBufferPtr buf;
1339 int options;
1340 long ret;
1342 TRACE("(%p)->(%p)\n", This, p);
1344 if(!p)
1345 return E_INVALIDARG;
1347 *p = NULL;
1349 buf = xmlBufferCreate();
1350 if(!buf)
1351 return E_OUTOFMEMORY;
1353 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1354 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1356 if(!ctxt)
1358 xmlBufferFree(buf);
1359 return E_OUTOFMEMORY;
1362 ret = xmlSaveDoc(ctxt, get_doc(This));
1363 /* flushes on close */
1364 xmlSaveClose(ctxt);
1366 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1367 if(ret != -1 && xmlBufferLength(buf) > 0)
1369 BSTR content;
1371 content = bstr_from_xmlChar(xmlBufferContent(buf));
1372 content = EnsureCorrectEOL(content);
1374 *p = content;
1376 else
1378 *p = SysAllocStringLen(NULL, 0);
1381 xmlBufferFree(buf);
1383 return *p ? S_OK : E_OUTOFMEMORY;
1387 static HRESULT WINAPI domdoc_transformNode(
1388 IXMLDOMDocument3 *iface,
1389 IXMLDOMNode *node,
1390 BSTR *p)
1392 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1393 TRACE("(%p)->(%p %p)\n", This, node, p);
1394 return node_transform_node(&This->node, node, p);
1398 static HRESULT WINAPI domdoc_selectNodes(
1399 IXMLDOMDocument3 *iface,
1400 BSTR p,
1401 IXMLDOMNodeList **outList)
1403 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1404 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1405 return node_select_nodes(&This->node, p, outList);
1409 static HRESULT WINAPI domdoc_selectSingleNode(
1410 IXMLDOMDocument3 *iface,
1411 BSTR p,
1412 IXMLDOMNode **outNode)
1414 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1415 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1416 return node_select_singlenode(&This->node, p, outNode);
1420 static HRESULT WINAPI domdoc_get_parsed(
1421 IXMLDOMDocument3 *iface,
1422 VARIANT_BOOL* isParsed )
1424 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1425 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1426 *isParsed = VARIANT_TRUE;
1427 return S_OK;
1430 static HRESULT WINAPI domdoc_get_namespaceURI(
1431 IXMLDOMDocument3 *iface,
1432 BSTR* namespaceURI )
1434 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1435 TRACE("(%p)->(%p)\n", This, namespaceURI);
1436 return return_null_bstr( namespaceURI );
1439 static HRESULT WINAPI domdoc_get_prefix(
1440 IXMLDOMDocument3 *iface,
1441 BSTR* prefix )
1443 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1444 TRACE("(%p)->(%p)\n", This, prefix);
1445 return return_null_bstr( prefix );
1449 static HRESULT WINAPI domdoc_get_baseName(
1450 IXMLDOMDocument3 *iface,
1451 BSTR* name )
1453 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1454 TRACE("(%p)->(%p)\n", This, name);
1455 return return_null_bstr( name );
1459 static HRESULT WINAPI domdoc_transformNodeToObject(
1460 IXMLDOMDocument3 *iface,
1461 IXMLDOMNode* stylesheet,
1462 VARIANT outputObject)
1464 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1465 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1466 return E_NOTIMPL;
1470 static HRESULT WINAPI domdoc_get_doctype(
1471 IXMLDOMDocument3 *iface,
1472 IXMLDOMDocumentType** doctype )
1474 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1475 IXMLDOMNode *node;
1476 xmlDtdPtr dtd;
1477 HRESULT hr;
1479 TRACE("(%p)->(%p)\n", This, doctype);
1481 if (!doctype) return E_INVALIDARG;
1483 *doctype = NULL;
1485 dtd = xmlGetIntSubset(get_doc(This));
1486 if (!dtd) return S_FALSE;
1488 node = create_node((xmlNodePtr)dtd);
1489 if (!node) return S_FALSE;
1491 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1492 IXMLDOMNode_Release(node);
1494 return hr;
1498 static HRESULT WINAPI domdoc_get_implementation(
1499 IXMLDOMDocument3 *iface,
1500 IXMLDOMImplementation** impl )
1502 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1504 TRACE("(%p)->(%p)\n", This, impl);
1506 if(!impl)
1507 return E_INVALIDARG;
1509 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1511 return S_OK;
1514 static HRESULT WINAPI domdoc_get_documentElement(
1515 IXMLDOMDocument3 *iface,
1516 IXMLDOMElement** DOMElement )
1518 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1519 IXMLDOMNode *element_node;
1520 xmlNodePtr root;
1521 HRESULT hr;
1523 TRACE("(%p)->(%p)\n", This, DOMElement);
1525 if(!DOMElement)
1526 return E_INVALIDARG;
1528 *DOMElement = NULL;
1530 root = xmlDocGetRootElement( get_doc(This) );
1531 if ( !root )
1532 return S_FALSE;
1534 element_node = create_node( root );
1535 if(!element_node) return S_FALSE;
1537 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1538 IXMLDOMNode_Release(element_node);
1540 return hr;
1544 static HRESULT WINAPI domdoc_put_documentElement(
1545 IXMLDOMDocument3 *iface,
1546 IXMLDOMElement* DOMElement )
1548 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1549 IXMLDOMNode *elementNode;
1550 xmlNodePtr oldRoot;
1551 xmlDocPtr old_doc;
1552 xmlnode *xmlNode;
1553 int refcount = 0;
1554 HRESULT hr;
1556 TRACE("(%p)->(%p)\n", This, DOMElement);
1558 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1559 if(FAILED(hr))
1560 return hr;
1562 xmlNode = get_node_obj( elementNode );
1563 if(!xmlNode) return E_FAIL;
1565 if(!xmlNode->node->parent)
1566 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1567 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1569 old_doc = xmlNode->node->doc;
1570 if (old_doc != get_doc(This))
1571 refcount = xmlnode_get_inst_cnt(xmlNode);
1573 /* old root is still orphaned by its document, update refcount from new root */
1574 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1575 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1576 if (refcount) xmldoc_release_refs(old_doc, refcount);
1577 IXMLDOMNode_Release( elementNode );
1579 if(oldRoot)
1580 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1582 return S_OK;
1586 static HRESULT WINAPI domdoc_createElement(
1587 IXMLDOMDocument3 *iface,
1588 BSTR tagname,
1589 IXMLDOMElement** element )
1591 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1592 IXMLDOMNode *node;
1593 VARIANT type;
1594 HRESULT hr;
1596 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1598 if (!element || !tagname) return E_INVALIDARG;
1600 V_VT(&type) = VT_I1;
1601 V_I1(&type) = NODE_ELEMENT;
1603 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1604 if (hr == S_OK)
1606 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1607 IXMLDOMNode_Release(node);
1610 return hr;
1614 static HRESULT WINAPI domdoc_createDocumentFragment(
1615 IXMLDOMDocument3 *iface,
1616 IXMLDOMDocumentFragment** frag )
1618 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1619 IXMLDOMNode *node;
1620 VARIANT type;
1621 HRESULT hr;
1623 TRACE("(%p)->(%p)\n", This, frag);
1625 if (!frag) return E_INVALIDARG;
1627 *frag = NULL;
1629 V_VT(&type) = VT_I1;
1630 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1632 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1633 if (hr == S_OK)
1635 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1636 IXMLDOMNode_Release(node);
1639 return hr;
1643 static HRESULT WINAPI domdoc_createTextNode(
1644 IXMLDOMDocument3 *iface,
1645 BSTR data,
1646 IXMLDOMText** text )
1648 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1649 IXMLDOMNode *node;
1650 VARIANT type;
1651 HRESULT hr;
1653 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1655 if (!text) return E_INVALIDARG;
1657 *text = NULL;
1659 V_VT(&type) = VT_I1;
1660 V_I1(&type) = NODE_TEXT;
1662 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1663 if (hr == S_OK)
1665 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1666 IXMLDOMNode_Release(node);
1667 hr = IXMLDOMText_put_data(*text, data);
1670 return hr;
1674 static HRESULT WINAPI domdoc_createComment(
1675 IXMLDOMDocument3 *iface,
1676 BSTR data,
1677 IXMLDOMComment** comment )
1679 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1680 VARIANT type;
1681 HRESULT hr;
1682 IXMLDOMNode *node;
1684 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1686 if (!comment) return E_INVALIDARG;
1688 *comment = NULL;
1690 V_VT(&type) = VT_I1;
1691 V_I1(&type) = NODE_COMMENT;
1693 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1694 if (hr == S_OK)
1696 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1697 IXMLDOMNode_Release(node);
1698 hr = IXMLDOMComment_put_data(*comment, data);
1701 return hr;
1705 static HRESULT WINAPI domdoc_createCDATASection(
1706 IXMLDOMDocument3 *iface,
1707 BSTR data,
1708 IXMLDOMCDATASection** cdata )
1710 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1711 IXMLDOMNode *node;
1712 VARIANT type;
1713 HRESULT hr;
1715 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1717 if (!cdata) return E_INVALIDARG;
1719 *cdata = NULL;
1721 V_VT(&type) = VT_I1;
1722 V_I1(&type) = NODE_CDATA_SECTION;
1724 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1725 if (hr == S_OK)
1727 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1728 IXMLDOMNode_Release(node);
1729 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1732 return hr;
1736 static HRESULT WINAPI domdoc_createProcessingInstruction(
1737 IXMLDOMDocument3 *iface,
1738 BSTR target,
1739 BSTR data,
1740 IXMLDOMProcessingInstruction** pi )
1742 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1743 IXMLDOMNode *node;
1744 VARIANT type;
1745 HRESULT hr;
1747 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1749 if (!pi) return E_INVALIDARG;
1751 *pi = NULL;
1753 V_VT(&type) = VT_I1;
1754 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1756 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1757 if (hr == S_OK)
1759 xmlnode *node_obj;
1761 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1762 node_obj = get_node_obj(node);
1763 hr = node_set_content(node_obj, data);
1765 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1766 IXMLDOMNode_Release(node);
1769 return hr;
1773 static HRESULT WINAPI domdoc_createAttribute(
1774 IXMLDOMDocument3 *iface,
1775 BSTR name,
1776 IXMLDOMAttribute** attribute )
1778 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1779 IXMLDOMNode *node;
1780 VARIANT type;
1781 HRESULT hr;
1783 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1785 if (!attribute || !name) return E_INVALIDARG;
1787 V_VT(&type) = VT_I1;
1788 V_I1(&type) = NODE_ATTRIBUTE;
1790 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1791 if (hr == S_OK)
1793 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1794 IXMLDOMNode_Release(node);
1797 return hr;
1801 static HRESULT WINAPI domdoc_createEntityReference(
1802 IXMLDOMDocument3 *iface,
1803 BSTR name,
1804 IXMLDOMEntityReference** entityref )
1806 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1807 IXMLDOMNode *node;
1808 VARIANT type;
1809 HRESULT hr;
1811 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1813 if (!entityref) return E_INVALIDARG;
1815 *entityref = NULL;
1817 V_VT(&type) = VT_I1;
1818 V_I1(&type) = NODE_ENTITY_REFERENCE;
1820 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1821 if (hr == S_OK)
1823 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1824 IXMLDOMNode_Release(node);
1827 return hr;
1830 xmlChar* tagName_to_XPath(const BSTR tagName)
1832 xmlChar *query, *tmp;
1833 static const xmlChar mod_pre[] = "*[local-name()='";
1834 static const xmlChar mod_post[] = "']";
1835 static const xmlChar prefix[] = "descendant::";
1836 const WCHAR *tokBegin, *tokEnd;
1837 int len;
1839 query = xmlStrdup(prefix);
1841 tokBegin = tagName;
1842 while (tokBegin && *tokBegin)
1844 switch (*tokBegin)
1846 case '/':
1847 query = xmlStrcat(query, BAD_CAST "/");
1848 ++tokBegin;
1849 break;
1850 case '*':
1851 query = xmlStrcat(query, BAD_CAST "*");
1852 ++tokBegin;
1853 break;
1854 default:
1855 query = xmlStrcat(query, mod_pre);
1856 tokEnd = tokBegin;
1857 while (*tokEnd && *tokEnd != '/')
1858 ++tokEnd;
1859 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1860 tmp = xmlMalloc(len);
1861 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1862 query = xmlStrncat(query, tmp, len);
1863 xmlFree(tmp);
1864 tokBegin = tokEnd;
1865 query = xmlStrcat(query, mod_post);
1869 return query;
1872 static HRESULT WINAPI domdoc_getElementsByTagName(
1873 IXMLDOMDocument3 *iface,
1874 BSTR tagName,
1875 IXMLDOMNodeList** resultList )
1877 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1878 xmlChar *query;
1879 HRESULT hr;
1880 BOOL XPath;
1882 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1884 if (!tagName || !resultList) return E_INVALIDARG;
1886 XPath = This->properties->XPath;
1887 This->properties->XPath = TRUE;
1888 query = tagName_to_XPath(tagName);
1889 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1890 xmlFree(query);
1891 This->properties->XPath = XPath;
1893 return hr;
1896 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1898 VARIANT tmp;
1899 HRESULT hr;
1901 VariantInit(&tmp);
1902 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1903 if(FAILED(hr))
1904 return E_INVALIDARG;
1906 *type = V_I4(&tmp);
1908 return S_OK;
1911 static HRESULT WINAPI domdoc_createNode(
1912 IXMLDOMDocument3 *iface,
1913 VARIANT Type,
1914 BSTR name,
1915 BSTR namespaceURI,
1916 IXMLDOMNode** node )
1918 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1919 DOMNodeType node_type;
1920 xmlNodePtr xmlnode;
1921 xmlChar *xml_name, *href;
1922 HRESULT hr;
1924 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1926 if(!node) return E_INVALIDARG;
1928 hr = get_node_type(Type, &node_type);
1929 if(FAILED(hr)) return hr;
1931 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1932 FIXME("nodes with namespaces currently not supported.\n");
1934 TRACE("node_type %d\n", node_type);
1936 /* exit earlier for types that need name */
1937 switch(node_type)
1939 case NODE_ELEMENT:
1940 case NODE_ATTRIBUTE:
1941 case NODE_ENTITY_REFERENCE:
1942 case NODE_PROCESSING_INSTRUCTION:
1943 if (!name || *name == 0) return E_FAIL;
1944 break;
1945 default:
1946 break;
1949 xml_name = xmlchar_from_wchar(name);
1950 /* prevent empty href to be allocated */
1951 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1953 switch(node_type)
1955 case NODE_ELEMENT:
1957 xmlChar *local, *prefix;
1959 local = xmlSplitQName2(xml_name, &prefix);
1961 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1963 /* allow to create default namespace xmlns= */
1964 if (local || (href && *href))
1966 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1967 xmlSetNs(xmlnode, ns);
1970 xmlFree(local);
1971 xmlFree(prefix);
1973 break;
1975 case NODE_ATTRIBUTE:
1976 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1977 break;
1978 case NODE_TEXT:
1979 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1980 break;
1981 case NODE_CDATA_SECTION:
1982 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1983 break;
1984 case NODE_ENTITY_REFERENCE:
1985 xmlnode = xmlNewReference(get_doc(This), xml_name);
1986 break;
1987 case NODE_PROCESSING_INSTRUCTION:
1988 #ifdef HAVE_XMLNEWDOCPI
1989 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1990 #else
1991 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1992 xmlnode = NULL;
1993 #endif
1994 break;
1995 case NODE_COMMENT:
1996 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1997 break;
1998 case NODE_DOCUMENT_FRAGMENT:
1999 xmlnode = xmlNewDocFragment(get_doc(This));
2000 break;
2001 /* unsupported types */
2002 case NODE_DOCUMENT:
2003 case NODE_DOCUMENT_TYPE:
2004 case NODE_ENTITY:
2005 case NODE_NOTATION:
2006 heap_free(xml_name);
2007 return E_INVALIDARG;
2008 default:
2009 FIXME("unhandled node type %d\n", node_type);
2010 xmlnode = NULL;
2011 break;
2014 *node = create_node(xmlnode);
2015 heap_free(xml_name);
2016 heap_free(href);
2018 if(*node)
2020 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2021 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2022 return S_OK;
2025 return E_FAIL;
2028 static HRESULT WINAPI domdoc_nodeFromID(
2029 IXMLDOMDocument3 *iface,
2030 BSTR idString,
2031 IXMLDOMNode** node )
2033 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2034 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2035 return E_NOTIMPL;
2038 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2040 domdoc *This = obj;
2041 xmlDocPtr xmldoc;
2043 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2044 if(xmldoc) {
2045 xmldoc->_private = create_priv();
2046 return attach_xmldoc(This, xmldoc);
2049 return S_OK;
2052 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2054 bsc_t *bsc;
2055 HRESULT hr;
2057 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2058 if(FAILED(hr))
2059 return hr;
2061 if(This->bsc) {
2062 hr = detach_bsc(This->bsc);
2063 if(FAILED(hr))
2064 return hr;
2067 This->bsc = bsc;
2068 return S_OK;
2071 static HRESULT WINAPI domdoc_load(
2072 IXMLDOMDocument3 *iface,
2073 VARIANT source,
2074 VARIANT_BOOL* isSuccessful )
2076 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2077 LPWSTR filename = NULL;
2078 HRESULT hr = S_FALSE;
2079 xmlDocPtr xmldoc;
2081 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2083 if (!isSuccessful)
2084 return E_POINTER;
2085 *isSuccessful = VARIANT_FALSE;
2087 assert( &This->node );
2089 switch( V_VT(&source) )
2091 case VT_BSTR:
2092 filename = V_BSTR(&source);
2093 break;
2094 case VT_BSTR|VT_BYREF:
2095 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2096 filename = *V_BSTRREF(&source);
2097 break;
2098 case VT_ARRAY|VT_UI1:
2100 SAFEARRAY *psa = V_ARRAY(&source);
2101 char *str;
2102 LONG len;
2103 UINT dim = SafeArrayGetDim(psa);
2105 switch (dim)
2107 case 0:
2108 ERR("SAFEARRAY == NULL\n");
2109 hr = This->error = E_INVALIDARG;
2110 break;
2111 case 1:
2112 /* Only takes UTF-8 strings.
2113 * NOT NULL-terminated. */
2114 SafeArrayAccessData(psa, (void**)&str);
2115 SafeArrayGetUBound(psa, 1, &len);
2117 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2119 hr = This->error = S_OK;
2120 *isSuccessful = VARIANT_TRUE;
2121 TRACE("parsed document %p\n", xmldoc);
2123 else
2125 This->error = E_FAIL;
2126 TRACE("failed to parse document\n");
2129 SafeArrayUnaccessData(psa);
2131 if(xmldoc)
2133 xmldoc->_private = create_priv();
2134 return attach_xmldoc(This, xmldoc);
2136 break;
2137 default:
2138 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2139 hr = This->error = E_NOTIMPL;
2142 break;
2143 case VT_UNKNOWN:
2145 ISequentialStream *stream = NULL;
2146 IXMLDOMDocument3 *newdoc = NULL;
2148 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2150 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2151 if(hr == S_OK)
2153 if(newdoc)
2155 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2157 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2158 xmldoc->_private = create_priv();
2159 hr = attach_xmldoc(This, xmldoc);
2161 if(SUCCEEDED(hr))
2162 *isSuccessful = VARIANT_TRUE;
2164 return hr;
2168 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2169 if (FAILED(hr))
2170 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2172 if (hr == S_OK)
2174 hr = domdoc_load_from_stream(This, stream);
2175 if (hr == S_OK)
2176 *isSuccessful = VARIANT_TRUE;
2177 ISequentialStream_Release(stream);
2178 return hr;
2181 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2182 break;
2184 default:
2185 FIXME("VT type not supported (%d)\n", V_VT(&source));
2188 if ( filename )
2190 IMoniker *mon;
2192 hr = create_moniker_from_url( filename, &mon);
2193 if ( SUCCEEDED(hr) )
2195 hr = domdoc_load_moniker( This, mon );
2196 IMoniker_Release(mon);
2199 if ( FAILED(hr) )
2200 This->error = E_FAIL;
2201 else
2203 hr = This->error = S_OK;
2204 *isSuccessful = VARIANT_TRUE;
2208 if(!filename || FAILED(hr)) {
2209 xmldoc = xmlNewDoc(NULL);
2210 xmldoc->_private = create_priv();
2211 hr = attach_xmldoc(This, xmldoc);
2212 if(SUCCEEDED(hr))
2213 hr = S_FALSE;
2216 TRACE("ret (%d)\n", hr);
2218 return hr;
2222 static HRESULT WINAPI domdoc_get_readyState(
2223 IXMLDOMDocument3 *iface,
2224 LONG *value )
2226 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2227 FIXME("stub! (%p)->(%p)\n", This, value);
2229 if (!value)
2230 return E_INVALIDARG;
2232 *value = READYSTATE_COMPLETE;
2233 return S_OK;
2237 static HRESULT WINAPI domdoc_get_parseError(
2238 IXMLDOMDocument3 *iface,
2239 IXMLDOMParseError** errorObj )
2241 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2242 static const WCHAR err[] = {'e','r','r','o','r',0};
2243 BSTR error_string = NULL;
2245 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2247 if(This->error)
2248 error_string = SysAllocString(err);
2250 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2251 if(!*errorObj) return E_OUTOFMEMORY;
2252 return S_OK;
2256 static HRESULT WINAPI domdoc_get_url(
2257 IXMLDOMDocument3 *iface,
2258 BSTR* urlString )
2260 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2261 FIXME("(%p)->(%p)\n", This, urlString);
2262 return E_NOTIMPL;
2266 static HRESULT WINAPI domdoc_get_async(
2267 IXMLDOMDocument3 *iface,
2268 VARIANT_BOOL* isAsync )
2270 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2272 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2273 *isAsync = This->async;
2274 return S_OK;
2278 static HRESULT WINAPI domdoc_put_async(
2279 IXMLDOMDocument3 *iface,
2280 VARIANT_BOOL isAsync )
2282 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2284 TRACE("(%p)->(%d)\n", This, isAsync);
2285 This->async = isAsync;
2286 return S_OK;
2290 static HRESULT WINAPI domdoc_abort(
2291 IXMLDOMDocument3 *iface )
2293 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2294 FIXME("%p\n", This);
2295 return E_NOTIMPL;
2298 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2299 static HRESULT WINAPI domdoc_loadXML(
2300 IXMLDOMDocument3 *iface,
2301 BSTR data,
2302 VARIANT_BOOL* isSuccessful )
2304 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2305 xmlDocPtr xmldoc = NULL;
2306 HRESULT hr = S_FALSE, hr2;
2308 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2310 assert ( &This->node );
2312 if ( isSuccessful )
2314 *isSuccessful = VARIANT_FALSE;
2316 if (data)
2318 WCHAR *ptr = data;
2320 /* skip leading spaces if needed */
2321 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2322 while (*ptr && isspaceW(*ptr)) ptr++;
2324 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2325 if ( !xmldoc )
2327 This->error = E_FAIL;
2328 TRACE("failed to parse document\n");
2330 else
2332 hr = This->error = S_OK;
2333 *isSuccessful = VARIANT_TRUE;
2334 TRACE("parsed document %p\n", xmldoc);
2339 if(!xmldoc)
2340 xmldoc = xmlNewDoc(NULL);
2341 xmldoc->_private = create_priv();
2342 hr2 = attach_xmldoc(This, xmldoc);
2343 if( FAILED(hr2) )
2344 hr = hr2;
2346 return hr;
2349 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2351 DWORD written = -1;
2353 if(!WriteFile(ctx, buffer, len, &written, NULL))
2355 WARN("write error\n");
2356 return -1;
2358 else
2359 return written;
2362 static int XMLCALL domdoc_save_closecallback(void *ctx)
2364 return CloseHandle(ctx) ? 0 : -1;
2367 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2369 ULONG written = 0;
2370 HRESULT hr;
2372 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2373 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2374 if (hr != S_OK)
2376 WARN("stream write error: 0x%08x\n", hr);
2377 return -1;
2379 else
2380 return len;
2383 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2385 IStream_Release((IStream*)ctx);
2386 return 0;
2389 static HRESULT WINAPI domdoc_save(
2390 IXMLDOMDocument3 *iface,
2391 VARIANT destination )
2393 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2394 xmlSaveCtxtPtr ctx = NULL;
2395 xmlNodePtr xmldecl;
2396 HRESULT ret = S_OK;
2398 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2400 switch (V_VT(&destination))
2402 case VT_UNKNOWN:
2404 IUnknown *pUnk = V_UNKNOWN(&destination);
2405 IXMLDOMDocument3 *document;
2406 IStream *stream;
2408 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2409 if(ret == S_OK)
2411 VARIANT_BOOL success;
2412 BSTR xml;
2414 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2415 if(ret == S_OK)
2417 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2418 SysFreeString(xml);
2421 IXMLDOMDocument3_Release(document);
2422 return ret;
2425 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2426 if(ret == S_OK)
2428 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2429 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2430 domdoc_stream_save_closecallback, stream, NULL, options);
2432 if(!ctx)
2434 IStream_Release(stream);
2435 return E_FAIL;
2439 break;
2441 case VT_BSTR:
2442 case VT_BSTR | VT_BYREF:
2444 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2446 /* save with file path */
2447 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2448 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2449 if( handle == INVALID_HANDLE_VALUE )
2451 WARN("failed to create file\n");
2452 return E_FAIL;
2455 /* disable top XML declaration */
2456 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2457 handle, NULL, options);
2458 if (!ctx)
2460 CloseHandle(handle);
2461 return E_FAIL;
2464 break;
2466 default:
2467 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2468 return S_FALSE;
2471 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2472 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2473 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2475 /* will release resources through close callback */
2476 xmlSaveClose(ctx);
2478 return ret;
2481 static HRESULT WINAPI domdoc_get_validateOnParse(
2482 IXMLDOMDocument3 *iface,
2483 VARIANT_BOOL* isValidating )
2485 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2486 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2487 *isValidating = This->validating;
2488 return S_OK;
2492 static HRESULT WINAPI domdoc_put_validateOnParse(
2493 IXMLDOMDocument3 *iface,
2494 VARIANT_BOOL isValidating )
2496 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2497 TRACE("(%p)->(%d)\n", This, isValidating);
2498 This->validating = isValidating;
2499 return S_OK;
2503 static HRESULT WINAPI domdoc_get_resolveExternals(
2504 IXMLDOMDocument3 *iface,
2505 VARIANT_BOOL* isResolving )
2507 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2508 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2509 *isResolving = This->resolving;
2510 return S_OK;
2514 static HRESULT WINAPI domdoc_put_resolveExternals(
2515 IXMLDOMDocument3 *iface,
2516 VARIANT_BOOL isResolving )
2518 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2519 TRACE("(%p)->(%d)\n", This, isResolving);
2520 This->resolving = isResolving;
2521 return S_OK;
2525 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2526 IXMLDOMDocument3 *iface,
2527 VARIANT_BOOL* isPreserving )
2529 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2530 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2531 *isPreserving = This->properties->preserving;
2532 return S_OK;
2536 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2537 IXMLDOMDocument3 *iface,
2538 VARIANT_BOOL isPreserving )
2540 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2541 TRACE("(%p)->(%d)\n", This, isPreserving);
2542 This->properties->preserving = isPreserving;
2543 return S_OK;
2547 static HRESULT WINAPI domdoc_put_onreadystatechange(
2548 IXMLDOMDocument3 *iface,
2549 VARIANT event )
2551 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2553 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2554 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2558 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2560 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2561 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2562 return E_NOTIMPL;
2565 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2567 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2568 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2569 return E_NOTIMPL;
2572 static HRESULT WINAPI domdoc_get_namespaces(
2573 IXMLDOMDocument3* iface,
2574 IXMLDOMSchemaCollection** collection )
2576 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2577 HRESULT hr;
2579 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2581 if (!collection) return E_POINTER;
2583 if (!This->namespaces)
2585 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2586 if (hr != S_OK) return hr;
2588 hr = cache_from_doc_ns(This->namespaces, &This->node);
2589 if (hr != S_OK)
2590 release_namespaces(This);
2593 if (This->namespaces)
2594 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2595 &IID_IXMLDOMSchemaCollection, (void**)collection);
2597 return hr;
2600 static HRESULT WINAPI domdoc_get_schemas(
2601 IXMLDOMDocument3* iface,
2602 VARIANT* schema )
2604 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2605 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2606 HRESULT hr = S_FALSE;
2608 TRACE("(%p)->(%p)\n", This, schema);
2610 V_VT(schema) = VT_NULL;
2611 /* just to reset pointer part, cause that's what application is expected to use */
2612 V_DISPATCH(schema) = NULL;
2614 if(cur_schema)
2616 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2617 if(SUCCEEDED(hr))
2618 V_VT(schema) = VT_DISPATCH;
2620 return hr;
2623 static HRESULT WINAPI domdoc_putref_schemas(
2624 IXMLDOMDocument3* iface,
2625 VARIANT schema)
2627 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2628 HRESULT hr = E_FAIL;
2629 IXMLDOMSchemaCollection2* new_schema = NULL;
2631 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2632 switch(V_VT(&schema))
2634 case VT_UNKNOWN:
2635 if (V_UNKNOWN(&schema))
2637 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2638 break;
2640 /* fallthrough */
2641 case VT_DISPATCH:
2642 if (V_DISPATCH(&schema))
2644 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2645 break;
2647 /* fallthrough */
2648 case VT_NULL:
2649 case VT_EMPTY:
2650 hr = S_OK;
2651 break;
2653 default:
2654 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2657 if(SUCCEEDED(hr))
2659 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2660 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2663 return hr;
2666 static inline BOOL is_wellformed(xmlDocPtr doc)
2668 #ifdef HAVE_XMLDOC_PROPERTIES
2669 return doc->properties & XML_DOC_WELLFORMED;
2670 #else
2671 /* Not a full check, but catches the worst violations */
2672 xmlNodePtr child;
2673 int root = 0;
2675 for (child = doc->children; child != NULL; child = child->next)
2677 switch (child->type)
2679 case XML_ELEMENT_NODE:
2680 if (++root > 1)
2681 return FALSE;
2682 break;
2683 case XML_TEXT_NODE:
2684 case XML_CDATA_SECTION_NODE:
2685 return FALSE;
2686 break;
2687 default:
2688 break;
2692 return root == 1;
2693 #endif
2696 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2698 va_list ap;
2699 va_start(ap, msg);
2700 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2701 va_end(ap);
2704 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2706 va_list ap;
2707 va_start(ap, msg);
2708 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2709 va_end(ap);
2712 static HRESULT WINAPI domdoc_validateNode(
2713 IXMLDOMDocument3* iface,
2714 IXMLDOMNode* node,
2715 IXMLDOMParseError** err)
2717 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2718 LONG state, err_code = 0;
2719 HRESULT hr = S_OK;
2720 int validated = 0;
2722 TRACE("(%p)->(%p, %p)\n", This, node, err);
2723 IXMLDOMDocument3_get_readyState(iface, &state);
2724 if (state != READYSTATE_COMPLETE)
2726 if (err)
2727 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2728 return E_PENDING;
2731 if (!node)
2733 if (err)
2734 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2735 return E_POINTER;
2738 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2740 if (err)
2741 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2742 return E_FAIL;
2745 if (!is_wellformed(get_doc(This)))
2747 ERR("doc not well-formed\n");
2748 if (err)
2749 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2750 return S_FALSE;
2753 /* DTD validation */
2754 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2756 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2757 vctx->error = validate_error;
2758 vctx->warning = validate_warning;
2759 ++validated;
2761 if (!((node == (IXMLDOMNode*)iface)?
2762 xmlValidateDocument(vctx, get_doc(This)) :
2763 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2765 /* TODO: get a real error code here */
2766 TRACE("DTD validation failed\n");
2767 err_code = E_XML_INVALID;
2768 hr = S_FALSE;
2770 xmlFreeValidCtxt(vctx);
2773 /* Schema validation */
2774 if (hr == S_OK && This->properties->schemaCache != NULL)
2777 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2778 if (SUCCEEDED(hr))
2780 ++validated;
2781 /* TODO: get a real error code here */
2782 if (hr == S_OK)
2784 TRACE("schema validation succeeded\n");
2786 else
2788 ERR("schema validation failed\n");
2789 err_code = E_XML_INVALID;
2792 else
2794 /* not really OK, just didn't find a schema for the ns */
2795 hr = S_OK;
2799 if (!validated)
2801 ERR("no DTD or schema found\n");
2802 err_code = E_XML_NODTD;
2803 hr = S_FALSE;
2806 if (err)
2807 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2809 return hr;
2812 static HRESULT WINAPI domdoc_validate(
2813 IXMLDOMDocument3* iface,
2814 IXMLDOMParseError** err)
2816 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2817 TRACE("(%p)->(%p)\n", This, err);
2818 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2821 static HRESULT WINAPI domdoc_setProperty(
2822 IXMLDOMDocument3* iface,
2823 BSTR p,
2824 VARIANT value)
2826 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2828 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2830 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2832 VARIANT varStr;
2833 HRESULT hr;
2834 BSTR bstr;
2836 V_VT(&varStr) = VT_EMPTY;
2837 if (V_VT(&value) != VT_BSTR)
2839 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2840 return hr;
2841 bstr = V_BSTR(&varStr);
2843 else
2844 bstr = V_BSTR(&value);
2846 hr = S_OK;
2847 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2848 This->properties->XPath = TRUE;
2849 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2850 This->properties->XPath = FALSE;
2851 else
2852 hr = E_FAIL;
2854 VariantClear(&varStr);
2855 return hr;
2857 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2859 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2860 struct list *pNsList;
2861 VARIANT varStr;
2862 HRESULT hr;
2863 BSTR bstr;
2865 V_VT(&varStr) = VT_EMPTY;
2866 if (V_VT(&value) != VT_BSTR)
2868 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2869 return hr;
2870 bstr = V_BSTR(&varStr);
2872 else
2873 bstr = V_BSTR(&value);
2875 hr = S_OK;
2877 pNsList = &(This->properties->selectNsList);
2878 clear_selectNsList(pNsList);
2879 heap_free(nsStr);
2880 nsStr = xmlchar_from_wchar(bstr);
2882 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2884 This->properties->selectNsStr = nsStr;
2885 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2886 if (bstr && *bstr)
2888 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2889 select_ns_entry* ns_entry = NULL;
2890 xmlXPathContextPtr ctx;
2892 ctx = xmlXPathNewContext(This->node.node->doc);
2893 pTokBegin = nsStr;
2895 /* skip leading spaces */
2896 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2897 *pTokBegin == '\t' || *pTokBegin == '\r')
2898 ++pTokBegin;
2900 for (; *pTokBegin; pTokBegin = pTokEnd)
2902 if (ns_entry)
2903 memset(ns_entry, 0, sizeof(select_ns_entry));
2904 else
2905 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2907 while (*pTokBegin == ' ')
2908 ++pTokBegin;
2909 pTokEnd = pTokBegin;
2910 while (*pTokEnd != ' ' && *pTokEnd != 0)
2911 ++pTokEnd;
2913 /* so it failed to advance which means we've got some trailing spaces */
2914 if (pTokEnd == pTokBegin) break;
2916 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2918 hr = E_FAIL;
2919 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2920 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2921 continue;
2924 pTokBegin += 5;
2925 if (*pTokBegin == '=')
2927 /*valid for XSLPattern?*/
2928 FIXME("Setting default xmlns not supported - skipping.\n");
2929 continue;
2931 else if (*pTokBegin == ':')
2933 ns_entry->prefix = ++pTokBegin;
2934 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2937 if (pTokInner == pTokEnd)
2939 hr = E_FAIL;
2940 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2941 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2942 continue;
2945 ns_entry->prefix_end = *pTokInner;
2946 *pTokInner = 0;
2947 ++pTokInner;
2949 if (pTokEnd-pTokInner > 1 &&
2950 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2951 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2953 ns_entry->href = ++pTokInner;
2954 ns_entry->href_end = *(pTokEnd-1);
2955 *(pTokEnd-1) = 0;
2956 list_add_tail(pNsList, &ns_entry->entry);
2957 /*let libxml figure out if they're valid from here ;)*/
2958 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2960 hr = E_FAIL;
2962 ns_entry = NULL;
2963 continue;
2965 else
2967 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2968 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2969 list_add_tail(pNsList, &ns_entry->entry);
2971 ns_entry = NULL;
2972 hr = E_FAIL;
2973 continue;
2976 else
2978 hr = E_FAIL;
2979 continue;
2982 heap_free(ns_entry);
2983 xmlXPathFreeContext(ctx);
2986 VariantClear(&varStr);
2987 return hr;
2989 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2990 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2991 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2993 /* Ignore */
2994 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
2995 return S_OK;
2998 FIXME("Unknown property %s\n", debugstr_w(p));
2999 return E_FAIL;
3002 static HRESULT WINAPI domdoc_getProperty(
3003 IXMLDOMDocument3* iface,
3004 BSTR p,
3005 VARIANT* var)
3007 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3009 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3011 if (!var)
3012 return E_INVALIDARG;
3014 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3016 V_VT(var) = VT_BSTR;
3017 V_BSTR(var) = This->properties->XPath ?
3018 SysAllocString(PropValueXPathW) :
3019 SysAllocString(PropValueXSLPatternW);
3020 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3022 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3024 int lenA, lenW;
3025 BSTR rebuiltStr, cur;
3026 const xmlChar *nsStr;
3027 struct list *pNsList;
3028 select_ns_entry* pNsEntry;
3030 V_VT(var) = VT_BSTR;
3031 nsStr = This->properties->selectNsStr;
3032 pNsList = &This->properties->selectNsList;
3033 lenA = This->properties->selectNsStr_len;
3034 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3035 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3036 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3037 cur = rebuiltStr;
3038 /* this is fine because all of the chars that end tokens are ASCII*/
3039 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3041 while (*cur != 0) ++cur;
3042 if (pNsEntry->prefix_end)
3044 *cur = pNsEntry->prefix_end;
3045 while (*cur != 0) ++cur;
3048 if (pNsEntry->href_end)
3050 *cur = pNsEntry->href_end;
3053 V_BSTR(var) = SysAllocString(rebuiltStr);
3054 heap_free(rebuiltStr);
3055 return S_OK;
3058 FIXME("Unknown property %s\n", debugstr_w(p));
3059 return E_FAIL;
3062 static HRESULT WINAPI domdoc_importNode(
3063 IXMLDOMDocument3* iface,
3064 IXMLDOMNode* node,
3065 VARIANT_BOOL deep,
3066 IXMLDOMNode** clone)
3068 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3069 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3070 return E_NOTIMPL;
3073 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3075 domdoc_QueryInterface,
3076 domdoc_AddRef,
3077 domdoc_Release,
3078 domdoc_GetTypeInfoCount,
3079 domdoc_GetTypeInfo,
3080 domdoc_GetIDsOfNames,
3081 domdoc_Invoke,
3082 domdoc_get_nodeName,
3083 domdoc_get_nodeValue,
3084 domdoc_put_nodeValue,
3085 domdoc_get_nodeType,
3086 domdoc_get_parentNode,
3087 domdoc_get_childNodes,
3088 domdoc_get_firstChild,
3089 domdoc_get_lastChild,
3090 domdoc_get_previousSibling,
3091 domdoc_get_nextSibling,
3092 domdoc_get_attributes,
3093 domdoc_insertBefore,
3094 domdoc_replaceChild,
3095 domdoc_removeChild,
3096 domdoc_appendChild,
3097 domdoc_hasChildNodes,
3098 domdoc_get_ownerDocument,
3099 domdoc_cloneNode,
3100 domdoc_get_nodeTypeString,
3101 domdoc_get_text,
3102 domdoc_put_text,
3103 domdoc_get_specified,
3104 domdoc_get_definition,
3105 domdoc_get_nodeTypedValue,
3106 domdoc_put_nodeTypedValue,
3107 domdoc_get_dataType,
3108 domdoc_put_dataType,
3109 domdoc_get_xml,
3110 domdoc_transformNode,
3111 domdoc_selectNodes,
3112 domdoc_selectSingleNode,
3113 domdoc_get_parsed,
3114 domdoc_get_namespaceURI,
3115 domdoc_get_prefix,
3116 domdoc_get_baseName,
3117 domdoc_transformNodeToObject,
3118 domdoc_get_doctype,
3119 domdoc_get_implementation,
3120 domdoc_get_documentElement,
3121 domdoc_put_documentElement,
3122 domdoc_createElement,
3123 domdoc_createDocumentFragment,
3124 domdoc_createTextNode,
3125 domdoc_createComment,
3126 domdoc_createCDATASection,
3127 domdoc_createProcessingInstruction,
3128 domdoc_createAttribute,
3129 domdoc_createEntityReference,
3130 domdoc_getElementsByTagName,
3131 domdoc_createNode,
3132 domdoc_nodeFromID,
3133 domdoc_load,
3134 domdoc_get_readyState,
3135 domdoc_get_parseError,
3136 domdoc_get_url,
3137 domdoc_get_async,
3138 domdoc_put_async,
3139 domdoc_abort,
3140 domdoc_loadXML,
3141 domdoc_save,
3142 domdoc_get_validateOnParse,
3143 domdoc_put_validateOnParse,
3144 domdoc_get_resolveExternals,
3145 domdoc_put_resolveExternals,
3146 domdoc_get_preserveWhiteSpace,
3147 domdoc_put_preserveWhiteSpace,
3148 domdoc_put_onreadystatechange,
3149 domdoc_put_onDataAvailable,
3150 domdoc_put_onTransformNode,
3151 domdoc_get_namespaces,
3152 domdoc_get_schemas,
3153 domdoc_putref_schemas,
3154 domdoc_validate,
3155 domdoc_setProperty,
3156 domdoc_getProperty,
3157 domdoc_validateNode,
3158 domdoc_importNode
3161 /* IConnectionPointContainer */
3162 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3163 REFIID riid, void **ppv)
3165 domdoc *This = impl_from_IConnectionPointContainer(iface);
3166 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3169 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3171 domdoc *This = impl_from_IConnectionPointContainer(iface);
3172 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3175 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3177 domdoc *This = impl_from_IConnectionPointContainer(iface);
3178 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3181 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3182 IEnumConnectionPoints **ppEnum)
3184 domdoc *This = impl_from_IConnectionPointContainer(iface);
3185 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3186 return E_NOTIMPL;
3189 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3190 REFIID riid, IConnectionPoint **cp)
3192 domdoc *This = impl_from_IConnectionPointContainer(iface);
3193 ConnectionPoint *iter;
3195 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3197 *cp = NULL;
3199 for(iter = This->cp_list; iter; iter = iter->next)
3201 if (IsEqualGUID(iter->iid, riid))
3202 *cp = &iter->IConnectionPoint_iface;
3205 if (*cp)
3207 IConnectionPoint_AddRef(*cp);
3208 return S_OK;
3211 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3212 return CONNECT_E_NOCONNECTION;
3216 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3218 ConnectionPointContainer_QueryInterface,
3219 ConnectionPointContainer_AddRef,
3220 ConnectionPointContainer_Release,
3221 ConnectionPointContainer_EnumConnectionPoints,
3222 ConnectionPointContainer_FindConnectionPoint
3225 /* IConnectionPoint */
3226 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3227 REFIID riid, void **ppv)
3229 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3231 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3233 *ppv = NULL;
3235 if (IsEqualGUID(&IID_IUnknown, riid) ||
3236 IsEqualGUID(&IID_IConnectionPoint, riid))
3238 *ppv = iface;
3241 if (*ppv)
3243 IConnectionPoint_AddRef(iface);
3244 return S_OK;
3247 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3248 return E_NOINTERFACE;
3251 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3253 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3254 return IConnectionPointContainer_AddRef(This->container);
3257 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3259 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3260 return IConnectionPointContainer_Release(This->container);
3263 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3265 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3267 TRACE("(%p)->(%p)\n", This, iid);
3269 if (!iid) return E_POINTER;
3271 *iid = *This->iid;
3272 return S_OK;
3275 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3276 IConnectionPointContainer **container)
3278 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3280 TRACE("(%p)->(%p)\n", This, container);
3282 if (!container) return E_POINTER;
3284 *container = This->container;
3285 IConnectionPointContainer_AddRef(*container);
3286 return S_OK;
3289 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3290 DWORD *cookie)
3292 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3293 IUnknown *sink;
3294 HRESULT hr;
3295 DWORD i;
3297 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3299 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3300 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3301 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3302 if(FAILED(hr))
3303 return CONNECT_E_CANNOTCONNECT;
3305 if(This->sinks)
3307 for (i = 0; i < This->sinks_size; i++)
3308 if (!This->sinks[i].unk)
3309 break;
3311 if (i == This->sinks_size)
3312 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3314 else
3316 This->sinks = heap_alloc(sizeof(*This->sinks));
3317 This->sinks_size = 1;
3318 i = 0;
3321 This->sinks[i].unk = sink;
3322 if (cookie)
3323 *cookie = i+1;
3325 return S_OK;
3328 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3330 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3332 TRACE("(%p)->(%d)\n", This, cookie);
3334 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3335 return CONNECT_E_NOCONNECTION;
3337 IUnknown_Release(This->sinks[cookie-1].unk);
3338 This->sinks[cookie-1].unk = NULL;
3340 return S_OK;
3343 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3344 IEnumConnections **ppEnum)
3346 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3347 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3348 return E_NOTIMPL;
3351 static const IConnectionPointVtbl ConnectionPointVtbl =
3353 ConnectionPoint_QueryInterface,
3354 ConnectionPoint_AddRef,
3355 ConnectionPoint_Release,
3356 ConnectionPoint_GetConnectionInterface,
3357 ConnectionPoint_GetConnectionPointContainer,
3358 ConnectionPoint_Advise,
3359 ConnectionPoint_Unadvise,
3360 ConnectionPoint_EnumConnections
3363 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3365 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3366 cp->doc = doc;
3367 cp->iid = riid;
3368 cp->sinks = NULL;
3369 cp->sinks_size = 0;
3371 cp->next = doc->cp_list;
3372 doc->cp_list = cp;
3374 cp->container = &doc->IConnectionPointContainer_iface;
3377 /* domdoc implementation of IObjectWithSite */
3378 static HRESULT WINAPI
3379 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3381 domdoc *This = impl_from_IObjectWithSite(iface);
3382 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3385 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3387 domdoc *This = impl_from_IObjectWithSite(iface);
3388 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3391 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3393 domdoc *This = impl_from_IObjectWithSite(iface);
3394 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3397 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3399 domdoc *This = impl_from_IObjectWithSite(iface);
3401 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3403 if ( !This->site )
3404 return E_FAIL;
3406 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3409 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3411 domdoc *This = impl_from_IObjectWithSite(iface);
3413 TRACE("(%p)->(%p)\n", iface, punk);
3415 if(!punk)
3417 if(This->site)
3419 IUnknown_Release( This->site );
3420 This->site = NULL;
3423 return S_OK;
3426 IUnknown_AddRef( punk );
3428 if(This->site)
3429 IUnknown_Release( This->site );
3431 This->site = punk;
3433 return S_OK;
3436 static const IObjectWithSiteVtbl domdocObjectSite =
3438 domdoc_ObjectWithSite_QueryInterface,
3439 domdoc_ObjectWithSite_AddRef,
3440 domdoc_ObjectWithSite_Release,
3441 domdoc_ObjectWithSite_SetSite,
3442 domdoc_ObjectWithSite_GetSite
3445 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3447 domdoc *This = impl_from_IObjectSafety(iface);
3448 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3451 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3453 domdoc *This = impl_from_IObjectSafety(iface);
3454 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3457 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3459 domdoc *This = impl_from_IObjectSafety(iface);
3460 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3463 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3465 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3466 DWORD *supported, DWORD *enabled)
3468 domdoc *This = impl_from_IObjectSafety(iface);
3470 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3472 if(!supported || !enabled) return E_POINTER;
3474 *supported = SAFETY_SUPPORTED_OPTIONS;
3475 *enabled = This->safeopt;
3477 return S_OK;
3480 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3481 DWORD mask, DWORD enabled)
3483 domdoc *This = impl_from_IObjectSafety(iface);
3484 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3486 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3487 return E_FAIL;
3489 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3491 return S_OK;
3494 #undef SAFETY_SUPPORTED_OPTIONS
3496 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3497 domdoc_Safety_QueryInterface,
3498 domdoc_Safety_AddRef,
3499 domdoc_Safety_Release,
3500 domdoc_Safety_GetInterfaceSafetyOptions,
3501 domdoc_Safety_SetInterfaceSafetyOptions
3504 static const tid_t domdoc_iface_tids[] = {
3505 IXMLDOMDocument3_tid,
3509 static dispex_static_data_t domdoc_dispex = {
3510 NULL,
3511 IXMLDOMDocument3_tid,
3512 NULL,
3513 domdoc_iface_tids
3516 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3518 domdoc *doc;
3520 doc = heap_alloc( sizeof (*doc) );
3521 if( !doc )
3522 return E_OUTOFMEMORY;
3524 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3525 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3526 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3527 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3528 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3529 doc->ref = 1;
3530 doc->async = VARIANT_TRUE;
3531 doc->validating = 0;
3532 doc->resolving = 0;
3533 doc->properties = properties_from_xmlDocPtr(xmldoc);
3534 doc->error = S_OK;
3535 doc->site = NULL;
3536 doc->safeopt = 0;
3537 doc->bsc = NULL;
3538 doc->cp_list = NULL;
3539 doc->namespaces = NULL;
3540 memset(doc->events, 0, sizeof(doc->events));
3542 /* events connection points */
3543 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3544 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3545 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3547 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3548 &domdoc_dispex);
3550 *document = &doc->IXMLDOMDocument3_iface;
3552 TRACE("returning iface %p\n", *document);
3553 return S_OK;
3556 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3558 xmlDocPtr xmldoc;
3559 HRESULT hr;
3561 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3563 xmldoc = xmlNewDoc(NULL);
3564 if(!xmldoc)
3565 return E_OUTOFMEMORY;
3567 xmldoc_init(xmldoc, version);
3569 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3570 if(FAILED(hr))
3572 free_properties(properties_from_xmlDocPtr(xmldoc));
3573 heap_free(xmldoc->_private);
3574 xmlFreeDoc(xmldoc);
3575 return hr;
3578 return hr;
3581 IUnknown* create_domdoc( xmlNodePtr document )
3583 void* pObj = NULL;
3584 HRESULT hr;
3586 TRACE("(%p)\n", document);
3588 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3589 if (FAILED(hr))
3590 return NULL;
3592 return pObj;
3595 #else
3597 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3599 MESSAGE("This program tried to use a DOMDocument object, but\n"
3600 "libxml2 support was not present at compile time.\n");
3601 return E_NOTIMPL;
3604 #endif