wineps: Fix a couple of typos in the path painting function.
[wine/testsucceed.git] / dlls / msxml3 / domdoc.c
blob30b63deafd1f0c75f753407738fa369b35f97cc2
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 _domdoc_properties {
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 ISupportErrorInfo ISupportErrorInfo_iface;
127 IConnectionPointContainer IConnectionPointContainer_iface;
128 LONG ref;
129 VARIANT_BOOL async;
130 VARIANT_BOOL validating;
131 VARIANT_BOOL resolving;
132 domdoc_properties* properties;
133 bsc_t *bsc;
134 HRESULT error;
136 /* IPersistStream */
137 IStream *stream;
139 /* IObjectWithSite*/
140 IUnknown *site;
142 /* IObjectSafety */
143 DWORD safeopt;
145 /* connection list */
146 ConnectionPoint *cp_list;
147 ConnectionPoint cp_domdocevents;
148 ConnectionPoint cp_propnotif;
149 ConnectionPoint cp_dispatch;
151 /* events */
152 IDispatch *events[EVENTID_LAST];
155 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
157 IDispatch *disp;
159 switch (V_VT(v))
161 case VT_UNKNOWN:
162 if (V_UNKNOWN(v))
163 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
164 else
165 disp = NULL;
166 break;
167 case VT_DISPATCH:
168 disp = V_DISPATCH(v);
169 if (disp) IDispatch_AddRef(disp);
170 break;
171 default:
172 return DISP_E_TYPEMISMATCH;
175 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
176 doc->events[eid] = disp;
178 return S_OK;
181 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
183 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
187 In native windows, the whole lifetime management of XMLDOMNodes is
188 managed automatically using reference counts. Wine emulates that by
189 maintaining a reference count to the document that is increased for
190 each IXMLDOMNode pointer passed out for this document. If all these
191 pointers are gone, the document is unreachable and gets freed, that
192 is, all nodes in the tree of the document get freed.
194 You are able to create nodes that are associated to a document (in
195 fact, in msxml's XMLDOM model, all nodes are associated to a document),
196 but not in the tree of that document, for example using the createFoo
197 functions from IXMLDOMDocument. These nodes do not get cleaned up
198 by libxml, so we have to do it ourselves.
200 To catch these nodes, a list of "orphan nodes" is introduced.
201 It contains pointers to all roots of node trees that are
202 associated with the document without being part of the document
203 tree. All nodes with parent==NULL (except for the document root nodes)
204 should be in the orphan node list of their document. All orphan nodes
205 get freed together with the document itself.
208 typedef struct _xmldoc_priv {
209 LONG refs;
210 struct list orphans;
211 domdoc_properties* properties;
212 } xmldoc_priv;
214 typedef struct _orphan_entry {
215 struct list entry;
216 xmlNode * node;
217 } orphan_entry;
219 typedef struct _select_ns_entry {
220 struct list entry;
221 xmlChar const* prefix;
222 xmlChar prefix_end;
223 xmlChar const* href;
224 xmlChar href_end;
225 } select_ns_entry;
227 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
229 return doc->_private;
232 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
234 return priv_from_xmlDocPtr(doc)->properties;
237 BOOL is_xpathmode(const xmlDocPtr doc)
239 return properties_from_xmlDocPtr(doc)->XPath;
242 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
244 properties_from_xmlDocPtr(doc)->XPath = xpath;
247 int registerNamespaces(xmlXPathContextPtr ctxt)
249 int n = 0;
250 const select_ns_entry* ns = NULL;
251 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
253 TRACE("(%p)\n", ctxt);
255 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
257 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
258 ++n;
261 return n;
264 static inline void clear_selectNsList(struct list* pNsList)
266 select_ns_entry *ns, *ns2;
267 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
269 heap_free( ns );
271 list_init(pNsList);
274 static xmldoc_priv * create_priv(void)
276 xmldoc_priv *priv;
277 priv = heap_alloc( sizeof (*priv) );
279 if (priv)
281 priv->refs = 0;
282 list_init( &priv->orphans );
283 priv->properties = NULL;
286 return priv;
289 static domdoc_properties * create_properties(MSXML_VERSION version)
291 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
293 list_init(&properties->selectNsList);
294 properties->preserving = VARIANT_FALSE;
295 properties->schemaCache = NULL;
296 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
297 properties->selectNsStr_len = 0;
299 /* properties that are dependent on object versions */
300 properties->version = version;
301 properties->XPath = (version == MSXML4 || version == MSXML6);
303 return properties;
306 static domdoc_properties* copy_properties(domdoc_properties const* properties)
308 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
309 select_ns_entry const* ns = NULL;
310 select_ns_entry* new_ns = NULL;
311 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
312 ptrdiff_t offset;
314 if (pcopy)
316 pcopy->version = properties->version;
317 pcopy->preserving = properties->preserving;
318 pcopy->schemaCache = properties->schemaCache;
319 if (pcopy->schemaCache)
320 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
321 pcopy->XPath = properties->XPath;
322 pcopy->selectNsStr_len = properties->selectNsStr_len;
323 list_init( &pcopy->selectNsList );
324 pcopy->selectNsStr = heap_alloc(len);
325 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
326 offset = pcopy->selectNsStr - properties->selectNsStr;
328 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
330 new_ns = heap_alloc(sizeof(select_ns_entry));
331 memcpy(new_ns, ns, sizeof(select_ns_entry));
332 new_ns->href += offset;
333 new_ns->prefix += offset;
334 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
339 return pcopy;
342 static void free_properties(domdoc_properties* properties)
344 if (properties)
346 if (properties->schemaCache)
347 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
348 clear_selectNsList(&properties->selectNsList);
349 heap_free((xmlChar*)properties->selectNsStr);
350 heap_free(properties);
354 /* links a "<?xml" node as a first child */
355 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
357 assert(doc != NULL);
358 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
361 /* unlinks a first "<?xml" child if it was created */
362 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
364 xmlNodePtr node;
366 assert(doc != NULL);
368 if (doc->standalone != -1)
370 node = doc->children;
371 xmlUnlinkNode( node );
373 else
374 node = NULL;
376 return node;
379 BOOL is_preserving_whitespace(xmlNodePtr node)
381 domdoc_properties* properties = NULL;
382 /* during parsing the xmlDoc._private stuff is not there */
383 if (priv_from_xmlDocPtr(node->doc))
384 properties = properties_from_xmlDocPtr(node->doc);
385 return ((properties && properties->preserving == VARIANT_TRUE) ||
386 xmlNodeGetSpacePreserve(node) == 1);
389 static inline BOOL strn_isspace(xmlChar const* str, int len)
391 for (; str && len > 0 && *str; ++str, --len)
392 if (!isspace(*str))
393 break;
395 return len == 0;
398 static void sax_characters(void *ctx, const xmlChar *ch, int len)
400 xmlParserCtxtPtr ctxt;
401 const domdoc *This;
403 ctxt = (xmlParserCtxtPtr) ctx;
404 This = (const domdoc*) ctxt->_private;
406 if (ctxt->node)
408 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
409 if (!This->properties->preserving &&
410 !is_preserving_whitespace(ctxt->node) &&
411 strn_isspace(ch, len))
412 return;
415 xmlSAX2Characters(ctxt, ch, len);
418 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
420 va_list ap;
421 va_start(ap, msg);
422 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
423 va_end(ap);
426 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
428 va_list ap;
429 va_start(ap, msg);
430 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
431 va_end(ap);
434 static void sax_serror(void* ctx, xmlErrorPtr err)
436 LIBXML2_CALLBACK_SERROR(doparse, err);
439 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
441 xmlDocPtr doc = NULL;
442 xmlParserCtxtPtr pctx;
443 static xmlSAXHandler sax_handler = {
444 xmlSAX2InternalSubset, /* internalSubset */
445 xmlSAX2IsStandalone, /* isStandalone */
446 xmlSAX2HasInternalSubset, /* hasInternalSubset */
447 xmlSAX2HasExternalSubset, /* hasExternalSubset */
448 xmlSAX2ResolveEntity, /* resolveEntity */
449 xmlSAX2GetEntity, /* getEntity */
450 xmlSAX2EntityDecl, /* entityDecl */
451 xmlSAX2NotationDecl, /* notationDecl */
452 xmlSAX2AttributeDecl, /* attributeDecl */
453 xmlSAX2ElementDecl, /* elementDecl */
454 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
455 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
456 xmlSAX2StartDocument, /* startDocument */
457 xmlSAX2EndDocument, /* endDocument */
458 xmlSAX2StartElement, /* startElement */
459 xmlSAX2EndElement, /* endElement */
460 xmlSAX2Reference, /* reference */
461 sax_characters, /* characters */
462 sax_characters, /* ignorableWhitespace */
463 xmlSAX2ProcessingInstruction, /* processingInstruction */
464 xmlSAX2Comment, /* comment */
465 sax_warning, /* warning */
466 sax_error, /* error */
467 sax_error, /* fatalError */
468 xmlSAX2GetParameterEntity, /* getParameterEntity */
469 xmlSAX2CDataBlock, /* cdataBlock */
470 xmlSAX2ExternalSubset, /* externalSubset */
471 0, /* initialized */
472 NULL, /* _private */
473 xmlSAX2StartElementNs, /* startElementNs */
474 xmlSAX2EndElementNs, /* endElementNs */
475 sax_serror /* serror */
477 xmlInitParser();
479 pctx = xmlCreateMemoryParserCtxt(ptr, len);
480 if (!pctx)
482 ERR("Failed to create parser context\n");
483 return NULL;
486 if (pctx->sax) xmlFree(pctx->sax);
487 pctx->sax = &sax_handler;
488 pctx->_private = This;
489 pctx->recovery = 0;
491 if (encoding != XML_CHAR_ENCODING_NONE)
492 xmlSwitchEncoding(pctx, encoding);
494 xmlParseDocument(pctx);
496 if (pctx->wellFormed)
498 doc = pctx->myDoc;
500 else
502 xmlFreeDoc(pctx->myDoc);
503 pctx->myDoc = NULL;
505 pctx->sax = NULL;
506 xmlFreeParserCtxt(pctx);
508 /* TODO: put this in one of the SAX callbacks */
509 /* create first child as a <?xml...?> */
510 if (doc && doc->standalone != -1)
512 xmlNodePtr node;
513 char buff[30];
514 xmlChar *xmlbuff = (xmlChar*)buff;
516 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
518 /* version attribute can't be omitted */
519 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
520 xmlNodeAddContent( node, xmlbuff );
522 if (doc->encoding)
524 sprintf(buff, " encoding=\"%s\"", doc->encoding);
525 xmlNodeAddContent( node, xmlbuff );
528 if (doc->standalone != -2)
530 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
531 xmlNodeAddContent( node, xmlbuff );
534 xmldoc_link_xmldecl( doc, node );
537 return doc;
540 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
542 doc->_private = create_priv();
543 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
546 LONG xmldoc_add_ref(xmlDocPtr doc)
548 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
549 TRACE("(%p)->(%d)\n", doc, ref);
550 return ref;
553 LONG xmldoc_release(xmlDocPtr doc)
555 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
556 LONG ref = InterlockedDecrement(&priv->refs);
557 TRACE("(%p)->(%d)\n", doc, ref);
558 if(ref == 0)
560 orphan_entry *orphan, *orphan2;
561 TRACE("freeing docptr %p\n", doc);
563 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
565 xmlFreeNode( orphan->node );
566 heap_free( orphan );
568 free_properties(priv->properties);
569 heap_free(doc->_private);
571 xmlFreeDoc(doc);
574 return ref;
577 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
579 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
580 orphan_entry *entry;
582 entry = heap_alloc( sizeof (*entry) );
583 if(!entry)
584 return E_OUTOFMEMORY;
586 entry->node = node;
587 list_add_head( &priv->orphans, &entry->entry );
588 return S_OK;
591 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
593 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
594 orphan_entry *entry, *entry2;
596 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
598 if( entry->node == node )
600 list_remove( &entry->entry );
601 heap_free( entry );
602 return S_OK;
606 return S_FALSE;
609 static inline xmlDocPtr get_doc( domdoc *This )
611 return (xmlDocPtr)This->node.node;
614 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
616 if(This->node.node)
618 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
619 if (xmldoc_release(get_doc(This)) != 0)
620 priv_from_xmlDocPtr(get_doc(This))->properties =
621 copy_properties(This->properties);
624 This->node.node = (xmlNodePtr) xml;
626 if(This->node.node)
628 xmldoc_add_ref(get_doc(This));
629 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
632 return S_OK;
635 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
637 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
640 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
642 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
645 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
647 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
650 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
652 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
655 static inline domdoc *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
657 return CONTAINING_RECORD(iface, domdoc, ISupportErrorInfo_iface);
660 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
662 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
665 /************************************************************************
666 * domdoc implementation of IPersistStream.
668 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
669 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
671 domdoc* This = impl_from_IPersistStreamInit(iface);
672 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
675 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
676 IPersistStreamInit *iface)
678 domdoc* This = impl_from_IPersistStreamInit(iface);
679 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
682 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
683 IPersistStreamInit *iface)
685 domdoc* This = impl_from_IPersistStreamInit(iface);
686 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
689 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
690 IPersistStreamInit *iface, CLSID *classid)
692 domdoc* This = impl_from_IPersistStreamInit(iface);
693 TRACE("(%p)->(%p)\n", This, classid);
695 if(!classid)
696 return E_POINTER;
698 *classid = *DOMDocument_version(This->properties->version);
700 return S_OK;
703 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
704 IPersistStreamInit *iface)
706 domdoc *This = impl_from_IPersistStreamInit(iface);
707 FIXME("(%p): stub!\n", This);
708 return S_FALSE;
711 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
712 IPersistStreamInit *iface, LPSTREAM pStm)
714 domdoc *This = impl_from_IPersistStreamInit(iface);
715 HRESULT hr;
716 HGLOBAL hglobal;
717 DWORD read, written, len;
718 BYTE buf[4096];
719 char *ptr;
720 xmlDocPtr xmldoc = NULL;
722 TRACE("(%p)->(%p)\n", This, pStm);
724 if (!pStm)
725 return E_INVALIDARG;
727 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
728 if (FAILED(hr))
729 return hr;
733 IStream_Read(pStm, buf, sizeof(buf), &read);
734 hr = IStream_Write(This->stream, buf, read, &written);
735 } while(SUCCEEDED(hr) && written != 0 && read != 0);
737 if (FAILED(hr))
739 ERR("Failed to copy stream\n");
740 return hr;
743 hr = GetHGlobalFromStream(This->stream, &hglobal);
744 if (FAILED(hr))
745 return hr;
747 len = GlobalSize(hglobal);
748 ptr = GlobalLock(hglobal);
749 if (len != 0)
750 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
751 GlobalUnlock(hglobal);
753 if (!xmldoc)
755 ERR("Failed to parse xml\n");
756 return E_FAIL;
759 xmldoc->_private = create_priv();
761 return attach_xmldoc(This, xmldoc);
764 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
765 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
767 domdoc *This = impl_from_IPersistStreamInit(iface);
768 BSTR xmlString;
769 HRESULT hr;
771 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
773 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
774 if(hr == S_OK)
776 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
778 hr = IStream_Write( stream, xmlString, len, NULL );
779 SysFreeString(xmlString);
782 TRACE("ret 0x%08x\n", hr);
784 return hr;
787 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
788 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
790 domdoc *This = impl_from_IPersistStreamInit(iface);
791 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
792 return E_NOTIMPL;
795 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
796 IPersistStreamInit *iface)
798 domdoc *This = impl_from_IPersistStreamInit(iface);
799 TRACE("(%p)\n", This);
800 return S_OK;
803 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
805 domdoc_IPersistStreamInit_QueryInterface,
806 domdoc_IPersistStreamInit_AddRef,
807 domdoc_IPersistStreamInit_Release,
808 domdoc_IPersistStreamInit_GetClassID,
809 domdoc_IPersistStreamInit_IsDirty,
810 domdoc_IPersistStreamInit_Load,
811 domdoc_IPersistStreamInit_Save,
812 domdoc_IPersistStreamInit_GetSizeMax,
813 domdoc_IPersistStreamInit_InitNew
816 /* ISupportErrorInfo interface */
817 static HRESULT WINAPI support_error_QueryInterface(
818 ISupportErrorInfo *iface,
819 REFIID riid, void** ppvObj )
821 domdoc *This = impl_from_ISupportErrorInfo(iface);
822 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
825 static ULONG WINAPI support_error_AddRef(
826 ISupportErrorInfo *iface )
828 domdoc *This = impl_from_ISupportErrorInfo(iface);
829 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
832 static ULONG WINAPI support_error_Release(
833 ISupportErrorInfo *iface )
835 domdoc *This = impl_from_ISupportErrorInfo(iface);
836 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
839 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
840 ISupportErrorInfo *iface,
841 REFIID riid )
843 FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
844 return S_FALSE;
847 static const struct ISupportErrorInfoVtbl support_error_vtbl =
849 support_error_QueryInterface,
850 support_error_AddRef,
851 support_error_Release,
852 support_error_InterfaceSupportsErrorInfo
855 /* IXMLDOMDocument2 interface */
856 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
858 domdoc *This = impl_from_IXMLDOMDocument3( iface );
860 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
862 *ppvObject = NULL;
864 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
865 IsEqualGUID( riid, &IID_IDispatch ) ||
866 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
867 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
868 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
869 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
871 *ppvObject = iface;
873 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
874 IsEqualGUID(&IID_IPersistStreamInit, riid))
876 *ppvObject = &This->IPersistStreamInit_iface;
878 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
880 *ppvObject = &This->IObjectWithSite_iface;
882 else if (IsEqualGUID(&IID_IObjectSafety, riid))
884 *ppvObject = &This->IObjectSafety_iface;
886 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
888 *ppvObject = &This->ISupportErrorInfo_iface;
890 else if(node_query_interface(&This->node, riid, ppvObject))
892 return *ppvObject ? S_OK : E_NOINTERFACE;
894 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
896 *ppvObject = &This->IConnectionPointContainer_iface;
898 else
900 TRACE("interface %s not implemented\n", debugstr_guid(riid));
901 return E_NOINTERFACE;
904 IUnknown_AddRef((IUnknown*)*ppvObject);
906 return S_OK;
910 static ULONG WINAPI domdoc_AddRef(
911 IXMLDOMDocument3 *iface )
913 domdoc *This = impl_from_IXMLDOMDocument3( iface );
914 ULONG ref = InterlockedIncrement( &This->ref );
915 TRACE("(%p)->(%d)\n", This, ref );
916 return ref;
920 static ULONG WINAPI domdoc_Release(
921 IXMLDOMDocument3 *iface )
923 domdoc *This = impl_from_IXMLDOMDocument3( iface );
924 LONG ref = InterlockedDecrement( &This->ref );
926 TRACE("(%p)->(%d)\n", This, ref );
928 if ( ref == 0 )
930 int eid;
932 if(This->bsc)
933 detach_bsc(This->bsc);
935 if (This->site)
936 IUnknown_Release( This->site );
937 destroy_xmlnode(&This->node);
938 if (This->stream)
939 IStream_Release(This->stream);
941 for (eid = 0; eid < EVENTID_LAST; eid++)
942 if (This->events[eid]) IDispatch_Release(This->events[eid]);
944 heap_free(This);
947 return ref;
950 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
952 domdoc *This = impl_from_IXMLDOMDocument3( iface );
954 TRACE("(%p)->(%p)\n", This, pctinfo);
956 *pctinfo = 1;
958 return S_OK;
961 static HRESULT WINAPI domdoc_GetTypeInfo(
962 IXMLDOMDocument3 *iface,
963 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
965 domdoc *This = impl_from_IXMLDOMDocument3( iface );
966 HRESULT hr;
968 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
970 hr = get_typeinfo(IXMLDOMDocument2_tid, ppTInfo);
972 return hr;
975 static HRESULT WINAPI domdoc_GetIDsOfNames(
976 IXMLDOMDocument3 *iface,
977 REFIID riid,
978 LPOLESTR* rgszNames,
979 UINT cNames,
980 LCID lcid,
981 DISPID* rgDispId)
983 domdoc *This = impl_from_IXMLDOMDocument3( iface );
984 ITypeInfo *typeinfo;
985 HRESULT hr;
987 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
988 lcid, rgDispId);
990 if(!rgszNames || cNames == 0 || !rgDispId)
991 return E_INVALIDARG;
993 hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
994 if(SUCCEEDED(hr))
996 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
997 ITypeInfo_Release(typeinfo);
1000 return hr;
1004 static HRESULT WINAPI domdoc_Invoke(
1005 IXMLDOMDocument3 *iface,
1006 DISPID dispIdMember,
1007 REFIID riid,
1008 LCID lcid,
1009 WORD wFlags,
1010 DISPPARAMS* pDispParams,
1011 VARIANT* pVarResult,
1012 EXCEPINFO* pExcepInfo,
1013 UINT* puArgErr)
1015 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1016 ITypeInfo *typeinfo;
1017 HRESULT hr;
1019 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1020 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1022 hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
1023 if(SUCCEEDED(hr))
1025 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMDocument3_iface, dispIdMember, wFlags,
1026 pDispParams, pVarResult, pExcepInfo, puArgErr);
1027 ITypeInfo_Release(typeinfo);
1030 return hr;
1034 static HRESULT WINAPI domdoc_get_nodeName(
1035 IXMLDOMDocument3 *iface,
1036 BSTR* name )
1038 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1040 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1042 TRACE("(%p)->(%p)\n", This, name);
1044 return return_bstr(documentW, name);
1048 static HRESULT WINAPI domdoc_get_nodeValue(
1049 IXMLDOMDocument3 *iface,
1050 VARIANT* value )
1052 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1054 TRACE("(%p)->(%p)\n", This, value);
1056 if(!value)
1057 return E_INVALIDARG;
1059 V_VT(value) = VT_NULL;
1060 V_BSTR(value) = NULL; /* tests show that we should do this */
1061 return S_FALSE;
1065 static HRESULT WINAPI domdoc_put_nodeValue(
1066 IXMLDOMDocument3 *iface,
1067 VARIANT value)
1069 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1070 TRACE("(%p)->(v%d)\n", This, V_VT(&value));
1071 return E_FAIL;
1075 static HRESULT WINAPI domdoc_get_nodeType(
1076 IXMLDOMDocument3 *iface,
1077 DOMNodeType* type )
1079 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1081 TRACE("(%p)->(%p)\n", This, type);
1083 *type = NODE_DOCUMENT;
1084 return S_OK;
1088 static HRESULT WINAPI domdoc_get_parentNode(
1089 IXMLDOMDocument3 *iface,
1090 IXMLDOMNode** parent )
1092 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1094 TRACE("(%p)->(%p)\n", This, parent);
1096 return node_get_parent(&This->node, parent);
1100 static HRESULT WINAPI domdoc_get_childNodes(
1101 IXMLDOMDocument3 *iface,
1102 IXMLDOMNodeList** childList )
1104 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1106 TRACE("(%p)->(%p)\n", This, childList);
1108 return node_get_child_nodes(&This->node, childList);
1112 static HRESULT WINAPI domdoc_get_firstChild(
1113 IXMLDOMDocument3 *iface,
1114 IXMLDOMNode** firstChild )
1116 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1118 TRACE("(%p)->(%p)\n", This, firstChild);
1120 return node_get_first_child(&This->node, firstChild);
1124 static HRESULT WINAPI domdoc_get_lastChild(
1125 IXMLDOMDocument3 *iface,
1126 IXMLDOMNode** lastChild )
1128 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1130 TRACE("(%p)->(%p)\n", This, lastChild);
1132 return node_get_last_child(&This->node, lastChild);
1136 static HRESULT WINAPI domdoc_get_previousSibling(
1137 IXMLDOMDocument3 *iface,
1138 IXMLDOMNode** previousSibling )
1140 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1142 TRACE("(%p)->(%p)\n", This, previousSibling);
1144 return return_null_node(previousSibling);
1148 static HRESULT WINAPI domdoc_get_nextSibling(
1149 IXMLDOMDocument3 *iface,
1150 IXMLDOMNode** nextSibling )
1152 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1154 TRACE("(%p)->(%p)\n", This, nextSibling);
1156 return return_null_node(nextSibling);
1160 static HRESULT WINAPI domdoc_get_attributes(
1161 IXMLDOMDocument3 *iface,
1162 IXMLDOMNamedNodeMap** attributeMap )
1164 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1166 TRACE("(%p)->(%p)\n", This, attributeMap);
1168 return return_null_ptr((void**)attributeMap);
1172 static HRESULT WINAPI domdoc_insertBefore(
1173 IXMLDOMDocument3 *iface,
1174 IXMLDOMNode* newChild,
1175 VARIANT refChild,
1176 IXMLDOMNode** outNewChild )
1178 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1180 TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1182 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1186 static HRESULT WINAPI domdoc_replaceChild(
1187 IXMLDOMDocument3 *iface,
1188 IXMLDOMNode* newChild,
1189 IXMLDOMNode* oldChild,
1190 IXMLDOMNode** outOldChild)
1192 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1194 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1196 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1200 static HRESULT WINAPI domdoc_removeChild(
1201 IXMLDOMDocument3 *iface,
1202 IXMLDOMNode *child,
1203 IXMLDOMNode **oldChild)
1205 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1206 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1207 return node_remove_child(&This->node, child, oldChild);
1211 static HRESULT WINAPI domdoc_appendChild(
1212 IXMLDOMDocument3 *iface,
1213 IXMLDOMNode *child,
1214 IXMLDOMNode **outChild)
1216 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1217 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1218 return node_append_child(&This->node, child, outChild);
1222 static HRESULT WINAPI domdoc_hasChildNodes(
1223 IXMLDOMDocument3 *iface,
1224 VARIANT_BOOL *ret)
1226 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1227 TRACE("(%p)->(%p)\n", This, ret);
1228 return node_has_childnodes(&This->node, ret);
1232 static HRESULT WINAPI domdoc_get_ownerDocument(
1233 IXMLDOMDocument3 *iface,
1234 IXMLDOMDocument **doc)
1236 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1237 TRACE("(%p)->(%p)\n", This, doc);
1238 return node_get_owner_doc(&This->node, doc);
1242 static HRESULT WINAPI domdoc_cloneNode(
1243 IXMLDOMDocument3 *iface,
1244 VARIANT_BOOL deep,
1245 IXMLDOMNode** outNode)
1247 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1248 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1249 return node_clone( &This->node, deep, outNode );
1253 static HRESULT WINAPI domdoc_get_nodeTypeString(
1254 IXMLDOMDocument3 *iface,
1255 BSTR *p)
1257 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1258 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1260 TRACE("(%p)->(%p)\n", This, p);
1262 return return_bstr(documentW, p);
1266 static HRESULT WINAPI domdoc_get_text(
1267 IXMLDOMDocument3 *iface,
1268 BSTR *p)
1270 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1271 TRACE("(%p)->(%p)\n", This, p);
1272 return node_get_text(&This->node, p);
1276 static HRESULT WINAPI domdoc_put_text(
1277 IXMLDOMDocument3 *iface,
1278 BSTR text )
1280 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1281 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1282 return E_FAIL;
1286 static HRESULT WINAPI domdoc_get_specified(
1287 IXMLDOMDocument3 *iface,
1288 VARIANT_BOOL* isSpecified )
1290 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1291 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1292 *isSpecified = VARIANT_TRUE;
1293 return S_OK;
1297 static HRESULT WINAPI domdoc_get_definition(
1298 IXMLDOMDocument3 *iface,
1299 IXMLDOMNode** definitionNode )
1301 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1302 FIXME("(%p)->(%p)\n", This, definitionNode);
1303 return E_NOTIMPL;
1307 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1308 IXMLDOMDocument3 *iface,
1309 VARIANT* v )
1311 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1312 TRACE("(%p)->(%p)\n", This, v);
1313 return return_null_var(v);
1316 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1317 IXMLDOMDocument3 *iface,
1318 VARIANT typedValue )
1320 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1321 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1322 return E_NOTIMPL;
1326 static HRESULT WINAPI domdoc_get_dataType(
1327 IXMLDOMDocument3 *iface,
1328 VARIANT* typename )
1330 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1331 TRACE("(%p)->(%p)\n", This, typename);
1332 return return_null_var( typename );
1336 static HRESULT WINAPI domdoc_put_dataType(
1337 IXMLDOMDocument3 *iface,
1338 BSTR dataTypeName )
1340 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1342 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1344 if(!dataTypeName)
1345 return E_INVALIDARG;
1347 return E_FAIL;
1350 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1352 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1355 static HRESULT WINAPI domdoc_get_xml(
1356 IXMLDOMDocument3 *iface,
1357 BSTR* p)
1359 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1360 xmlSaveCtxtPtr ctxt;
1361 xmlBufferPtr buf;
1362 int options;
1363 long ret;
1365 TRACE("(%p)->(%p)\n", This, p);
1367 if(!p)
1368 return E_INVALIDARG;
1370 *p = NULL;
1372 buf = xmlBufferCreate();
1373 if(!buf)
1374 return E_OUTOFMEMORY;
1376 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1377 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1379 if(!ctxt)
1381 xmlBufferFree(buf);
1382 return E_OUTOFMEMORY;
1385 ret = xmlSaveDoc(ctxt, get_doc(This));
1386 /* flushes on close */
1387 xmlSaveClose(ctxt);
1389 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1390 if(ret != -1 && xmlBufferLength(buf) > 0)
1392 BSTR content;
1394 content = bstr_from_xmlChar(xmlBufferContent(buf));
1395 content = EnsureCorrectEOL(content);
1397 *p = content;
1399 else
1401 *p = SysAllocStringLen(NULL, 0);
1404 xmlBufferFree(buf);
1406 return *p ? S_OK : E_OUTOFMEMORY;
1410 static HRESULT WINAPI domdoc_transformNode(
1411 IXMLDOMDocument3 *iface,
1412 IXMLDOMNode *node,
1413 BSTR *p)
1415 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1416 TRACE("(%p)->(%p %p)\n", This, node, p);
1417 return node_transform_node(&This->node, node, p);
1421 static HRESULT WINAPI domdoc_selectNodes(
1422 IXMLDOMDocument3 *iface,
1423 BSTR p,
1424 IXMLDOMNodeList **outList)
1426 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1427 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1428 return node_select_nodes(&This->node, p, outList);
1432 static HRESULT WINAPI domdoc_selectSingleNode(
1433 IXMLDOMDocument3 *iface,
1434 BSTR p,
1435 IXMLDOMNode **outNode)
1437 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1438 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1439 return node_select_singlenode(&This->node, p, outNode);
1443 static HRESULT WINAPI domdoc_get_parsed(
1444 IXMLDOMDocument3 *iface,
1445 VARIANT_BOOL* isParsed )
1447 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1448 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1449 *isParsed = VARIANT_TRUE;
1450 return S_OK;
1454 static HRESULT WINAPI domdoc_get_namespaceURI(
1455 IXMLDOMDocument3 *iface,
1456 BSTR* namespaceURI )
1458 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1459 TRACE("(%p)->(%p)\n", This, namespaceURI);
1460 return node_get_namespaceURI(&This->node, namespaceURI);
1464 static HRESULT WINAPI domdoc_get_prefix(
1465 IXMLDOMDocument3 *iface,
1466 BSTR* prefix )
1468 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1469 TRACE("(%p)->(%p)\n", This, prefix);
1470 return return_null_bstr( prefix );
1474 static HRESULT WINAPI domdoc_get_baseName(
1475 IXMLDOMDocument3 *iface,
1476 BSTR* name )
1478 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1479 TRACE("(%p)->(%p)\n", This, name);
1480 return return_null_bstr( name );
1484 static HRESULT WINAPI domdoc_transformNodeToObject(
1485 IXMLDOMDocument3 *iface,
1486 IXMLDOMNode* stylesheet,
1487 VARIANT outputObject)
1489 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1490 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1491 return E_NOTIMPL;
1495 static HRESULT WINAPI domdoc_get_doctype(
1496 IXMLDOMDocument3 *iface,
1497 IXMLDOMDocumentType** doctype )
1499 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1500 IXMLDOMNode *node;
1501 xmlDtdPtr dtd;
1502 HRESULT hr;
1504 TRACE("(%p)->(%p)\n", This, doctype);
1506 if (!doctype) return E_INVALIDARG;
1508 *doctype = NULL;
1510 dtd = xmlGetIntSubset(get_doc(This));
1511 if (!dtd) return S_FALSE;
1513 node = create_node((xmlNodePtr)dtd);
1514 if (!node) return S_FALSE;
1516 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1517 IXMLDOMNode_Release(node);
1519 return hr;
1523 static HRESULT WINAPI domdoc_get_implementation(
1524 IXMLDOMDocument3 *iface,
1525 IXMLDOMImplementation** impl )
1527 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1529 TRACE("(%p)->(%p)\n", This, impl);
1531 if(!impl)
1532 return E_INVALIDARG;
1534 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1536 return S_OK;
1539 static HRESULT WINAPI domdoc_get_documentElement(
1540 IXMLDOMDocument3 *iface,
1541 IXMLDOMElement** DOMElement )
1543 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1544 IXMLDOMNode *element_node;
1545 xmlNodePtr root;
1546 HRESULT hr;
1548 TRACE("(%p)->(%p)\n", This, DOMElement);
1550 if(!DOMElement)
1551 return E_INVALIDARG;
1553 *DOMElement = NULL;
1555 root = xmlDocGetRootElement( get_doc(This) );
1556 if ( !root )
1557 return S_FALSE;
1559 element_node = create_node( root );
1560 if(!element_node) return S_FALSE;
1562 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1563 IXMLDOMNode_Release(element_node);
1565 return hr;
1569 static HRESULT WINAPI domdoc_put_documentElement(
1570 IXMLDOMDocument3 *iface,
1571 IXMLDOMElement* DOMElement )
1573 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1574 IXMLDOMNode *elementNode;
1575 xmlNodePtr oldRoot;
1576 xmlnode *xmlNode;
1577 HRESULT hr;
1579 TRACE("(%p)->(%p)\n", This, DOMElement);
1581 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1582 if(FAILED(hr))
1583 return hr;
1585 xmlNode = get_node_obj( elementNode );
1586 if(!xmlNode) return E_FAIL;
1588 if(!xmlNode->node->parent)
1589 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1590 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1592 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1593 IXMLDOMNode_Release( elementNode );
1595 if(oldRoot)
1596 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1598 return S_OK;
1602 static HRESULT WINAPI domdoc_createElement(
1603 IXMLDOMDocument3 *iface,
1604 BSTR tagname,
1605 IXMLDOMElement** element )
1607 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1608 IXMLDOMNode *node;
1609 VARIANT type;
1610 HRESULT hr;
1612 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1614 if (!element || !tagname) return E_INVALIDARG;
1616 V_VT(&type) = VT_I1;
1617 V_I1(&type) = NODE_ELEMENT;
1619 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1620 if (hr == S_OK)
1622 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1623 IXMLDOMNode_Release(node);
1626 return hr;
1630 static HRESULT WINAPI domdoc_createDocumentFragment(
1631 IXMLDOMDocument3 *iface,
1632 IXMLDOMDocumentFragment** frag )
1634 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1635 IXMLDOMNode *node;
1636 VARIANT type;
1637 HRESULT hr;
1639 TRACE("(%p)->(%p)\n", This, frag);
1641 if (!frag) return E_INVALIDARG;
1643 *frag = NULL;
1645 V_VT(&type) = VT_I1;
1646 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1648 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1649 if (hr == S_OK)
1651 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1652 IXMLDOMNode_Release(node);
1655 return hr;
1659 static HRESULT WINAPI domdoc_createTextNode(
1660 IXMLDOMDocument3 *iface,
1661 BSTR data,
1662 IXMLDOMText** text )
1664 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1665 IXMLDOMNode *node;
1666 VARIANT type;
1667 HRESULT hr;
1669 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1671 if (!text) return E_INVALIDARG;
1673 *text = NULL;
1675 V_VT(&type) = VT_I1;
1676 V_I1(&type) = NODE_TEXT;
1678 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1679 if (hr == S_OK)
1681 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1682 IXMLDOMNode_Release(node);
1683 hr = IXMLDOMText_put_data(*text, data);
1686 return hr;
1690 static HRESULT WINAPI domdoc_createComment(
1691 IXMLDOMDocument3 *iface,
1692 BSTR data,
1693 IXMLDOMComment** comment )
1695 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1696 VARIANT type;
1697 HRESULT hr;
1698 IXMLDOMNode *node;
1700 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1702 if (!comment) return E_INVALIDARG;
1704 *comment = NULL;
1706 V_VT(&type) = VT_I1;
1707 V_I1(&type) = NODE_COMMENT;
1709 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1710 if (hr == S_OK)
1712 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1713 IXMLDOMNode_Release(node);
1714 hr = IXMLDOMComment_put_data(*comment, data);
1717 return hr;
1721 static HRESULT WINAPI domdoc_createCDATASection(
1722 IXMLDOMDocument3 *iface,
1723 BSTR data,
1724 IXMLDOMCDATASection** cdata )
1726 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1727 IXMLDOMNode *node;
1728 VARIANT type;
1729 HRESULT hr;
1731 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1733 if (!cdata) return E_INVALIDARG;
1735 *cdata = NULL;
1737 V_VT(&type) = VT_I1;
1738 V_I1(&type) = NODE_CDATA_SECTION;
1740 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1741 if (hr == S_OK)
1743 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1744 IXMLDOMNode_Release(node);
1745 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1748 return hr;
1752 static HRESULT WINAPI domdoc_createProcessingInstruction(
1753 IXMLDOMDocument3 *iface,
1754 BSTR target,
1755 BSTR data,
1756 IXMLDOMProcessingInstruction** pi )
1758 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1759 IXMLDOMNode *node;
1760 VARIANT type;
1761 HRESULT hr;
1763 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1765 if (!pi) return E_INVALIDARG;
1767 *pi = NULL;
1769 V_VT(&type) = VT_I1;
1770 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1772 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1773 if (hr == S_OK)
1775 xmlnode *node_obj;
1777 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1778 node_obj = get_node_obj(node);
1779 hr = node_set_content(node_obj, data);
1781 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1782 IXMLDOMNode_Release(node);
1785 return hr;
1789 static HRESULT WINAPI domdoc_createAttribute(
1790 IXMLDOMDocument3 *iface,
1791 BSTR name,
1792 IXMLDOMAttribute** attribute )
1794 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1795 IXMLDOMNode *node;
1796 VARIANT type;
1797 HRESULT hr;
1799 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1801 if (!attribute || !name) return E_INVALIDARG;
1803 V_VT(&type) = VT_I1;
1804 V_I1(&type) = NODE_ATTRIBUTE;
1806 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1807 if (hr == S_OK)
1809 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1810 IXMLDOMNode_Release(node);
1813 return hr;
1817 static HRESULT WINAPI domdoc_createEntityReference(
1818 IXMLDOMDocument3 *iface,
1819 BSTR name,
1820 IXMLDOMEntityReference** entityref )
1822 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1823 IXMLDOMNode *node;
1824 VARIANT type;
1825 HRESULT hr;
1827 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1829 if (!entityref) return E_INVALIDARG;
1831 *entityref = NULL;
1833 V_VT(&type) = VT_I1;
1834 V_I1(&type) = NODE_ENTITY_REFERENCE;
1836 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1837 if (hr == S_OK)
1839 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1840 IXMLDOMNode_Release(node);
1843 return hr;
1846 xmlChar* tagName_to_XPath(const BSTR tagName)
1848 xmlChar *query, *tmp;
1849 static const xmlChar mod_pre[] = "*[local-name()='";
1850 static const xmlChar mod_post[] = "']";
1851 static const xmlChar prefix[] = "descendant::";
1852 const WCHAR *tokBegin, *tokEnd;
1853 int len;
1855 query = xmlStrdup(prefix);
1857 tokBegin = tagName;
1858 while (tokBegin && *tokBegin)
1860 switch (*tokBegin)
1862 case '/':
1863 query = xmlStrcat(query, BAD_CAST "/");
1864 ++tokBegin;
1865 break;
1866 case '*':
1867 query = xmlStrcat(query, BAD_CAST "*");
1868 ++tokBegin;
1869 break;
1870 default:
1871 query = xmlStrcat(query, mod_pre);
1872 tokEnd = tokBegin;
1873 while (*tokEnd && *tokEnd != '/')
1874 ++tokEnd;
1875 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1876 tmp = xmlMalloc(len);
1877 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1878 query = xmlStrncat(query, tmp, len);
1879 xmlFree(tmp);
1880 tokBegin = tokEnd;
1881 query = xmlStrcat(query, mod_post);
1885 return query;
1888 static HRESULT WINAPI domdoc_getElementsByTagName(
1889 IXMLDOMDocument3 *iface,
1890 BSTR tagName,
1891 IXMLDOMNodeList** resultList )
1893 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1894 xmlChar *query;
1895 HRESULT hr;
1896 BOOL XPath;
1898 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1900 if (!tagName || !resultList) return E_INVALIDARG;
1902 XPath = This->properties->XPath;
1903 This->properties->XPath = TRUE;
1904 query = tagName_to_XPath(tagName);
1905 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1906 xmlFree(query);
1907 This->properties->XPath = XPath;
1909 return hr;
1912 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1914 VARIANT tmp;
1915 HRESULT hr;
1917 VariantInit(&tmp);
1918 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1919 if(FAILED(hr))
1920 return E_INVALIDARG;
1922 *type = V_I4(&tmp);
1924 return S_OK;
1927 static HRESULT WINAPI domdoc_createNode(
1928 IXMLDOMDocument3 *iface,
1929 VARIANT Type,
1930 BSTR name,
1931 BSTR namespaceURI,
1932 IXMLDOMNode** node )
1934 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1935 DOMNodeType node_type;
1936 xmlNodePtr xmlnode;
1937 xmlChar *xml_name, *href;
1938 HRESULT hr;
1940 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1942 if(!node) return E_INVALIDARG;
1944 hr = get_node_type(Type, &node_type);
1945 if(FAILED(hr)) return hr;
1947 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1948 FIXME("nodes with namespaces currently not supported.\n");
1950 TRACE("node_type %d\n", node_type);
1952 /* exit earlier for types that need name */
1953 switch(node_type)
1955 case NODE_ELEMENT:
1956 case NODE_ATTRIBUTE:
1957 case NODE_ENTITY_REFERENCE:
1958 case NODE_PROCESSING_INSTRUCTION:
1959 if (!name || *name == 0) return E_FAIL;
1960 break;
1961 default:
1962 break;
1965 xml_name = xmlchar_from_wchar(name);
1966 /* prevent empty href to be allocated */
1967 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1969 switch(node_type)
1971 case NODE_ELEMENT:
1973 xmlChar *local, *prefix;
1975 local = xmlSplitQName2(xml_name, &prefix);
1977 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1979 /* allow to create default namespace xmlns= */
1980 if (local || (href && *href))
1982 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1983 xmlSetNs(xmlnode, ns);
1986 xmlFree(local);
1987 xmlFree(prefix);
1989 break;
1991 case NODE_ATTRIBUTE:
1992 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1993 break;
1994 case NODE_TEXT:
1995 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1996 break;
1997 case NODE_CDATA_SECTION:
1998 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1999 break;
2000 case NODE_ENTITY_REFERENCE:
2001 xmlnode = xmlNewReference(get_doc(This), xml_name);
2002 break;
2003 case NODE_PROCESSING_INSTRUCTION:
2004 #ifdef HAVE_XMLNEWDOCPI
2005 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2006 #else
2007 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2008 xmlnode = NULL;
2009 #endif
2010 break;
2011 case NODE_COMMENT:
2012 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2013 break;
2014 case NODE_DOCUMENT_FRAGMENT:
2015 xmlnode = xmlNewDocFragment(get_doc(This));
2016 break;
2017 /* unsupported types */
2018 case NODE_DOCUMENT:
2019 case NODE_DOCUMENT_TYPE:
2020 case NODE_ENTITY:
2021 case NODE_NOTATION:
2022 heap_free(xml_name);
2023 return E_INVALIDARG;
2024 default:
2025 FIXME("unhandled node type %d\n", node_type);
2026 xmlnode = NULL;
2027 break;
2030 *node = create_node(xmlnode);
2031 heap_free(xml_name);
2032 heap_free(href);
2034 if(*node)
2036 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2037 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2038 return S_OK;
2041 return E_FAIL;
2044 static HRESULT WINAPI domdoc_nodeFromID(
2045 IXMLDOMDocument3 *iface,
2046 BSTR idString,
2047 IXMLDOMNode** node )
2049 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2050 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2051 return E_NOTIMPL;
2054 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2056 domdoc *This = obj;
2057 xmlDocPtr xmldoc;
2059 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2060 if(xmldoc) {
2061 xmldoc->_private = create_priv();
2062 return attach_xmldoc(This, xmldoc);
2065 return S_OK;
2068 static HRESULT doread( domdoc *This, LPWSTR filename )
2070 bsc_t *bsc;
2071 HRESULT hr;
2073 hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2074 if(FAILED(hr))
2075 return hr;
2077 if(This->bsc) {
2078 hr = detach_bsc(This->bsc);
2079 if(FAILED(hr))
2080 return hr;
2083 This->bsc = bsc;
2084 return S_OK;
2087 static HRESULT WINAPI domdoc_load(
2088 IXMLDOMDocument3 *iface,
2089 VARIANT source,
2090 VARIANT_BOOL* isSuccessful )
2092 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2093 LPWSTR filename = NULL;
2094 HRESULT hr = S_FALSE;
2095 IXMLDOMDocument3 *pNewDoc = NULL;
2096 IStream *pStream = NULL;
2097 xmlDocPtr xmldoc;
2099 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2101 if (!isSuccessful)
2102 return E_POINTER;
2103 *isSuccessful = VARIANT_FALSE;
2105 assert( &This->node );
2107 switch( V_VT(&source) )
2109 case VT_BSTR:
2110 filename = V_BSTR(&source);
2111 break;
2112 case VT_BSTR|VT_BYREF:
2113 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2114 filename = *V_BSTRREF(&source);
2115 break;
2116 case VT_ARRAY|VT_UI1:
2118 SAFEARRAY *psa = V_ARRAY(&source);
2119 char *str;
2120 LONG len;
2121 UINT dim = SafeArrayGetDim(psa);
2123 switch (dim)
2125 case 0:
2126 ERR("SAFEARRAY == NULL\n");
2127 hr = This->error = E_INVALIDARG;
2128 break;
2129 case 1:
2130 /* Only takes UTF-8 strings.
2131 * NOT NULL-terminated. */
2132 SafeArrayAccessData(psa, (void**)&str);
2133 SafeArrayGetUBound(psa, 1, &len);
2135 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2137 hr = This->error = S_OK;
2138 *isSuccessful = VARIANT_TRUE;
2139 TRACE("parsed document %p\n", xmldoc);
2141 else
2143 This->error = E_FAIL;
2144 TRACE("failed to parse document\n");
2147 SafeArrayUnaccessData(psa);
2149 if(xmldoc)
2151 xmldoc->_private = create_priv();
2152 return attach_xmldoc(This, xmldoc);
2154 break;
2155 default:
2156 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2157 hr = This->error = E_NOTIMPL;
2160 break;
2161 case VT_UNKNOWN:
2162 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2163 if(hr == S_OK)
2165 if(pNewDoc)
2167 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2168 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2169 hr = attach_xmldoc(This, xmldoc);
2171 if(SUCCEEDED(hr))
2172 *isSuccessful = VARIANT_TRUE;
2174 return hr;
2177 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2178 if(hr == S_OK)
2180 IPersistStream *pDocStream;
2181 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2182 if(hr == S_OK)
2184 hr = IPersistStream_Load(pDocStream, pStream);
2185 IStream_Release(pStream);
2186 if(hr == S_OK)
2188 *isSuccessful = VARIANT_TRUE;
2190 TRACE("Using IStream to load Document\n");
2191 return S_OK;
2193 else
2195 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2198 else
2200 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2203 else
2205 /* ISequentialStream */
2206 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2208 break;
2209 default:
2210 FIXME("VT type not supported (%d)\n", V_VT(&source));
2213 if ( filename )
2215 hr = doread( This, filename );
2217 if ( FAILED(hr) )
2218 This->error = E_FAIL;
2219 else
2221 hr = This->error = S_OK;
2222 *isSuccessful = VARIANT_TRUE;
2226 if(!filename || FAILED(hr)) {
2227 xmldoc = xmlNewDoc(NULL);
2228 xmldoc->_private = create_priv();
2229 hr = attach_xmldoc(This, xmldoc);
2230 if(SUCCEEDED(hr))
2231 hr = S_FALSE;
2234 TRACE("ret (%d)\n", hr);
2236 return hr;
2240 static HRESULT WINAPI domdoc_get_readyState(
2241 IXMLDOMDocument3 *iface,
2242 LONG *value )
2244 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2245 FIXME("stub! (%p)->(%p)\n", This, value);
2247 if (!value)
2248 return E_INVALIDARG;
2250 *value = READYSTATE_COMPLETE;
2251 return S_OK;
2255 static HRESULT WINAPI domdoc_get_parseError(
2256 IXMLDOMDocument3 *iface,
2257 IXMLDOMParseError** errorObj )
2259 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2260 static const WCHAR err[] = {'e','r','r','o','r',0};
2261 BSTR error_string = NULL;
2263 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2265 if(This->error)
2266 error_string = SysAllocString(err);
2268 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2269 if(!*errorObj) return E_OUTOFMEMORY;
2270 return S_OK;
2274 static HRESULT WINAPI domdoc_get_url(
2275 IXMLDOMDocument3 *iface,
2276 BSTR* urlString )
2278 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2279 FIXME("(%p)->(%p)\n", This, urlString);
2280 return E_NOTIMPL;
2284 static HRESULT WINAPI domdoc_get_async(
2285 IXMLDOMDocument3 *iface,
2286 VARIANT_BOOL* isAsync )
2288 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2290 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2291 *isAsync = This->async;
2292 return S_OK;
2296 static HRESULT WINAPI domdoc_put_async(
2297 IXMLDOMDocument3 *iface,
2298 VARIANT_BOOL isAsync )
2300 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2302 TRACE("(%p)->(%d)\n", This, isAsync);
2303 This->async = isAsync;
2304 return S_OK;
2308 static HRESULT WINAPI domdoc_abort(
2309 IXMLDOMDocument3 *iface )
2311 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2312 FIXME("%p\n", This);
2313 return E_NOTIMPL;
2317 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2318 static HRESULT WINAPI domdoc_loadXML(
2319 IXMLDOMDocument3 *iface,
2320 BSTR bstrXML,
2321 VARIANT_BOOL* isSuccessful )
2323 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2324 xmlDocPtr xmldoc = NULL;
2325 HRESULT hr = S_FALSE, hr2;
2327 TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2329 assert ( &This->node );
2331 if ( isSuccessful )
2333 *isSuccessful = VARIANT_FALSE;
2335 if ( bstrXML )
2337 xmldoc = doparse(This, (LPCSTR)bstrXML, lstrlenW(bstrXML) * sizeof(*bstrXML), XML_CHAR_ENCODING_UTF16LE);
2338 if ( !xmldoc )
2340 This->error = E_FAIL;
2341 TRACE("failed to parse document\n");
2343 else
2345 hr = This->error = S_OK;
2346 *isSuccessful = VARIANT_TRUE;
2347 TRACE("parsed document %p\n", xmldoc);
2351 if(!xmldoc)
2352 xmldoc = xmlNewDoc(NULL);
2354 xmldoc->_private = create_priv();
2356 hr2 = attach_xmldoc(This, xmldoc);
2357 if( FAILED(hr2) )
2358 hr = hr2;
2360 return hr;
2363 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2365 DWORD written = -1;
2367 if(!WriteFile(ctx, buffer, len, &written, NULL))
2369 WARN("write error\n");
2370 return -1;
2372 else
2373 return written;
2376 static int XMLCALL domdoc_save_closecallback(void *ctx)
2378 return CloseHandle(ctx) ? 0 : -1;
2381 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2383 ULONG written = 0;
2384 HRESULT hr;
2386 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2387 if (hr != S_OK)
2389 WARN("stream write error: 0x%08x\n", hr);
2390 return -1;
2392 else
2393 return written;
2396 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2398 IStream_Release((IStream*)ctx);
2399 return 0;
2402 static HRESULT WINAPI domdoc_save(
2403 IXMLDOMDocument3 *iface,
2404 VARIANT destination )
2406 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2407 xmlSaveCtxtPtr ctx = NULL;
2408 xmlNodePtr xmldecl;
2409 HRESULT ret = S_OK;
2411 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2413 switch (V_VT(&destination))
2415 case VT_UNKNOWN:
2417 IUnknown *pUnk = V_UNKNOWN(&destination);
2418 IXMLDOMDocument2 *document;
2419 IStream *stream;
2421 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2422 if(ret == S_OK)
2424 VARIANT_BOOL success;
2425 BSTR xml;
2427 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2428 if(ret == S_OK)
2430 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2431 SysFreeString(xml);
2434 IXMLDOMDocument3_Release(document);
2435 return ret;
2438 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2439 if(ret == S_OK)
2441 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2442 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2444 if(!ctx)
2446 IStream_Release(stream);
2447 return E_FAIL;
2451 break;
2453 case VT_BSTR:
2454 case VT_BSTR | VT_BYREF:
2456 /* save with file path */
2457 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2458 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2459 if( handle == INVALID_HANDLE_VALUE )
2461 WARN("failed to create file\n");
2462 return E_FAIL;
2465 /* disable top XML declaration */
2466 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2467 handle, NULL, XML_SAVE_NO_DECL);
2468 if (!ctx)
2470 CloseHandle(handle);
2471 return E_FAIL;
2474 break;
2476 default:
2477 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2478 return S_FALSE;
2481 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2482 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2483 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2485 /* will release resources through close callback */
2486 xmlSaveClose(ctx);
2488 return ret;
2491 static HRESULT WINAPI domdoc_get_validateOnParse(
2492 IXMLDOMDocument3 *iface,
2493 VARIANT_BOOL* isValidating )
2495 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2496 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2497 *isValidating = This->validating;
2498 return S_OK;
2502 static HRESULT WINAPI domdoc_put_validateOnParse(
2503 IXMLDOMDocument3 *iface,
2504 VARIANT_BOOL isValidating )
2506 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2507 TRACE("(%p)->(%d)\n", This, isValidating);
2508 This->validating = isValidating;
2509 return S_OK;
2513 static HRESULT WINAPI domdoc_get_resolveExternals(
2514 IXMLDOMDocument3 *iface,
2515 VARIANT_BOOL* isResolving )
2517 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2518 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2519 *isResolving = This->resolving;
2520 return S_OK;
2524 static HRESULT WINAPI domdoc_put_resolveExternals(
2525 IXMLDOMDocument3 *iface,
2526 VARIANT_BOOL isResolving )
2528 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2529 TRACE("(%p)->(%d)\n", This, isResolving);
2530 This->resolving = isResolving;
2531 return S_OK;
2535 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2536 IXMLDOMDocument3 *iface,
2537 VARIANT_BOOL* isPreserving )
2539 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2540 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2541 *isPreserving = This->properties->preserving;
2542 return S_OK;
2546 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2547 IXMLDOMDocument3 *iface,
2548 VARIANT_BOOL isPreserving )
2550 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2551 TRACE("(%p)->(%d)\n", This, isPreserving);
2552 This->properties->preserving = isPreserving;
2553 return S_OK;
2557 static HRESULT WINAPI domdoc_put_onreadystatechange(
2558 IXMLDOMDocument3 *iface,
2559 VARIANT event )
2561 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2563 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2564 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2568 static HRESULT WINAPI domdoc_put_onDataAvailable(
2569 IXMLDOMDocument3 *iface,
2570 VARIANT onDataAvailableSink )
2572 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2573 FIXME("%p\n", This);
2574 return E_NOTIMPL;
2577 static HRESULT WINAPI domdoc_put_onTransformNode(
2578 IXMLDOMDocument3 *iface,
2579 VARIANT onTransformNodeSink )
2581 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2582 FIXME("%p\n", This);
2583 return E_NOTIMPL;
2586 static HRESULT WINAPI domdoc_get_namespaces(
2587 IXMLDOMDocument3* iface,
2588 IXMLDOMSchemaCollection** schemaCollection )
2590 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2591 FIXME("(%p)->(%p)\n", This, schemaCollection);
2592 return E_NOTIMPL;
2595 static HRESULT WINAPI domdoc_get_schemas(
2596 IXMLDOMDocument3* iface,
2597 VARIANT* var1 )
2599 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2600 HRESULT hr = S_FALSE;
2601 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2603 TRACE("(%p)->(%p)\n", This, var1);
2605 VariantInit(var1); /* Test shows we don't call VariantClear here */
2606 V_VT(var1) = VT_NULL;
2608 if(cur_schema)
2610 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2611 if(SUCCEEDED(hr))
2612 V_VT(var1) = VT_DISPATCH;
2614 return hr;
2617 static HRESULT WINAPI domdoc_putref_schemas(
2618 IXMLDOMDocument3* iface,
2619 VARIANT var1)
2621 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2622 HRESULT hr = E_FAIL;
2623 IXMLDOMSchemaCollection2* new_schema = NULL;
2625 FIXME("(%p): semi-stub\n", This);
2626 switch(V_VT(&var1))
2628 case VT_UNKNOWN:
2629 hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2630 break;
2632 case VT_DISPATCH:
2633 hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2634 break;
2636 case VT_NULL:
2637 case VT_EMPTY:
2638 hr = S_OK;
2639 break;
2641 default:
2642 WARN("Can't get schema from vt %x\n", V_VT(&var1));
2645 if(SUCCEEDED(hr))
2647 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2648 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2651 return hr;
2654 static inline BOOL is_wellformed(xmlDocPtr doc)
2656 #ifdef HAVE_XMLDOC_PROPERTIES
2657 return doc->properties & XML_DOC_WELLFORMED;
2658 #else
2659 /* Not a full check, but catches the worst violations */
2660 xmlNodePtr child;
2661 int root = 0;
2663 for (child = doc->children; child != NULL; child = child->next)
2665 switch (child->type)
2667 case XML_ELEMENT_NODE:
2668 if (++root > 1)
2669 return FALSE;
2670 break;
2671 case XML_TEXT_NODE:
2672 case XML_CDATA_SECTION_NODE:
2673 return FALSE;
2674 break;
2675 default:
2676 break;
2680 return root == 1;
2681 #endif
2684 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2686 va_list ap;
2687 va_start(ap, msg);
2688 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2689 va_end(ap);
2692 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2694 va_list ap;
2695 va_start(ap, msg);
2696 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2697 va_end(ap);
2700 static HRESULT WINAPI domdoc_validateNode(
2701 IXMLDOMDocument3* iface,
2702 IXMLDOMNode* node,
2703 IXMLDOMParseError** err)
2705 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2706 LONG state, err_code = 0;
2707 HRESULT hr = S_OK;
2708 int validated = 0;
2710 TRACE("(%p)->(%p, %p)\n", This, node, err);
2711 domdoc_get_readyState(iface, &state);
2712 if (state != READYSTATE_COMPLETE)
2714 if (err)
2715 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2716 return E_PENDING;
2719 if (!node)
2721 if (err)
2722 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2723 return E_POINTER;
2726 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2728 if (err)
2729 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2730 return E_FAIL;
2733 if (!is_wellformed(get_doc(This)))
2735 ERR("doc not well-formed\n");
2736 if (err)
2737 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2738 return S_FALSE;
2741 /* DTD validation */
2742 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2744 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2745 vctx->error = validate_error;
2746 vctx->warning = validate_warning;
2747 ++validated;
2749 if (!((node == (IXMLDOMNode*)iface)?
2750 xmlValidateDocument(vctx, get_doc(This)) :
2751 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2753 /* TODO: get a real error code here */
2754 TRACE("DTD validation failed\n");
2755 err_code = E_XML_INVALID;
2756 hr = S_FALSE;
2758 xmlFreeValidCtxt(vctx);
2761 /* Schema validation */
2762 if (hr == S_OK && This->properties->schemaCache != NULL)
2765 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2766 if (SUCCEEDED(hr))
2768 ++validated;
2769 /* TODO: get a real error code here */
2770 if (hr == S_OK)
2772 TRACE("schema validation succeeded\n");
2774 else
2776 ERR("schema validation failed\n");
2777 err_code = E_XML_INVALID;
2780 else
2782 /* not really OK, just didn't find a schema for the ns */
2783 hr = S_OK;
2787 if (!validated)
2789 ERR("no DTD or schema found\n");
2790 err_code = E_XML_NODTD;
2791 hr = S_FALSE;
2794 if (err)
2795 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2797 return hr;
2800 static HRESULT WINAPI domdoc_validate(
2801 IXMLDOMDocument3* iface,
2802 IXMLDOMParseError** err)
2804 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2805 TRACE("(%p)->(%p)\n", This, err);
2806 return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2809 static HRESULT WINAPI domdoc_setProperty(
2810 IXMLDOMDocument3* iface,
2811 BSTR p,
2812 VARIANT var)
2814 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2816 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2818 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2820 VARIANT varStr;
2821 HRESULT hr;
2822 BSTR bstr;
2824 V_VT(&varStr) = VT_EMPTY;
2825 if (V_VT(&var) != VT_BSTR)
2827 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2828 return hr;
2829 bstr = V_BSTR(&varStr);
2831 else
2832 bstr = V_BSTR(&var);
2834 hr = S_OK;
2835 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2836 This->properties->XPath = TRUE;
2837 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2838 This->properties->XPath = FALSE;
2839 else
2840 hr = E_FAIL;
2842 VariantClear(&varStr);
2843 return hr;
2845 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2847 VARIANT varStr;
2848 HRESULT hr;
2849 BSTR bstr;
2850 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2851 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2852 xmlXPathContextPtr ctx;
2853 struct list *pNsList;
2854 select_ns_entry* pNsEntry = NULL;
2856 V_VT(&varStr) = VT_EMPTY;
2857 if (V_VT(&var) != VT_BSTR)
2859 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2860 return hr;
2861 bstr = V_BSTR(&varStr);
2863 else
2864 bstr = V_BSTR(&var);
2866 hr = S_OK;
2868 pNsList = &(This->properties->selectNsList);
2869 clear_selectNsList(pNsList);
2870 heap_free(nsStr);
2871 nsStr = xmlchar_from_wchar(bstr);
2873 TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2875 This->properties->selectNsStr = nsStr;
2876 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2877 if (bstr && *bstr)
2879 ctx = xmlXPathNewContext(This->node.node->doc);
2880 pTokBegin = nsStr;
2881 for (; *pTokBegin; pTokBegin = pTokEnd)
2883 if (pNsEntry != NULL)
2884 memset(pNsEntry, 0, sizeof(select_ns_entry));
2885 else
2886 pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2888 while (*pTokBegin == ' ')
2889 ++pTokBegin;
2890 pTokEnd = pTokBegin;
2891 while (*pTokEnd != ' ' && *pTokEnd != 0)
2892 ++pTokEnd;
2894 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2896 hr = E_FAIL;
2897 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2898 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2899 continue;
2902 pTokBegin += 5;
2903 if (*pTokBegin == '=')
2905 /*valid for XSLPattern?*/
2906 FIXME("Setting default xmlns not supported - skipping.\n");
2907 continue;
2909 else if (*pTokBegin == ':')
2911 pNsEntry->prefix = ++pTokBegin;
2912 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2915 if (pTokInner == pTokEnd)
2917 hr = E_FAIL;
2918 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2919 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2920 continue;
2923 pNsEntry->prefix_end = *pTokInner;
2924 *pTokInner = 0;
2925 ++pTokInner;
2927 if (pTokEnd-pTokInner > 1 &&
2928 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2929 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2931 pNsEntry->href = ++pTokInner;
2932 pNsEntry->href_end = *(pTokEnd-1);
2933 *(pTokEnd-1) = 0;
2934 list_add_tail(pNsList, &pNsEntry->entry);
2935 /*let libxml figure out if they're valid from here ;)*/
2936 if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2938 hr = E_FAIL;
2940 pNsEntry = NULL;
2941 continue;
2943 else
2945 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2946 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2947 list_add_tail(pNsList, &pNsEntry->entry);
2949 pNsEntry = NULL;
2950 hr = E_FAIL;
2951 continue;
2954 else
2956 hr = E_FAIL;
2957 continue;
2960 heap_free(pNsEntry);
2961 xmlXPathFreeContext(ctx);
2964 VariantClear(&varStr);
2965 return hr;
2967 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2968 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2969 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2971 /* Ignore */
2972 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2973 return S_OK;
2976 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2977 return E_FAIL;
2980 static HRESULT WINAPI domdoc_getProperty(
2981 IXMLDOMDocument3* iface,
2982 BSTR p,
2983 VARIANT* var)
2985 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2987 TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2989 if (!var)
2990 return E_INVALIDARG;
2992 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2994 V_VT(var) = VT_BSTR;
2995 V_BSTR(var) = This->properties->XPath ?
2996 SysAllocString(PropValueXPathW) :
2997 SysAllocString(PropValueXSLPatternW);
2998 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3000 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3002 int lenA, lenW;
3003 BSTR rebuiltStr, cur;
3004 const xmlChar *nsStr;
3005 struct list *pNsList;
3006 select_ns_entry* pNsEntry;
3008 V_VT(var) = VT_BSTR;
3009 nsStr = This->properties->selectNsStr;
3010 pNsList = &This->properties->selectNsList;
3011 lenA = This->properties->selectNsStr_len;
3012 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3013 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3014 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3015 cur = rebuiltStr;
3016 /* this is fine because all of the chars that end tokens are ASCII*/
3017 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3019 while (*cur != 0) ++cur;
3020 if (pNsEntry->prefix_end)
3022 *cur = pNsEntry->prefix_end;
3023 while (*cur != 0) ++cur;
3026 if (pNsEntry->href_end)
3028 *cur = pNsEntry->href_end;
3031 V_BSTR(var) = SysAllocString(rebuiltStr);
3032 heap_free(rebuiltStr);
3033 return S_OK;
3036 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
3037 return E_FAIL;
3040 static HRESULT WINAPI domdoc_importNode(
3041 IXMLDOMDocument3* iface,
3042 IXMLDOMNode* node,
3043 VARIANT_BOOL deep,
3044 IXMLDOMNode** clone)
3046 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3047 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3048 return E_NOTIMPL;
3051 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
3053 domdoc_QueryInterface,
3054 domdoc_AddRef,
3055 domdoc_Release,
3056 domdoc_GetTypeInfoCount,
3057 domdoc_GetTypeInfo,
3058 domdoc_GetIDsOfNames,
3059 domdoc_Invoke,
3060 domdoc_get_nodeName,
3061 domdoc_get_nodeValue,
3062 domdoc_put_nodeValue,
3063 domdoc_get_nodeType,
3064 domdoc_get_parentNode,
3065 domdoc_get_childNodes,
3066 domdoc_get_firstChild,
3067 domdoc_get_lastChild,
3068 domdoc_get_previousSibling,
3069 domdoc_get_nextSibling,
3070 domdoc_get_attributes,
3071 domdoc_insertBefore,
3072 domdoc_replaceChild,
3073 domdoc_removeChild,
3074 domdoc_appendChild,
3075 domdoc_hasChildNodes,
3076 domdoc_get_ownerDocument,
3077 domdoc_cloneNode,
3078 domdoc_get_nodeTypeString,
3079 domdoc_get_text,
3080 domdoc_put_text,
3081 domdoc_get_specified,
3082 domdoc_get_definition,
3083 domdoc_get_nodeTypedValue,
3084 domdoc_put_nodeTypedValue,
3085 domdoc_get_dataType,
3086 domdoc_put_dataType,
3087 domdoc_get_xml,
3088 domdoc_transformNode,
3089 domdoc_selectNodes,
3090 domdoc_selectSingleNode,
3091 domdoc_get_parsed,
3092 domdoc_get_namespaceURI,
3093 domdoc_get_prefix,
3094 domdoc_get_baseName,
3095 domdoc_transformNodeToObject,
3096 domdoc_get_doctype,
3097 domdoc_get_implementation,
3098 domdoc_get_documentElement,
3099 domdoc_put_documentElement,
3100 domdoc_createElement,
3101 domdoc_createDocumentFragment,
3102 domdoc_createTextNode,
3103 domdoc_createComment,
3104 domdoc_createCDATASection,
3105 domdoc_createProcessingInstruction,
3106 domdoc_createAttribute,
3107 domdoc_createEntityReference,
3108 domdoc_getElementsByTagName,
3109 domdoc_createNode,
3110 domdoc_nodeFromID,
3111 domdoc_load,
3112 domdoc_get_readyState,
3113 domdoc_get_parseError,
3114 domdoc_get_url,
3115 domdoc_get_async,
3116 domdoc_put_async,
3117 domdoc_abort,
3118 domdoc_loadXML,
3119 domdoc_save,
3120 domdoc_get_validateOnParse,
3121 domdoc_put_validateOnParse,
3122 domdoc_get_resolveExternals,
3123 domdoc_put_resolveExternals,
3124 domdoc_get_preserveWhiteSpace,
3125 domdoc_put_preserveWhiteSpace,
3126 domdoc_put_onreadystatechange,
3127 domdoc_put_onDataAvailable,
3128 domdoc_put_onTransformNode,
3129 domdoc_get_namespaces,
3130 domdoc_get_schemas,
3131 domdoc_putref_schemas,
3132 domdoc_validate,
3133 domdoc_setProperty,
3134 domdoc_getProperty,
3135 domdoc_validateNode,
3136 domdoc_importNode
3139 /* IConnectionPointContainer */
3140 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3141 REFIID riid, void **ppv)
3143 domdoc *This = impl_from_IConnectionPointContainer(iface);
3144 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3147 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3149 domdoc *This = impl_from_IConnectionPointContainer(iface);
3150 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3153 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3155 domdoc *This = impl_from_IConnectionPointContainer(iface);
3156 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3159 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3160 IEnumConnectionPoints **ppEnum)
3162 domdoc *This = impl_from_IConnectionPointContainer(iface);
3163 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3164 return E_NOTIMPL;
3167 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3168 REFIID riid, IConnectionPoint **cp)
3170 domdoc *This = impl_from_IConnectionPointContainer(iface);
3171 ConnectionPoint *iter;
3173 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3175 *cp = NULL;
3177 for(iter = This->cp_list; iter; iter = iter->next)
3179 if (IsEqualGUID(iter->iid, riid))
3180 *cp = &iter->IConnectionPoint_iface;
3183 if (*cp)
3185 IConnectionPoint_AddRef(*cp);
3186 return S_OK;
3189 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3190 return CONNECT_E_NOCONNECTION;
3194 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3196 ConnectionPointContainer_QueryInterface,
3197 ConnectionPointContainer_AddRef,
3198 ConnectionPointContainer_Release,
3199 ConnectionPointContainer_EnumConnectionPoints,
3200 ConnectionPointContainer_FindConnectionPoint
3203 /* IConnectionPoint */
3204 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3205 REFIID riid, void **ppv)
3207 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3209 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3211 *ppv = NULL;
3213 if (IsEqualGUID(&IID_IUnknown, riid) ||
3214 IsEqualGUID(&IID_IConnectionPoint, riid))
3216 *ppv = iface;
3219 if (*ppv)
3221 IConnectionPoint_AddRef(iface);
3222 return S_OK;
3225 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3226 return E_NOINTERFACE;
3229 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3231 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3232 return IConnectionPointContainer_AddRef(This->container);
3235 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3237 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3238 return IConnectionPointContainer_Release(This->container);
3241 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3243 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3245 TRACE("(%p)->(%p)\n", This, iid);
3247 if (!iid) return E_POINTER;
3249 *iid = *This->iid;
3250 return S_OK;
3253 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3254 IConnectionPointContainer **container)
3256 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3258 TRACE("(%p)->(%p)\n", This, container);
3260 if (!container) return E_POINTER;
3262 *container = This->container;
3263 IConnectionPointContainer_AddRef(*container);
3264 return S_OK;
3267 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3268 DWORD *pdwCookie)
3270 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3271 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3272 return E_NOTIMPL;
3275 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3277 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3279 TRACE("(%p)->(%d)\n", This, cookie);
3281 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3282 return CONNECT_E_NOCONNECTION;
3284 IUnknown_Release(This->sinks[cookie-1].unk);
3285 This->sinks[cookie-1].unk = NULL;
3287 return S_OK;
3290 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3291 IEnumConnections **ppEnum)
3293 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3294 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3295 return E_NOTIMPL;
3298 static const IConnectionPointVtbl ConnectionPointVtbl =
3300 ConnectionPoint_QueryInterface,
3301 ConnectionPoint_AddRef,
3302 ConnectionPoint_Release,
3303 ConnectionPoint_GetConnectionInterface,
3304 ConnectionPoint_GetConnectionPointContainer,
3305 ConnectionPoint_Advise,
3306 ConnectionPoint_Unadvise,
3307 ConnectionPoint_EnumConnections
3310 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3312 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3313 cp->doc = doc;
3314 cp->iid = riid;
3315 cp->sinks = NULL;
3316 cp->sinks_size = 0;
3318 cp->next = doc->cp_list;
3319 doc->cp_list = cp;
3321 cp->container = &doc->IConnectionPointContainer_iface;
3324 /* domdoc implementation of IObjectWithSite */
3325 static HRESULT WINAPI
3326 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3328 domdoc *This = impl_from_IObjectWithSite(iface);
3329 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3332 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3334 domdoc *This = impl_from_IObjectWithSite(iface);
3335 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3338 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3340 domdoc *This = impl_from_IObjectWithSite(iface);
3341 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3344 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3346 domdoc *This = impl_from_IObjectWithSite(iface);
3348 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3350 if ( !This->site )
3351 return E_FAIL;
3353 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3356 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3358 domdoc *This = impl_from_IObjectWithSite(iface);
3360 TRACE("(%p)->(%p)\n", iface, punk);
3362 if(!punk)
3364 if(This->site)
3366 IUnknown_Release( This->site );
3367 This->site = NULL;
3370 return S_OK;
3373 IUnknown_AddRef( punk );
3375 if(This->site)
3376 IUnknown_Release( This->site );
3378 This->site = punk;
3380 return S_OK;
3383 static const IObjectWithSiteVtbl domdocObjectSite =
3385 domdoc_ObjectWithSite_QueryInterface,
3386 domdoc_ObjectWithSite_AddRef,
3387 domdoc_ObjectWithSite_Release,
3388 domdoc_ObjectWithSite_SetSite,
3389 domdoc_ObjectWithSite_GetSite
3392 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3394 domdoc *This = impl_from_IObjectSafety(iface);
3395 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3398 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3400 domdoc *This = impl_from_IObjectSafety(iface);
3401 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3404 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3406 domdoc *This = impl_from_IObjectSafety(iface);
3407 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3410 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3412 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3413 DWORD *supported, DWORD *enabled)
3415 domdoc *This = impl_from_IObjectSafety(iface);
3417 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3419 if(!supported || !enabled) return E_POINTER;
3421 *supported = SAFETY_SUPPORTED_OPTIONS;
3422 *enabled = This->safeopt;
3424 return S_OK;
3427 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3428 DWORD mask, DWORD enabled)
3430 domdoc *This = impl_from_IObjectSafety(iface);
3431 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3433 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3434 return E_FAIL;
3436 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3438 return S_OK;
3441 #undef SAFETY_SUPPORTED_OPTIONS
3443 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3444 domdoc_Safety_QueryInterface,
3445 domdoc_Safety_AddRef,
3446 domdoc_Safety_Release,
3447 domdoc_Safety_GetInterfaceSafetyOptions,
3448 domdoc_Safety_SetInterfaceSafetyOptions
3451 static const tid_t domdoc_iface_tids[] = {
3452 IXMLDOMNode_tid,
3453 IXMLDOMDocument_tid,
3454 IXMLDOMDocument2_tid,
3457 static dispex_static_data_t domdoc_dispex = {
3458 NULL,
3459 IXMLDOMDocument2_tid,
3460 NULL,
3461 domdoc_iface_tids
3464 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3466 domdoc *doc;
3468 doc = heap_alloc( sizeof (*doc) );
3469 if( !doc )
3470 return E_OUTOFMEMORY;
3472 doc->IXMLDOMDocument3_iface.lpVtbl = &domdoc_vtbl;
3473 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3474 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3475 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3476 doc->ISupportErrorInfo_iface.lpVtbl = &support_error_vtbl;
3477 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3478 doc->ref = 1;
3479 doc->async = VARIANT_TRUE;
3480 doc->validating = 0;
3481 doc->resolving = 0;
3482 doc->properties = properties_from_xmlDocPtr(xmldoc);
3483 doc->error = S_OK;
3484 doc->stream = NULL;
3485 doc->site = NULL;
3486 doc->safeopt = 0;
3487 doc->bsc = NULL;
3488 doc->cp_list = NULL;
3489 memset(doc->events, 0, sizeof(doc->events));
3491 /* events connection points */
3492 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3493 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3494 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3496 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3497 &domdoc_dispex);
3499 *document = &doc->IXMLDOMDocument3_iface;
3501 TRACE("returning iface %p\n", *document);
3502 return S_OK;
3505 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3507 xmlDocPtr xmldoc;
3508 HRESULT hr;
3510 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3512 xmldoc = xmlNewDoc(NULL);
3513 if(!xmldoc)
3514 return E_OUTOFMEMORY;
3516 xmldoc->_private = create_priv();
3517 priv_from_xmlDocPtr(xmldoc)->properties = create_properties(version);
3519 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3520 if(FAILED(hr))
3522 free_properties(properties_from_xmlDocPtr(xmldoc));
3523 heap_free(xmldoc->_private);
3524 xmlFreeDoc(xmldoc);
3525 return hr;
3528 return hr;
3531 IUnknown* create_domdoc( xmlNodePtr document )
3533 void* pObj = NULL;
3534 HRESULT hr;
3536 TRACE("(%p)\n", document);
3538 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3539 if (FAILED(hr))
3540 return NULL;
3542 return pObj;
3545 #else
3547 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3549 MESSAGE("This program tried to use a DOMDocument object, but\n"
3550 "libxml2 support was not present at compile time.\n");
3551 return E_NOTIMPL;
3554 #endif