msxml3: Add support for VT_BSTR|VT_BYREF in domdoc_save().
[wine] / dlls / msxml3 / domdoc.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
5  * Copyright 2010-2011 Adam Martinson for CodeWeavers
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24
25 #include "config.h"
26
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
37
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"
50 #include "dispex.h"
51
52 #include "wine/debug.h"
53 #include "wine/list.h"
54
55 #include "msxml_private.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58
59 #ifdef HAVE_LIBXML2
60
61 /* not defined in older versions */
62 #define XML_SAVE_FORMAT     1
63 #define XML_SAVE_NO_DECL    2
64 #define XML_SAVE_NO_EMPTY   4
65 #define XML_SAVE_NO_XHTML   8
66 #define XML_SAVE_XHTML     16
67 #define XML_SAVE_AS_XML    32
68 #define XML_SAVE_AS_HTML   64
69
70 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
71 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
72 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
73 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
74 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
75 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
76 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77
78 /* Anything that passes the test_get_ownerDocument()
79  * tests can go here (data shared between all instances).
80  * We need to preserve this when reloading a document,
81  * and also need access to it from the libxml backend. */
82 typedef struct _domdoc_properties {
83     MSXML_VERSION version;
84     VARIANT_BOOL preserving;
85     IXMLDOMSchemaCollection2* schemaCache;
86     struct list selectNsList;
87     xmlChar const* selectNsStr;
88     LONG selectNsStr_len;
89     BOOL XPath;
90 } domdoc_properties;
91
92 typedef struct ConnectionPoint ConnectionPoint;
93 typedef struct domdoc domdoc;
94
95 struct ConnectionPoint
96 {
97     IConnectionPoint IConnectionPoint_iface;
98     const IID *iid;
99
100     ConnectionPoint *next;
101     IConnectionPointContainer *container;
102     domdoc *doc;
103
104     union
105     {
106         IUnknown *unk;
107         IDispatch *disp;
108         IPropertyNotifySink *propnotif;
109     } *sinks;
110     DWORD sinks_size;
111 };
112
113 typedef enum {
114     EVENTID_READYSTATECHANGE = 0,
115     EVENTID_DATAAVAILABLE,
116     EVENTID_TRANSFORMNODE,
117     EVENTID_LAST
118 } eventid_t;
119
120 struct domdoc
121 {
122     xmlnode node;
123     IXMLDOMDocument3          IXMLDOMDocument3_iface;
124     IPersistStreamInit        IPersistStreamInit_iface;
125     IObjectWithSite           IObjectWithSite_iface;
126     IObjectSafety             IObjectSafety_iface;
127     ISupportErrorInfo         ISupportErrorInfo_iface;
128     IConnectionPointContainer IConnectionPointContainer_iface;
129     LONG ref;
130     VARIANT_BOOL async;
131     VARIANT_BOOL validating;
132     VARIANT_BOOL resolving;
133     domdoc_properties* properties;
134     bsc_t *bsc;
135     HRESULT error;
136
137     /* IPersistStream */
138     IStream *stream;
139
140     /* IObjectWithSite*/
141     IUnknown *site;
142
143     /* IObjectSafety */
144     DWORD safeopt;
145
146     /* connection list */
147     ConnectionPoint *cp_list;
148     ConnectionPoint cp_domdocevents;
149     ConnectionPoint cp_propnotif;
150     ConnectionPoint cp_dispatch;
151
152     /* events */
153     IDispatch *events[EVENTID_LAST];
154 };
155
156 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
157 {
158     IDispatch *disp;
159
160     switch (V_VT(v))
161     {
162     case VT_UNKNOWN:
163         if (V_UNKNOWN(v))
164             IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
165         else
166             disp = NULL;
167         break;
168     case VT_DISPATCH:
169         disp = V_DISPATCH(v);
170         if (disp) IDispatch_AddRef(disp);
171         break;
172     default:
173         return DISP_E_TYPEMISMATCH;
174     }
175
176     if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
177     doc->events[eid] = disp;
178
179     return S_OK;
180 }
181
182 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
183 {
184     return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 }
186
187 /*
188   In native windows, the whole lifetime management of XMLDOMNodes is
189   managed automatically using reference counts. Wine emulates that by
190   maintaining a reference count to the document that is increased for
191   each IXMLDOMNode pointer passed out for this document. If all these
192   pointers are gone, the document is unreachable and gets freed, that
193   is, all nodes in the tree of the document get freed.
194
195   You are able to create nodes that are associated to a document (in
196   fact, in msxml's XMLDOM model, all nodes are associated to a document),
197   but not in the tree of that document, for example using the createFoo
198   functions from IXMLDOMDocument. These nodes do not get cleaned up
199   by libxml, so we have to do it ourselves.
200
201   To catch these nodes, a list of "orphan nodes" is introduced.
202   It contains pointers to all roots of node trees that are
203   associated with the document without being part of the document
204   tree. All nodes with parent==NULL (except for the document root nodes)
205   should be in the orphan node list of their document. All orphan nodes
206   get freed together with the document itself.
207  */
208
209 typedef struct _xmldoc_priv {
210     LONG refs;
211     struct list orphans;
212     domdoc_properties* properties;
213 } xmldoc_priv;
214
215 typedef struct _orphan_entry {
216     struct list entry;
217     xmlNode * node;
218 } orphan_entry;
219
220 typedef struct _select_ns_entry {
221     struct list entry;
222     xmlChar const* prefix;
223     xmlChar prefix_end;
224     xmlChar const* href;
225     xmlChar href_end;
226 } select_ns_entry;
227
228 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
229 {
230     return doc->_private;
231 }
232
233 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
234 {
235     return priv_from_xmlDocPtr(doc)->properties;
236 }
237
238 BOOL is_xpathmode(const xmlDocPtr doc)
239 {
240     return properties_from_xmlDocPtr(doc)->XPath;
241 }
242
243 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
244 {
245     properties_from_xmlDocPtr(doc)->XPath = xpath;
246 }
247
248 int registerNamespaces(xmlXPathContextPtr ctxt)
249 {
250     int n = 0;
251     const select_ns_entry* ns = NULL;
252     const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
253
254     TRACE("(%p)\n", ctxt);
255
256     LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
257     {
258         xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
259         ++n;
260     }
261
262     return n;
263 }
264
265 static inline void clear_selectNsList(struct list* pNsList)
266 {
267     select_ns_entry *ns, *ns2;
268     LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
269     {
270         heap_free( ns );
271     }
272     list_init(pNsList);
273 }
274
275 static xmldoc_priv * create_priv(void)
276 {
277     xmldoc_priv *priv;
278     priv = heap_alloc( sizeof (*priv) );
279
280     if (priv)
281     {
282         priv->refs = 0;
283         list_init( &priv->orphans );
284         priv->properties = NULL;
285     }
286
287     return priv;
288 }
289
290 static domdoc_properties * create_properties(const GUID *clsid)
291 {
292     domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
293
294     list_init(&properties->selectNsList);
295     properties->preserving = VARIANT_FALSE;
296     properties->schemaCache = NULL;
297     properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
298     properties->selectNsStr_len = 0;
299
300     /* properties that are dependent on object versions */
301     if (IsEqualCLSID(clsid, &CLSID_DOMDocument30))
302     {
303         properties->version = MSXML3;
304         properties->XPath = FALSE;
305     }
306     else if (IsEqualCLSID(clsid, &CLSID_DOMDocument40))
307     {
308         properties->version = MSXML4;
309         properties->XPath = TRUE;
310     }
311     else if (IsEqualCLSID(clsid, &CLSID_DOMDocument60))
312     {
313         properties->version = MSXML6;
314         properties->XPath = TRUE;
315     }
316     else
317     {
318         properties->version = MSXML_DEFAULT;
319         properties->XPath = FALSE;
320     }
321
322     return properties;
323 }
324
325 static domdoc_properties* copy_properties(domdoc_properties const* properties)
326 {
327     domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
328     select_ns_entry const* ns = NULL;
329     select_ns_entry* new_ns = NULL;
330     int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
331     ptrdiff_t offset;
332
333     if (pcopy)
334     {
335         pcopy->version = properties->version;
336         pcopy->preserving = properties->preserving;
337         pcopy->schemaCache = properties->schemaCache;
338         if (pcopy->schemaCache)
339             IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
340         pcopy->XPath = properties->XPath;
341         pcopy->selectNsStr_len = properties->selectNsStr_len;
342         list_init( &pcopy->selectNsList );
343         pcopy->selectNsStr = heap_alloc(len);
344         memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
345         offset = pcopy->selectNsStr - properties->selectNsStr;
346
347         LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
348         {
349             new_ns = heap_alloc(sizeof(select_ns_entry));
350             memcpy(new_ns, ns, sizeof(select_ns_entry));
351             new_ns->href += offset;
352             new_ns->prefix += offset;
353             list_add_tail(&pcopy->selectNsList, &new_ns->entry);
354         }
355
356     }
357
358     return pcopy;
359 }
360
361 static void free_properties(domdoc_properties* properties)
362 {
363     if (properties)
364     {
365         if (properties->schemaCache)
366             IXMLDOMSchemaCollection2_Release(properties->schemaCache);
367         clear_selectNsList(&properties->selectNsList);
368         heap_free((xmlChar*)properties->selectNsStr);
369         heap_free(properties);
370     }
371 }
372
373 /* links a "<?xml" node as a first child */
374 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
375 {
376     assert(doc != NULL);
377     if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
378 }
379
380 /* unlinks a first "<?xml" child if it was created */
381 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
382 {
383     xmlNodePtr node;
384
385     assert(doc != NULL);
386
387     if (doc->standalone != -1)
388     {
389         node = doc->children;
390         xmlUnlinkNode( node );
391     }
392     else
393         node = NULL;
394
395     return node;
396 }
397
398 BOOL is_preserving_whitespace(xmlNodePtr node)
399 {
400     domdoc_properties* properties = NULL;
401     /* during parsing the xmlDoc._private stuff is not there */
402     if (priv_from_xmlDocPtr(node->doc))
403         properties = properties_from_xmlDocPtr(node->doc);
404     return ((properties && properties->preserving == VARIANT_TRUE) ||
405             xmlNodeGetSpacePreserve(node) == 1);
406 }
407
408 static inline BOOL strn_isspace(xmlChar const* str, int len)
409 {
410     for (; str && len > 0 && *str; ++str, --len)
411         if (!isspace(*str))
412             break;
413
414     return len == 0;
415 }
416
417 static void sax_characters(void *ctx, const xmlChar *ch, int len)
418 {
419     xmlParserCtxtPtr ctxt;
420     const domdoc *This;
421
422     ctxt = (xmlParserCtxtPtr) ctx;
423     This = (const domdoc*) ctxt->_private;
424
425     if (ctxt->node)
426     {
427         /* 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             return;
432     }
433
434     xmlSAX2Characters(ctxt, ch, len);
435 }
436
437 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
438 {
439     va_list ap;
440     va_start(ap, msg);
441     LIBXML2_CALLBACK_ERR(doparse, msg, ap);
442     va_end(ap);
443 }
444
445 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
446 {
447     va_list ap;
448     va_start(ap, msg);
449     LIBXML2_CALLBACK_WARN(doparse, msg, ap);
450     va_end(ap);
451 }
452
453 static void sax_serror(void* ctx, xmlErrorPtr err)
454 {
455     LIBXML2_CALLBACK_SERROR(doparse, err);
456 }
457
458 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
459 {
460     xmlDocPtr doc = NULL;
461     xmlParserCtxtPtr pctx;
462     static xmlSAXHandler sax_handler = {
463         xmlSAX2InternalSubset,          /* internalSubset */
464         xmlSAX2IsStandalone,            /* isStandalone */
465         xmlSAX2HasInternalSubset,       /* hasInternalSubset */
466         xmlSAX2HasExternalSubset,       /* hasExternalSubset */
467         xmlSAX2ResolveEntity,           /* resolveEntity */
468         xmlSAX2GetEntity,               /* getEntity */
469         xmlSAX2EntityDecl,              /* entityDecl */
470         xmlSAX2NotationDecl,            /* notationDecl */
471         xmlSAX2AttributeDecl,           /* attributeDecl */
472         xmlSAX2ElementDecl,             /* elementDecl */
473         xmlSAX2UnparsedEntityDecl,      /* unparsedEntityDecl */
474         xmlSAX2SetDocumentLocator,      /* setDocumentLocator */
475         xmlSAX2StartDocument,           /* startDocument */
476         xmlSAX2EndDocument,             /* endDocument */
477         xmlSAX2StartElement,            /* startElement */
478         xmlSAX2EndElement,              /* endElement */
479         xmlSAX2Reference,               /* reference */
480         sax_characters,                 /* characters */
481         sax_characters,                 /* ignorableWhitespace */
482         xmlSAX2ProcessingInstruction,   /* processingInstruction */
483         xmlSAX2Comment,                 /* comment */
484         sax_warning,                    /* warning */
485         sax_error,                      /* error */
486         sax_error,                      /* fatalError */
487         xmlSAX2GetParameterEntity,      /* getParameterEntity */
488         xmlSAX2CDataBlock,              /* cdataBlock */
489         xmlSAX2ExternalSubset,          /* externalSubset */
490         0,                              /* initialized */
491         NULL,                           /* _private */
492         xmlSAX2StartElementNs,          /* startElementNs */
493         xmlSAX2EndElementNs,            /* endElementNs */
494         sax_serror                      /* serror */
495     };
496     xmlInitParser();
497
498     pctx = xmlCreateMemoryParserCtxt(ptr, len);
499     if (!pctx)
500     {
501         ERR("Failed to create parser context\n");
502         return NULL;
503     }
504
505     if (pctx->sax) xmlFree(pctx->sax);
506     pctx->sax = &sax_handler;
507     pctx->_private = This;
508     pctx->recovery = 0;
509
510     if (encoding != XML_CHAR_ENCODING_NONE)
511         xmlSwitchEncoding(pctx, encoding);
512
513     xmlParseDocument(pctx);
514
515     if (pctx->wellFormed)
516     {
517         doc = pctx->myDoc;
518     }
519     else
520     {
521        xmlFreeDoc(pctx->myDoc);
522        pctx->myDoc = NULL;
523     }
524     pctx->sax = NULL;
525     xmlFreeParserCtxt(pctx);
526
527     /* TODO: put this in one of the SAX callbacks */
528     /* create first child as a <?xml...?> */
529     if (doc && doc->standalone != -1)
530     {
531         xmlNodePtr node;
532         char buff[30];
533         xmlChar *xmlbuff = (xmlChar*)buff;
534
535         node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
536
537         /* version attribute can't be omitted */
538         sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
539         xmlNodeAddContent( node, xmlbuff );
540
541         if (doc->encoding)
542         {
543             sprintf(buff, " encoding=\"%s\"", doc->encoding);
544             xmlNodeAddContent( node, xmlbuff );
545         }
546
547         if (doc->standalone != -2)
548         {
549             sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
550             xmlNodeAddContent( node, xmlbuff );
551         }
552
553         xmldoc_link_xmldecl( doc, node );
554     }
555
556     return doc;
557 }
558
559 void xmldoc_init(xmlDocPtr doc, const GUID *clsid)
560 {
561     doc->_private = create_priv();
562     priv_from_xmlDocPtr(doc)->properties = create_properties(clsid);
563 }
564
565 LONG xmldoc_add_ref(xmlDocPtr doc)
566 {
567     LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
568     TRACE("(%p)->(%d)\n", doc, ref);
569     return ref;
570 }
571
572 LONG xmldoc_release(xmlDocPtr doc)
573 {
574     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
575     LONG ref = InterlockedDecrement(&priv->refs);
576     TRACE("(%p)->(%d)\n", doc, ref);
577     if(ref == 0)
578     {
579         orphan_entry *orphan, *orphan2;
580         TRACE("freeing docptr %p\n", doc);
581
582         LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
583         {
584             xmlFreeNode( orphan->node );
585             heap_free( orphan );
586         }
587         free_properties(priv->properties);
588         heap_free(doc->_private);
589
590         xmlFreeDoc(doc);
591     }
592
593     return ref;
594 }
595
596 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
597 {
598     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
599     orphan_entry *entry;
600
601     entry = heap_alloc( sizeof (*entry) );
602     if(!entry)
603         return E_OUTOFMEMORY;
604
605     entry->node = node;
606     list_add_head( &priv->orphans, &entry->entry );
607     return S_OK;
608 }
609
610 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
611 {
612     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
613     orphan_entry *entry, *entry2;
614
615     LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
616     {
617         if( entry->node == node )
618         {
619             list_remove( &entry->entry );
620             heap_free( entry );
621             return S_OK;
622         }
623     }
624
625     return S_FALSE;
626 }
627
628 static inline xmlDocPtr get_doc( domdoc *This )
629 {
630     return (xmlDocPtr)This->node.node;
631 }
632
633 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
634 {
635     if(This->node.node)
636     {
637         priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
638         if (xmldoc_release(get_doc(This)) != 0)
639             priv_from_xmlDocPtr(get_doc(This))->properties =
640                 copy_properties(This->properties);
641     }
642
643     This->node.node = (xmlNodePtr) xml;
644
645     if(This->node.node)
646     {
647         xmldoc_add_ref(get_doc(This));
648         priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
649     }
650
651     return S_OK;
652 }
653
654 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
655 {
656     return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
657 }
658
659 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
660 {
661     return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
662 }
663
664 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
665 {
666     return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
667 }
668
669 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
670 {
671     return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
672 }
673
674 static inline domdoc *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
675 {
676     return CONTAINING_RECORD(iface, domdoc, ISupportErrorInfo_iface);
677 }
678
679 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
680 {
681     return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
682 }
683
684 /************************************************************************
685  * domdoc implementation of IPersistStream.
686  */
687 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
688     IPersistStreamInit *iface, REFIID riid, void **ppvObj)
689 {
690     domdoc* This = impl_from_IPersistStreamInit(iface);
691     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
692 }
693
694 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
695     IPersistStreamInit *iface)
696 {
697     domdoc* This = impl_from_IPersistStreamInit(iface);
698     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
699 }
700
701 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
702     IPersistStreamInit *iface)
703 {
704     domdoc* This = impl_from_IPersistStreamInit(iface);
705     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
706 }
707
708 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
709     IPersistStreamInit *iface, CLSID *classid)
710 {
711     domdoc* This = impl_from_IPersistStreamInit(iface);
712     TRACE("(%p)->(%p)\n", This, classid);
713
714     if(!classid)
715         return E_POINTER;
716
717     *classid = *DOMDocument_version(This->properties->version);
718
719     return S_OK;
720 }
721
722 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
723     IPersistStreamInit *iface)
724 {
725     domdoc *This = impl_from_IPersistStreamInit(iface);
726     FIXME("(%p): stub!\n", This);
727     return S_FALSE;
728 }
729
730 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
731     IPersistStreamInit *iface, LPSTREAM pStm)
732 {
733     domdoc *This = impl_from_IPersistStreamInit(iface);
734     HRESULT hr;
735     HGLOBAL hglobal;
736     DWORD read, written, len;
737     BYTE buf[4096];
738     char *ptr;
739     xmlDocPtr xmldoc = NULL;
740
741     TRACE("(%p)->(%p)\n", This, pStm);
742
743     if (!pStm)
744         return E_INVALIDARG;
745
746     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
747     if (FAILED(hr))
748         return hr;
749
750     do
751     {
752         IStream_Read(pStm, buf, sizeof(buf), &read);
753         hr = IStream_Write(This->stream, buf, read, &written);
754     } while(SUCCEEDED(hr) && written != 0 && read != 0);
755
756     if (FAILED(hr))
757     {
758         ERR("Failed to copy stream\n");
759         return hr;
760     }
761
762     hr = GetHGlobalFromStream(This->stream, &hglobal);
763     if (FAILED(hr))
764         return hr;
765
766     len = GlobalSize(hglobal);
767     ptr = GlobalLock(hglobal);
768     if (len != 0)
769         xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
770     GlobalUnlock(hglobal);
771
772     if (!xmldoc)
773     {
774         ERR("Failed to parse xml\n");
775         return E_FAIL;
776     }
777
778     xmldoc->_private = create_priv();
779
780     return attach_xmldoc(This, xmldoc);
781 }
782
783 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
784     IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
785 {
786     domdoc *This = impl_from_IPersistStreamInit(iface);
787     BSTR xmlString;
788     HRESULT hr;
789
790     TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
791
792     hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
793     if(hr == S_OK)
794     {
795         DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
796
797         hr = IStream_Write( stream, xmlString, len, NULL );
798         SysFreeString(xmlString);
799     }
800
801     TRACE("ret 0x%08x\n", hr);
802
803     return hr;
804 }
805
806 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
807     IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
808 {
809     domdoc *This = impl_from_IPersistStreamInit(iface);
810     TRACE("(%p)->(%p): stub!\n", This, pcbSize);
811     return E_NOTIMPL;
812 }
813
814 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
815     IPersistStreamInit *iface)
816 {
817     domdoc *This = impl_from_IPersistStreamInit(iface);
818     TRACE("(%p)\n", This);
819     return S_OK;
820 }
821
822 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
823 {
824     domdoc_IPersistStreamInit_QueryInterface,
825     domdoc_IPersistStreamInit_AddRef,
826     domdoc_IPersistStreamInit_Release,
827     domdoc_IPersistStreamInit_GetClassID,
828     domdoc_IPersistStreamInit_IsDirty,
829     domdoc_IPersistStreamInit_Load,
830     domdoc_IPersistStreamInit_Save,
831     domdoc_IPersistStreamInit_GetSizeMax,
832     domdoc_IPersistStreamInit_InitNew
833 };
834
835 /* ISupportErrorInfo interface */
836 static HRESULT WINAPI support_error_QueryInterface(
837     ISupportErrorInfo *iface,
838     REFIID riid, void** ppvObj )
839 {
840     domdoc *This = impl_from_ISupportErrorInfo(iface);
841     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
842 }
843
844 static ULONG WINAPI support_error_AddRef(
845     ISupportErrorInfo *iface )
846 {
847     domdoc *This = impl_from_ISupportErrorInfo(iface);
848     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
849 }
850
851 static ULONG WINAPI support_error_Release(
852     ISupportErrorInfo *iface )
853 {
854     domdoc *This = impl_from_ISupportErrorInfo(iface);
855     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
856 }
857
858 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
859     ISupportErrorInfo *iface,
860     REFIID riid )
861 {
862     FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
863     return S_FALSE;
864 }
865
866 static const struct ISupportErrorInfoVtbl support_error_vtbl =
867 {
868     support_error_QueryInterface,
869     support_error_AddRef,
870     support_error_Release,
871     support_error_InterfaceSupportsErrorInfo
872 };
873
874 /* IXMLDOMDocument2 interface */
875 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
876 {
877     domdoc *This = impl_from_IXMLDOMDocument3( iface );
878
879     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
880
881     *ppvObject = NULL;
882
883     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
884          IsEqualGUID( riid, &IID_IDispatch ) ||
885          IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
886          IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
887          IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
888          IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
889     {
890         *ppvObject = iface;
891     }
892     else if (IsEqualGUID(&IID_IPersistStream, riid) ||
893              IsEqualGUID(&IID_IPersistStreamInit, riid))
894     {
895         *ppvObject = &This->IPersistStreamInit_iface;
896     }
897     else if (IsEqualGUID(&IID_IObjectWithSite, riid))
898     {
899         *ppvObject = &This->IObjectWithSite_iface;
900     }
901     else if (IsEqualGUID(&IID_IObjectSafety, riid))
902     {
903         *ppvObject = &This->IObjectSafety_iface;
904     }
905     else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
906     {
907         *ppvObject = &This->ISupportErrorInfo_iface;
908     }
909     else if(node_query_interface(&This->node, riid, ppvObject))
910     {
911         return *ppvObject ? S_OK : E_NOINTERFACE;
912     }
913     else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
914     {
915         *ppvObject = &This->IConnectionPointContainer_iface;
916     }
917     else
918     {
919         TRACE("interface %s not implemented\n", debugstr_guid(riid));
920         return E_NOINTERFACE;
921     }
922
923     IUnknown_AddRef((IUnknown*)*ppvObject);
924
925     return S_OK;
926 }
927
928
929 static ULONG WINAPI domdoc_AddRef(
930      IXMLDOMDocument3 *iface )
931 {
932     domdoc *This = impl_from_IXMLDOMDocument3( iface );
933     ULONG ref = InterlockedIncrement( &This->ref );
934     TRACE("(%p)->(%d)\n", This, ref );
935     return ref;
936 }
937
938
939 static ULONG WINAPI domdoc_Release(
940      IXMLDOMDocument3 *iface )
941 {
942     domdoc *This = impl_from_IXMLDOMDocument3( iface );
943     LONG ref = InterlockedDecrement( &This->ref );
944
945     TRACE("(%p)->(%d)\n", This, ref );
946
947     if ( ref == 0 )
948     {
949         int eid;
950
951         if(This->bsc)
952             detach_bsc(This->bsc);
953
954         if (This->site)
955             IUnknown_Release( This->site );
956         destroy_xmlnode(&This->node);
957         if (This->stream)
958             IStream_Release(This->stream);
959
960         for (eid = 0; eid < EVENTID_LAST; eid++)
961             if (This->events[eid]) IDispatch_Release(This->events[eid]);
962
963         heap_free(This);
964     }
965
966     return ref;
967 }
968
969 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
970 {
971     domdoc *This = impl_from_IXMLDOMDocument3( iface );
972
973     TRACE("(%p)->(%p)\n", This, pctinfo);
974
975     *pctinfo = 1;
976
977     return S_OK;
978 }
979
980 static HRESULT WINAPI domdoc_GetTypeInfo(
981     IXMLDOMDocument3 *iface,
982     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
983 {
984     domdoc *This = impl_from_IXMLDOMDocument3( iface );
985     HRESULT hr;
986
987     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
988
989     hr = get_typeinfo(IXMLDOMDocument2_tid, ppTInfo);
990
991     return hr;
992 }
993
994 static HRESULT WINAPI domdoc_GetIDsOfNames(
995     IXMLDOMDocument3 *iface,
996     REFIID riid,
997     LPOLESTR* rgszNames,
998     UINT cNames,
999     LCID lcid,
1000     DISPID* rgDispId)
1001 {
1002     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1003     ITypeInfo *typeinfo;
1004     HRESULT hr;
1005
1006     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1007           lcid, rgDispId);
1008
1009     if(!rgszNames || cNames == 0 || !rgDispId)
1010         return E_INVALIDARG;
1011
1012     hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
1013     if(SUCCEEDED(hr))
1014     {
1015         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1016         ITypeInfo_Release(typeinfo);
1017     }
1018
1019     return hr;
1020 }
1021
1022
1023 static HRESULT WINAPI domdoc_Invoke(
1024     IXMLDOMDocument3 *iface,
1025     DISPID dispIdMember,
1026     REFIID riid,
1027     LCID lcid,
1028     WORD wFlags,
1029     DISPPARAMS* pDispParams,
1030     VARIANT* pVarResult,
1031     EXCEPINFO* pExcepInfo,
1032     UINT* puArgErr)
1033 {
1034     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1035     ITypeInfo *typeinfo;
1036     HRESULT hr;
1037
1038     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1039           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1040
1041     hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
1042     if(SUCCEEDED(hr))
1043     {
1044         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMDocument3_iface, dispIdMember, wFlags,
1045                 pDispParams, pVarResult, pExcepInfo, puArgErr);
1046         ITypeInfo_Release(typeinfo);
1047     }
1048
1049     return hr;
1050 }
1051
1052
1053 static HRESULT WINAPI domdoc_get_nodeName(
1054     IXMLDOMDocument3 *iface,
1055     BSTR* name )
1056 {
1057     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1058
1059     static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1060
1061     TRACE("(%p)->(%p)\n", This, name);
1062
1063     return return_bstr(documentW, name);
1064 }
1065
1066
1067 static HRESULT WINAPI domdoc_get_nodeValue(
1068     IXMLDOMDocument3 *iface,
1069     VARIANT* value )
1070 {
1071     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1072
1073     TRACE("(%p)->(%p)\n", This, value);
1074
1075     if(!value)
1076         return E_INVALIDARG;
1077
1078     V_VT(value) = VT_NULL;
1079     V_BSTR(value) = NULL; /* tests show that we should do this */
1080     return S_FALSE;
1081 }
1082
1083
1084 static HRESULT WINAPI domdoc_put_nodeValue(
1085     IXMLDOMDocument3 *iface,
1086     VARIANT value)
1087 {
1088     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1089     TRACE("(%p)->(v%d)\n", This, V_VT(&value));
1090     return E_FAIL;
1091 }
1092
1093
1094 static HRESULT WINAPI domdoc_get_nodeType(
1095     IXMLDOMDocument3 *iface,
1096     DOMNodeType* type )
1097 {
1098     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1099
1100     TRACE("(%p)->(%p)\n", This, type);
1101
1102     *type = NODE_DOCUMENT;
1103     return S_OK;
1104 }
1105
1106
1107 static HRESULT WINAPI domdoc_get_parentNode(
1108     IXMLDOMDocument3 *iface,
1109     IXMLDOMNode** parent )
1110 {
1111     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1112
1113     TRACE("(%p)->(%p)\n", This, parent);
1114
1115     return node_get_parent(&This->node, parent);
1116 }
1117
1118
1119 static HRESULT WINAPI domdoc_get_childNodes(
1120     IXMLDOMDocument3 *iface,
1121     IXMLDOMNodeList** childList )
1122 {
1123     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1124
1125     TRACE("(%p)->(%p)\n", This, childList);
1126
1127     return node_get_child_nodes(&This->node, childList);
1128 }
1129
1130
1131 static HRESULT WINAPI domdoc_get_firstChild(
1132     IXMLDOMDocument3 *iface,
1133     IXMLDOMNode** firstChild )
1134 {
1135     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1136
1137     TRACE("(%p)->(%p)\n", This, firstChild);
1138
1139     return node_get_first_child(&This->node, firstChild);
1140 }
1141
1142
1143 static HRESULT WINAPI domdoc_get_lastChild(
1144     IXMLDOMDocument3 *iface,
1145     IXMLDOMNode** lastChild )
1146 {
1147     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1148
1149     TRACE("(%p)->(%p)\n", This, lastChild);
1150
1151     return node_get_last_child(&This->node, lastChild);
1152 }
1153
1154
1155 static HRESULT WINAPI domdoc_get_previousSibling(
1156     IXMLDOMDocument3 *iface,
1157     IXMLDOMNode** previousSibling )
1158 {
1159     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1160
1161     TRACE("(%p)->(%p)\n", This, previousSibling);
1162
1163     return return_null_node(previousSibling);
1164 }
1165
1166
1167 static HRESULT WINAPI domdoc_get_nextSibling(
1168     IXMLDOMDocument3 *iface,
1169     IXMLDOMNode** nextSibling )
1170 {
1171     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1172
1173     TRACE("(%p)->(%p)\n", This, nextSibling);
1174
1175     return return_null_node(nextSibling);
1176 }
1177
1178
1179 static HRESULT WINAPI domdoc_get_attributes(
1180     IXMLDOMDocument3 *iface,
1181     IXMLDOMNamedNodeMap** attributeMap )
1182 {
1183     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1184
1185     TRACE("(%p)->(%p)\n", This, attributeMap);
1186
1187     return return_null_ptr((void**)attributeMap);
1188 }
1189
1190
1191 static HRESULT WINAPI domdoc_insertBefore(
1192     IXMLDOMDocument3 *iface,
1193     IXMLDOMNode* newChild,
1194     VARIANT refChild,
1195     IXMLDOMNode** outNewChild )
1196 {
1197     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1198
1199     TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1200
1201     return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1202 }
1203
1204
1205 static HRESULT WINAPI domdoc_replaceChild(
1206     IXMLDOMDocument3 *iface,
1207     IXMLDOMNode* newChild,
1208     IXMLDOMNode* oldChild,
1209     IXMLDOMNode** outOldChild)
1210 {
1211     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1212
1213     TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1214
1215     return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1216 }
1217
1218
1219 static HRESULT WINAPI domdoc_removeChild(
1220     IXMLDOMDocument3 *iface,
1221     IXMLDOMNode  *child,
1222     IXMLDOMNode **oldChild)
1223 {
1224     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1225     TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1226     return node_remove_child(&This->node, child, oldChild);
1227 }
1228
1229
1230 static HRESULT WINAPI domdoc_appendChild(
1231     IXMLDOMDocument3 *iface,
1232     IXMLDOMNode  *child,
1233     IXMLDOMNode **outChild)
1234 {
1235     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1236     TRACE("(%p)->(%p %p)\n", This, child, outChild);
1237     return node_append_child(&This->node, child, outChild);
1238 }
1239
1240
1241 static HRESULT WINAPI domdoc_hasChildNodes(
1242     IXMLDOMDocument3 *iface,
1243     VARIANT_BOOL *ret)
1244 {
1245     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1246     TRACE("(%p)->(%p)\n", This, ret);
1247     return node_has_childnodes(&This->node, ret);
1248 }
1249
1250
1251 static HRESULT WINAPI domdoc_get_ownerDocument(
1252     IXMLDOMDocument3 *iface,
1253     IXMLDOMDocument **doc)
1254 {
1255     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1256     TRACE("(%p)->(%p)\n", This, doc);
1257     return node_get_owner_doc(&This->node, doc);
1258 }
1259
1260
1261 static HRESULT WINAPI domdoc_cloneNode(
1262     IXMLDOMDocument3 *iface,
1263     VARIANT_BOOL deep,
1264     IXMLDOMNode** outNode)
1265 {
1266     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1267     TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1268     return node_clone( &This->node, deep, outNode );
1269 }
1270
1271
1272 static HRESULT WINAPI domdoc_get_nodeTypeString(
1273     IXMLDOMDocument3 *iface,
1274     BSTR *p)
1275 {
1276     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1277     static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1278
1279     TRACE("(%p)->(%p)\n", This, p);
1280
1281     return return_bstr(documentW, p);
1282 }
1283
1284
1285 static HRESULT WINAPI domdoc_get_text(
1286     IXMLDOMDocument3 *iface,
1287     BSTR *p)
1288 {
1289     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1290     TRACE("(%p)->(%p)\n", This, p);
1291     return node_get_text(&This->node, p);
1292 }
1293
1294
1295 static HRESULT WINAPI domdoc_put_text(
1296     IXMLDOMDocument3 *iface,
1297     BSTR text )
1298 {
1299     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1300     TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1301     return E_FAIL;
1302 }
1303
1304
1305 static HRESULT WINAPI domdoc_get_specified(
1306     IXMLDOMDocument3 *iface,
1307     VARIANT_BOOL* isSpecified )
1308 {
1309     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1310     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1311     *isSpecified = VARIANT_TRUE;
1312     return S_OK;
1313 }
1314
1315
1316 static HRESULT WINAPI domdoc_get_definition(
1317     IXMLDOMDocument3 *iface,
1318     IXMLDOMNode** definitionNode )
1319 {
1320     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1321     FIXME("(%p)->(%p)\n", This, definitionNode);
1322     return E_NOTIMPL;
1323 }
1324
1325
1326 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1327     IXMLDOMDocument3 *iface,
1328     VARIANT* v )
1329 {
1330     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1331     TRACE("(%p)->(%p)\n", This, v);
1332     return return_null_var(v);
1333 }
1334
1335 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1336     IXMLDOMDocument3 *iface,
1337     VARIANT typedValue )
1338 {
1339     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1340     FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1341     return E_NOTIMPL;
1342 }
1343
1344
1345 static HRESULT WINAPI domdoc_get_dataType(
1346     IXMLDOMDocument3 *iface,
1347     VARIANT* typename )
1348 {
1349     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1350     TRACE("(%p)->(%p)\n", This, typename);
1351     return return_null_var( typename );
1352 }
1353
1354
1355 static HRESULT WINAPI domdoc_put_dataType(
1356     IXMLDOMDocument3 *iface,
1357     BSTR dataTypeName )
1358 {
1359     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1360
1361     FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1362
1363     if(!dataTypeName)
1364         return E_INVALIDARG;
1365
1366     return E_FAIL;
1367 }
1368
1369 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1370 {
1371     return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1372 }
1373
1374 static HRESULT WINAPI domdoc_get_xml(
1375     IXMLDOMDocument3 *iface,
1376     BSTR* p)
1377 {
1378     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1379     xmlSaveCtxtPtr ctxt;
1380     xmlBufferPtr buf;
1381     int options;
1382     long ret;
1383
1384     TRACE("(%p)->(%p)\n", This, p);
1385
1386     if(!p)
1387         return E_INVALIDARG;
1388
1389     *p = NULL;
1390
1391     buf = xmlBufferCreate();
1392     if(!buf)
1393         return E_OUTOFMEMORY;
1394
1395     options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1396     ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1397
1398     if(!ctxt)
1399     {
1400         xmlBufferFree(buf);
1401         return E_OUTOFMEMORY;
1402     }
1403
1404     ret = xmlSaveDoc(ctxt, get_doc(This));
1405     /* flushes on close */
1406     xmlSaveClose(ctxt);
1407
1408     TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1409     if(ret != -1 && xmlBufferLength(buf) > 0)
1410     {
1411         BSTR content;
1412
1413         content = bstr_from_xmlChar(xmlBufferContent(buf));
1414         content = EnsureCorrectEOL(content);
1415
1416         *p = content;
1417     }
1418     else
1419     {
1420         *p = SysAllocStringLen(NULL, 0);
1421     }
1422
1423     xmlBufferFree(buf);
1424
1425     return *p ? S_OK : E_OUTOFMEMORY;
1426 }
1427
1428
1429 static HRESULT WINAPI domdoc_transformNode(
1430     IXMLDOMDocument3 *iface,
1431     IXMLDOMNode *node,
1432     BSTR *p)
1433 {
1434     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1435     TRACE("(%p)->(%p %p)\n", This, node, p);
1436     return node_transform_node(&This->node, node, p);
1437 }
1438
1439
1440 static HRESULT WINAPI domdoc_selectNodes(
1441     IXMLDOMDocument3 *iface,
1442     BSTR p,
1443     IXMLDOMNodeList **outList)
1444 {
1445     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1446     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1447     return node_select_nodes(&This->node, p, outList);
1448 }
1449
1450
1451 static HRESULT WINAPI domdoc_selectSingleNode(
1452     IXMLDOMDocument3 *iface,
1453     BSTR p,
1454     IXMLDOMNode **outNode)
1455 {
1456     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1457     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1458     return node_select_singlenode(&This->node, p, outNode);
1459 }
1460
1461
1462 static HRESULT WINAPI domdoc_get_parsed(
1463     IXMLDOMDocument3 *iface,
1464     VARIANT_BOOL* isParsed )
1465 {
1466     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1467     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1468     *isParsed = VARIANT_TRUE;
1469     return S_OK;
1470 }
1471
1472
1473 static HRESULT WINAPI domdoc_get_namespaceURI(
1474     IXMLDOMDocument3 *iface,
1475     BSTR* namespaceURI )
1476 {
1477     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1478     TRACE("(%p)->(%p)\n", This, namespaceURI);
1479     return node_get_namespaceURI(&This->node, namespaceURI);
1480 }
1481
1482
1483 static HRESULT WINAPI domdoc_get_prefix(
1484     IXMLDOMDocument3 *iface,
1485     BSTR* prefix )
1486 {
1487     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1488     TRACE("(%p)->(%p)\n", This, prefix);
1489     return return_null_bstr( prefix );
1490 }
1491
1492
1493 static HRESULT WINAPI domdoc_get_baseName(
1494     IXMLDOMDocument3 *iface,
1495     BSTR* name )
1496 {
1497     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1498     TRACE("(%p)->(%p)\n", This, name);
1499     return return_null_bstr( name );
1500 }
1501
1502
1503 static HRESULT WINAPI domdoc_transformNodeToObject(
1504     IXMLDOMDocument3 *iface,
1505     IXMLDOMNode* stylesheet,
1506     VARIANT outputObject)
1507 {
1508     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1509     FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1510     return E_NOTIMPL;
1511 }
1512
1513
1514 static HRESULT WINAPI domdoc_get_doctype(
1515     IXMLDOMDocument3 *iface,
1516     IXMLDOMDocumentType** doctype )
1517 {
1518     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1519     IXMLDOMNode *node;
1520     xmlDtdPtr dtd;
1521     HRESULT hr;
1522
1523     TRACE("(%p)->(%p)\n", This, doctype);
1524
1525     if (!doctype) return E_INVALIDARG;
1526
1527     *doctype = NULL;
1528
1529     dtd = xmlGetIntSubset(get_doc(This));
1530     if (!dtd) return S_FALSE;
1531
1532     node = create_node((xmlNodePtr)dtd);
1533     if (!node) return S_FALSE;
1534
1535     hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1536     IXMLDOMNode_Release(node);
1537
1538     return hr;
1539 }
1540
1541
1542 static HRESULT WINAPI domdoc_get_implementation(
1543     IXMLDOMDocument3 *iface,
1544     IXMLDOMImplementation** impl )
1545 {
1546     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1547
1548     TRACE("(%p)->(%p)\n", This, impl);
1549
1550     if(!impl)
1551         return E_INVALIDARG;
1552
1553     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1554
1555     return S_OK;
1556 }
1557
1558 static HRESULT WINAPI domdoc_get_documentElement(
1559     IXMLDOMDocument3 *iface,
1560     IXMLDOMElement** DOMElement )
1561 {
1562     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1563     IXMLDOMNode *element_node;
1564     xmlNodePtr root;
1565     HRESULT hr;
1566
1567     TRACE("(%p)->(%p)\n", This, DOMElement);
1568
1569     if(!DOMElement)
1570         return E_INVALIDARG;
1571
1572     *DOMElement = NULL;
1573
1574     root = xmlDocGetRootElement( get_doc(This) );
1575     if ( !root )
1576         return S_FALSE;
1577
1578     element_node = create_node( root );
1579     if(!element_node) return S_FALSE;
1580
1581     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1582     IXMLDOMNode_Release(element_node);
1583
1584     return hr;
1585 }
1586
1587
1588 static HRESULT WINAPI domdoc_put_documentElement(
1589     IXMLDOMDocument3 *iface,
1590     IXMLDOMElement* DOMElement )
1591 {
1592     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1593     IXMLDOMNode *elementNode;
1594     xmlNodePtr oldRoot;
1595     xmlnode *xmlNode;
1596     HRESULT hr;
1597
1598     TRACE("(%p)->(%p)\n", This, DOMElement);
1599
1600     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1601     if(FAILED(hr))
1602         return hr;
1603
1604     xmlNode = get_node_obj( elementNode );
1605     if(!xmlNode) return E_FAIL;
1606
1607     if(!xmlNode->node->parent)
1608         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1609             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1610
1611     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1612     IXMLDOMNode_Release( elementNode );
1613
1614     if(oldRoot)
1615         xmldoc_add_orphan(oldRoot->doc, oldRoot);
1616
1617     return S_OK;
1618 }
1619
1620
1621 static HRESULT WINAPI domdoc_createElement(
1622     IXMLDOMDocument3 *iface,
1623     BSTR tagname,
1624     IXMLDOMElement** element )
1625 {
1626     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1627     IXMLDOMNode *node;
1628     VARIANT type;
1629     HRESULT hr;
1630
1631     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1632
1633     if (!element || !tagname) return E_INVALIDARG;
1634
1635     V_VT(&type) = VT_I1;
1636     V_I1(&type) = NODE_ELEMENT;
1637
1638     hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1639     if (hr == S_OK)
1640     {
1641         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1642         IXMLDOMNode_Release(node);
1643     }
1644
1645     return hr;
1646 }
1647
1648
1649 static HRESULT WINAPI domdoc_createDocumentFragment(
1650     IXMLDOMDocument3 *iface,
1651     IXMLDOMDocumentFragment** frag )
1652 {
1653     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1654     IXMLDOMNode *node;
1655     VARIANT type;
1656     HRESULT hr;
1657
1658     TRACE("(%p)->(%p)\n", This, frag);
1659
1660     if (!frag) return E_INVALIDARG;
1661
1662     *frag = NULL;
1663
1664     V_VT(&type) = VT_I1;
1665     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1666
1667     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1668     if (hr == S_OK)
1669     {
1670         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1671         IXMLDOMNode_Release(node);
1672     }
1673
1674     return hr;
1675 }
1676
1677
1678 static HRESULT WINAPI domdoc_createTextNode(
1679     IXMLDOMDocument3 *iface,
1680     BSTR data,
1681     IXMLDOMText** text )
1682 {
1683     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1684     IXMLDOMNode *node;
1685     VARIANT type;
1686     HRESULT hr;
1687
1688     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1689
1690     if (!text) return E_INVALIDARG;
1691
1692     *text = NULL;
1693
1694     V_VT(&type) = VT_I1;
1695     V_I1(&type) = NODE_TEXT;
1696
1697     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1698     if (hr == S_OK)
1699     {
1700         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1701         IXMLDOMNode_Release(node);
1702         hr = IXMLDOMText_put_data(*text, data);
1703     }
1704
1705     return hr;
1706 }
1707
1708
1709 static HRESULT WINAPI domdoc_createComment(
1710     IXMLDOMDocument3 *iface,
1711     BSTR data,
1712     IXMLDOMComment** comment )
1713 {
1714     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1715     VARIANT type;
1716     HRESULT hr;
1717     IXMLDOMNode *node;
1718
1719     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1720
1721     if (!comment) return E_INVALIDARG;
1722
1723     *comment = NULL;
1724
1725     V_VT(&type) = VT_I1;
1726     V_I1(&type) = NODE_COMMENT;
1727
1728     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1729     if (hr == S_OK)
1730     {
1731         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1732         IXMLDOMNode_Release(node);
1733         hr = IXMLDOMComment_put_data(*comment, data);
1734     }
1735
1736     return hr;
1737 }
1738
1739
1740 static HRESULT WINAPI domdoc_createCDATASection(
1741     IXMLDOMDocument3 *iface,
1742     BSTR data,
1743     IXMLDOMCDATASection** cdata )
1744 {
1745     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1746     IXMLDOMNode *node;
1747     VARIANT type;
1748     HRESULT hr;
1749
1750     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1751
1752     if (!cdata) return E_INVALIDARG;
1753
1754     *cdata = NULL;
1755
1756     V_VT(&type) = VT_I1;
1757     V_I1(&type) = NODE_CDATA_SECTION;
1758
1759     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1760     if (hr == S_OK)
1761     {
1762         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1763         IXMLDOMNode_Release(node);
1764         hr = IXMLDOMCDATASection_put_data(*cdata, data);
1765     }
1766
1767     return hr;
1768 }
1769
1770
1771 static HRESULT WINAPI domdoc_createProcessingInstruction(
1772     IXMLDOMDocument3 *iface,
1773     BSTR target,
1774     BSTR data,
1775     IXMLDOMProcessingInstruction** pi )
1776 {
1777     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1778     IXMLDOMNode *node;
1779     VARIANT type;
1780     HRESULT hr;
1781
1782     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1783
1784     if (!pi) return E_INVALIDARG;
1785
1786     *pi = NULL;
1787
1788     V_VT(&type) = VT_I1;
1789     V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1790
1791     hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1792     if (hr == S_OK)
1793     {
1794         xmlnode *node_obj;
1795
1796         /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1797         node_obj = get_node_obj(node);
1798         hr = node_set_content(node_obj, data);
1799
1800         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1801         IXMLDOMNode_Release(node);
1802     }
1803
1804     return hr;
1805 }
1806
1807
1808 static HRESULT WINAPI domdoc_createAttribute(
1809     IXMLDOMDocument3 *iface,
1810     BSTR name,
1811     IXMLDOMAttribute** attribute )
1812 {
1813     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1814     IXMLDOMNode *node;
1815     VARIANT type;
1816     HRESULT hr;
1817
1818     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1819
1820     if (!attribute || !name) return E_INVALIDARG;
1821
1822     V_VT(&type) = VT_I1;
1823     V_I1(&type) = NODE_ATTRIBUTE;
1824
1825     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1826     if (hr == S_OK)
1827     {
1828         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1829         IXMLDOMNode_Release(node);
1830     }
1831
1832     return hr;
1833 }
1834
1835
1836 static HRESULT WINAPI domdoc_createEntityReference(
1837     IXMLDOMDocument3 *iface,
1838     BSTR name,
1839     IXMLDOMEntityReference** entityref )
1840 {
1841     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1842     IXMLDOMNode *node;
1843     VARIANT type;
1844     HRESULT hr;
1845
1846     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1847
1848     if (!entityref) return E_INVALIDARG;
1849
1850     *entityref = NULL;
1851
1852     V_VT(&type) = VT_I1;
1853     V_I1(&type) = NODE_ENTITY_REFERENCE;
1854
1855     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1856     if (hr == S_OK)
1857     {
1858         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1859         IXMLDOMNode_Release(node);
1860     }
1861
1862     return hr;
1863 }
1864
1865 xmlChar* tagName_to_XPath(const BSTR tagName)
1866 {
1867     xmlChar *query, *tmp;
1868     static const xmlChar mod_pre[] = "*[local-name()='";
1869     static const xmlChar mod_post[] = "']";
1870     static const xmlChar prefix[] = "descendant::";
1871     const WCHAR *tokBegin, *tokEnd;
1872     int len;
1873
1874     query = xmlStrdup(prefix);
1875
1876     tokBegin = tagName;
1877     while (tokBegin && *tokBegin)
1878     {
1879         switch (*tokBegin)
1880         {
1881         case '/':
1882             query = xmlStrcat(query, BAD_CAST "/");
1883             ++tokBegin;
1884             break;
1885         case '*':
1886             query = xmlStrcat(query, BAD_CAST "*");
1887             ++tokBegin;
1888             break;
1889         default:
1890             query = xmlStrcat(query, mod_pre);
1891             tokEnd = tokBegin;
1892             while (*tokEnd && *tokEnd != '/')
1893                 ++tokEnd;
1894             len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1895             tmp = xmlMalloc(len);
1896             WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1897             query = xmlStrncat(query, tmp, len);
1898             xmlFree(tmp);
1899             tokBegin = tokEnd;
1900             query = xmlStrcat(query, mod_post);
1901         }
1902     }
1903
1904     return query;
1905 }
1906
1907 static HRESULT WINAPI domdoc_getElementsByTagName(
1908     IXMLDOMDocument3 *iface,
1909     BSTR tagName,
1910     IXMLDOMNodeList** resultList )
1911 {
1912     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1913     xmlChar *query;
1914     HRESULT hr;
1915     BOOL XPath;
1916
1917     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1918
1919     if (!tagName || !resultList) return E_INVALIDARG;
1920
1921     XPath = This->properties->XPath;
1922     This->properties->XPath = TRUE;
1923     query = tagName_to_XPath(tagName);
1924     hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1925     xmlFree(query);
1926     This->properties->XPath = XPath;
1927
1928     return hr;
1929 }
1930
1931 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1932 {
1933     VARIANT tmp;
1934     HRESULT hr;
1935
1936     VariantInit(&tmp);
1937     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1938     if(FAILED(hr))
1939         return E_INVALIDARG;
1940
1941     *type = V_I4(&tmp);
1942
1943     return S_OK;
1944 }
1945
1946 static HRESULT WINAPI domdoc_createNode(
1947     IXMLDOMDocument3 *iface,
1948     VARIANT Type,
1949     BSTR name,
1950     BSTR namespaceURI,
1951     IXMLDOMNode** node )
1952 {
1953     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1954     DOMNodeType node_type;
1955     xmlNodePtr xmlnode;
1956     xmlChar *xml_name, *href;
1957     HRESULT hr;
1958
1959     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1960
1961     if(!node) return E_INVALIDARG;
1962
1963     hr = get_node_type(Type, &node_type);
1964     if(FAILED(hr)) return hr;
1965
1966     if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1967         FIXME("nodes with namespaces currently not supported.\n");
1968
1969     TRACE("node_type %d\n", node_type);
1970
1971     /* exit earlier for types that need name */
1972     switch(node_type)
1973     {
1974     case NODE_ELEMENT:
1975     case NODE_ATTRIBUTE:
1976     case NODE_ENTITY_REFERENCE:
1977     case NODE_PROCESSING_INSTRUCTION:
1978         if (!name || *name == 0) return E_FAIL;
1979     default:
1980         break;
1981     }
1982
1983     xml_name = xmlchar_from_wchar(name);
1984     /* prevent empty href to be allocated */
1985     href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1986
1987     switch(node_type)
1988     {
1989     case NODE_ELEMENT:
1990     {
1991         xmlChar *local, *prefix;
1992
1993         local = xmlSplitQName2(xml_name, &prefix);
1994
1995         xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1996
1997         /* allow to create default namespace xmlns= */
1998         if (local || (href && *href))
1999         {
2000             xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
2001             xmlSetNs(xmlnode, ns);
2002         }
2003
2004         xmlFree(local);
2005         xmlFree(prefix);
2006
2007         break;
2008     }
2009     case NODE_ATTRIBUTE:
2010         xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
2011         break;
2012     case NODE_TEXT:
2013         xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2014         break;
2015     case NODE_CDATA_SECTION:
2016         xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2017         break;
2018     case NODE_ENTITY_REFERENCE:
2019         xmlnode = xmlNewReference(get_doc(This), xml_name);
2020         break;
2021     case NODE_PROCESSING_INSTRUCTION:
2022 #ifdef HAVE_XMLNEWDOCPI
2023         xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2024 #else
2025         FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2026         xmlnode = NULL;
2027 #endif
2028         break;
2029     case NODE_COMMENT:
2030         xmlnode = xmlNewDocComment(get_doc(This), NULL);
2031         break;
2032     case NODE_DOCUMENT_FRAGMENT:
2033         xmlnode = xmlNewDocFragment(get_doc(This));
2034         break;
2035     /* unsupported types */
2036     case NODE_DOCUMENT:
2037     case NODE_DOCUMENT_TYPE:
2038     case NODE_ENTITY:
2039     case NODE_NOTATION:
2040         heap_free(xml_name);
2041         return E_INVALIDARG;
2042     default:
2043         FIXME("unhandled node type %d\n", node_type);
2044         xmlnode = NULL;
2045         break;
2046     }
2047
2048     *node = create_node(xmlnode);
2049     heap_free(xml_name);
2050     heap_free(href);
2051
2052     if(*node)
2053     {
2054         TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2055         xmldoc_add_orphan(xmlnode->doc, xmlnode);
2056         return S_OK;
2057     }
2058
2059     return E_FAIL;
2060 }
2061
2062 static HRESULT WINAPI domdoc_nodeFromID(
2063     IXMLDOMDocument3 *iface,
2064     BSTR idString,
2065     IXMLDOMNode** node )
2066 {
2067     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2068     FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2069     return E_NOTIMPL;
2070 }
2071
2072 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2073 {
2074     domdoc *This = obj;
2075     xmlDocPtr xmldoc;
2076
2077     xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2078     if(xmldoc) {
2079         xmldoc->_private = create_priv();
2080         return attach_xmldoc(This, xmldoc);
2081     }
2082
2083     return S_OK;
2084 }
2085
2086 static HRESULT doread( domdoc *This, LPWSTR filename )
2087 {
2088     bsc_t *bsc;
2089     HRESULT hr;
2090
2091     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2092     if(FAILED(hr))
2093         return hr;
2094
2095     if(This->bsc)
2096         detach_bsc(This->bsc);
2097
2098     This->bsc = bsc;
2099     return S_OK;
2100 }
2101
2102 static HRESULT WINAPI domdoc_load(
2103     IXMLDOMDocument3 *iface,
2104     VARIANT source,
2105     VARIANT_BOOL* isSuccessful )
2106 {
2107     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2108     LPWSTR filename = NULL;
2109     HRESULT hr = S_FALSE;
2110     IXMLDOMDocument3 *pNewDoc = NULL;
2111     IStream *pStream = NULL;
2112     xmlDocPtr xmldoc;
2113
2114     TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2115
2116     if (!isSuccessful)
2117         return E_POINTER;
2118     *isSuccessful = VARIANT_FALSE;
2119
2120     assert( &This->node );
2121
2122     switch( V_VT(&source) )
2123     {
2124     case VT_BSTR:
2125         filename = V_BSTR(&source);
2126         break;
2127     case VT_BSTR|VT_BYREF:
2128         if (!V_BSTRREF(&source)) return E_INVALIDARG;
2129         filename = *V_BSTRREF(&source);
2130         break;
2131     case VT_ARRAY|VT_UI1:
2132         {
2133             SAFEARRAY *psa = V_ARRAY(&source);
2134             char *str;
2135             LONG len;
2136             UINT dim = SafeArrayGetDim(psa);
2137
2138             switch (dim)
2139             {
2140             case 0:
2141                 ERR("SAFEARRAY == NULL\n");
2142                 hr = This->error = E_INVALIDARG;
2143                 break;
2144             case 1:
2145                 /* Only takes UTF-8 strings.
2146                  * NOT NULL-terminated. */
2147                 SafeArrayAccessData(psa, (void**)&str);
2148                 SafeArrayGetUBound(psa, 1, &len);
2149
2150                 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2151                 {
2152                     hr = This->error = S_OK;
2153                     *isSuccessful = VARIANT_TRUE;
2154                     TRACE("parsed document %p\n", xmldoc);
2155                 }
2156                 else
2157                 {
2158                     This->error = E_FAIL;
2159                     TRACE("failed to parse document\n");
2160                 }
2161
2162                 SafeArrayUnaccessData(psa);
2163
2164                 if(xmldoc)
2165                 {
2166                     xmldoc->_private = create_priv();
2167                     return attach_xmldoc(This, xmldoc);
2168                 }
2169                 break;
2170             default:
2171                 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2172                 hr = This->error = E_NOTIMPL;
2173             }
2174         }
2175         break;
2176     case VT_UNKNOWN:
2177         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2178         if(hr == S_OK)
2179         {
2180             if(pNewDoc)
2181             {
2182                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2183                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2184                 hr = attach_xmldoc(This, xmldoc);
2185
2186                 if(SUCCEEDED(hr))
2187                     *isSuccessful = VARIANT_TRUE;
2188
2189                 return hr;
2190             }
2191         }
2192         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2193         if(hr == S_OK)
2194         {
2195             IPersistStream *pDocStream;
2196             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2197             if(hr == S_OK)
2198             {
2199                 hr = IPersistStream_Load(pDocStream, pStream);
2200                 IStream_Release(pStream);
2201                 if(hr == S_OK)
2202                 {
2203                     *isSuccessful = VARIANT_TRUE;
2204
2205                     TRACE("Using IStream to load Document\n");
2206                     return S_OK;
2207                 }
2208                 else
2209                 {
2210                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2211                 }
2212             }
2213             else
2214             {
2215                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2216             }
2217         }
2218         else
2219         {
2220             /* ISequentialStream */
2221             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2222         }
2223         break;
2224      default:
2225             FIXME("VT type not supported (%d)\n", V_VT(&source));
2226     }
2227
2228     if ( filename )
2229     {
2230         hr = doread( This, filename );
2231
2232         if ( FAILED(hr) )
2233             This->error = E_FAIL;
2234         else
2235         {
2236             hr = This->error = S_OK;
2237             *isSuccessful = VARIANT_TRUE;
2238         }
2239     }
2240
2241     if(!filename || FAILED(hr)) {
2242         xmldoc = xmlNewDoc(NULL);
2243         xmldoc->_private = create_priv();
2244         hr = attach_xmldoc(This, xmldoc);
2245         if(SUCCEEDED(hr))
2246             hr = S_FALSE;
2247     }
2248
2249     TRACE("ret (%d)\n", hr);
2250
2251     return hr;
2252 }
2253
2254
2255 static HRESULT WINAPI domdoc_get_readyState(
2256     IXMLDOMDocument3 *iface,
2257     LONG *value )
2258 {
2259     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2260     FIXME("stub! (%p)->(%p)\n", This, value);
2261
2262     if (!value)
2263         return E_INVALIDARG;
2264
2265     *value = READYSTATE_COMPLETE;
2266     return S_OK;
2267 }
2268
2269
2270 static HRESULT WINAPI domdoc_get_parseError(
2271     IXMLDOMDocument3 *iface,
2272     IXMLDOMParseError** errorObj )
2273 {
2274     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2275     static const WCHAR err[] = {'e','r','r','o','r',0};
2276     BSTR error_string = NULL;
2277
2278     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2279
2280     if(This->error)
2281         error_string = SysAllocString(err);
2282
2283     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2284     if(!*errorObj) return E_OUTOFMEMORY;
2285     return S_OK;
2286 }
2287
2288
2289 static HRESULT WINAPI domdoc_get_url(
2290     IXMLDOMDocument3 *iface,
2291     BSTR* urlString )
2292 {
2293     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2294     FIXME("(%p)->(%p)\n", This, urlString);
2295     return E_NOTIMPL;
2296 }
2297
2298
2299 static HRESULT WINAPI domdoc_get_async(
2300     IXMLDOMDocument3 *iface,
2301     VARIANT_BOOL* isAsync )
2302 {
2303     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2304
2305     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2306     *isAsync = This->async;
2307     return S_OK;
2308 }
2309
2310
2311 static HRESULT WINAPI domdoc_put_async(
2312     IXMLDOMDocument3 *iface,
2313     VARIANT_BOOL isAsync )
2314 {
2315     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2316
2317     TRACE("(%p)->(%d)\n", This, isAsync);
2318     This->async = isAsync;
2319     return S_OK;
2320 }
2321
2322
2323 static HRESULT WINAPI domdoc_abort(
2324     IXMLDOMDocument3 *iface )
2325 {
2326     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2327     FIXME("%p\n", This);
2328     return E_NOTIMPL;
2329 }
2330
2331
2332 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2333 static HRESULT WINAPI domdoc_loadXML(
2334     IXMLDOMDocument3 *iface,
2335     BSTR bstrXML,
2336     VARIANT_BOOL* isSuccessful )
2337 {
2338     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2339     xmlDocPtr xmldoc = NULL;
2340     HRESULT hr = S_FALSE, hr2;
2341
2342     TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2343
2344     assert ( &This->node );
2345
2346     if ( isSuccessful )
2347     {
2348         *isSuccessful = VARIANT_FALSE;
2349
2350         if ( bstrXML )
2351         {
2352             xmldoc = doparse(This, (LPCSTR)bstrXML, lstrlenW(bstrXML) * sizeof(*bstrXML), XML_CHAR_ENCODING_UTF16LE);
2353             if ( !xmldoc )
2354             {
2355                 This->error = E_FAIL;
2356                 TRACE("failed to parse document\n");
2357             }
2358             else
2359             {
2360                 hr = This->error = S_OK;
2361                 *isSuccessful = VARIANT_TRUE;
2362                 TRACE("parsed document %p\n", xmldoc);
2363             }
2364         }
2365     }
2366     if(!xmldoc)
2367         xmldoc = xmlNewDoc(NULL);
2368
2369     xmldoc->_private = create_priv();
2370
2371     hr2 = attach_xmldoc(This, xmldoc);
2372     if( FAILED(hr2) )
2373         hr = hr2;
2374
2375     return hr;
2376 }
2377
2378 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2379 {
2380     DWORD written = -1;
2381
2382     if(!WriteFile(ctx, buffer, len, &written, NULL))
2383     {
2384         WARN("write error\n");
2385         return -1;
2386     }
2387     else
2388         return written;
2389 }
2390
2391 static int XMLCALL domdoc_save_closecallback(void *ctx)
2392 {
2393     return CloseHandle(ctx) ? 0 : -1;
2394 }
2395
2396 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2397 {
2398     ULONG written = 0;
2399     HRESULT hr;
2400
2401     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2402     if (hr != S_OK)
2403     {
2404         WARN("stream write error: 0x%08x\n", hr);
2405         return -1;
2406     }
2407     else
2408         return written;
2409 }
2410
2411 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2412 {
2413     IStream_Release((IStream*)ctx);
2414     return 0;
2415 }
2416
2417 static HRESULT WINAPI domdoc_save(
2418     IXMLDOMDocument3 *iface,
2419     VARIANT destination )
2420 {
2421     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2422     xmlSaveCtxtPtr ctx = NULL;
2423     xmlNodePtr xmldecl;
2424     HRESULT ret = S_OK;
2425
2426     TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2427
2428     switch (V_VT(&destination))
2429     {
2430     case VT_UNKNOWN:
2431         {
2432             IUnknown *pUnk = V_UNKNOWN(&destination);
2433             IXMLDOMDocument2 *document;
2434             IStream *stream;
2435
2436             ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2437             if(ret == S_OK)
2438             {
2439                 VARIANT_BOOL success;
2440                 BSTR xml;
2441
2442                 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2443                 if(ret == S_OK)
2444                 {
2445                     ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2446                     SysFreeString(xml);
2447                 }
2448
2449                 IXMLDOMDocument3_Release(document);
2450                 return ret;
2451             }
2452
2453             ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2454             if(ret == S_OK)
2455             {
2456                 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2457                     domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2458
2459                 if(!ctx)
2460                 {
2461                     IStream_Release(stream);
2462                     return E_FAIL;
2463                 }
2464             }
2465         }
2466         break;
2467
2468     case VT_BSTR:
2469     case VT_BSTR | VT_BYREF:
2470         {
2471             /* save with file path */
2472             HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2473                                          GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2474             if( handle == INVALID_HANDLE_VALUE )
2475             {
2476                 WARN("failed to create file\n");
2477                 return E_FAIL;
2478             }
2479
2480             /* disable top XML declaration */
2481             ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2482                               handle, NULL, XML_SAVE_NO_DECL);
2483             if (!ctx)
2484             {
2485                 CloseHandle(handle);
2486                 return E_FAIL;
2487             }
2488         }
2489         break;
2490
2491     default:
2492         FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2493         return S_FALSE;
2494     }
2495
2496     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2497     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2498     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2499
2500     /* will release resources through close callback */
2501     xmlSaveClose(ctx);
2502
2503     return ret;
2504 }
2505
2506 static HRESULT WINAPI domdoc_get_validateOnParse(
2507     IXMLDOMDocument3 *iface,
2508     VARIANT_BOOL* isValidating )
2509 {
2510     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2511     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2512     *isValidating = This->validating;
2513     return S_OK;
2514 }
2515
2516
2517 static HRESULT WINAPI domdoc_put_validateOnParse(
2518     IXMLDOMDocument3 *iface,
2519     VARIANT_BOOL isValidating )
2520 {
2521     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2522     TRACE("(%p)->(%d)\n", This, isValidating);
2523     This->validating = isValidating;
2524     return S_OK;
2525 }
2526
2527
2528 static HRESULT WINAPI domdoc_get_resolveExternals(
2529     IXMLDOMDocument3 *iface,
2530     VARIANT_BOOL* isResolving )
2531 {
2532     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2533     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2534     *isResolving = This->resolving;
2535     return S_OK;
2536 }
2537
2538
2539 static HRESULT WINAPI domdoc_put_resolveExternals(
2540     IXMLDOMDocument3 *iface,
2541     VARIANT_BOOL isResolving )
2542 {
2543     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2544     TRACE("(%p)->(%d)\n", This, isResolving);
2545     This->resolving = isResolving;
2546     return S_OK;
2547 }
2548
2549
2550 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2551     IXMLDOMDocument3 *iface,
2552     VARIANT_BOOL* isPreserving )
2553 {
2554     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2555     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2556     *isPreserving = This->properties->preserving;
2557     return S_OK;
2558 }
2559
2560
2561 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2562     IXMLDOMDocument3 *iface,
2563     VARIANT_BOOL isPreserving )
2564 {
2565     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2566     TRACE("(%p)->(%d)\n", This, isPreserving);
2567     This->properties->preserving = isPreserving;
2568     return S_OK;
2569 }
2570
2571
2572 static HRESULT WINAPI domdoc_put_onreadystatechange(
2573     IXMLDOMDocument3 *iface,
2574     VARIANT event )
2575 {
2576     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2577
2578     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2579     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2580 }
2581
2582
2583 static HRESULT WINAPI domdoc_put_onDataAvailable(
2584     IXMLDOMDocument3 *iface,
2585     VARIANT onDataAvailableSink )
2586 {
2587     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2588     FIXME("%p\n", This);
2589     return E_NOTIMPL;
2590 }
2591
2592 static HRESULT WINAPI domdoc_put_onTransformNode(
2593     IXMLDOMDocument3 *iface,
2594     VARIANT onTransformNodeSink )
2595 {
2596     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2597     FIXME("%p\n", This);
2598     return E_NOTIMPL;
2599 }
2600
2601 static HRESULT WINAPI domdoc_get_namespaces(
2602     IXMLDOMDocument3* iface,
2603     IXMLDOMSchemaCollection** schemaCollection )
2604 {
2605     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2606     FIXME("(%p)->(%p)\n", This, schemaCollection);
2607     return E_NOTIMPL;
2608 }
2609
2610 static HRESULT WINAPI domdoc_get_schemas(
2611     IXMLDOMDocument3* iface,
2612     VARIANT* var1 )
2613 {
2614     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2615     HRESULT hr = S_FALSE;
2616     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2617
2618     TRACE("(%p)->(%p)\n", This, var1);
2619
2620     VariantInit(var1); /* Test shows we don't call VariantClear here */
2621     V_VT(var1) = VT_NULL;
2622
2623     if(cur_schema)
2624     {
2625         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2626         if(SUCCEEDED(hr))
2627             V_VT(var1) = VT_DISPATCH;
2628     }
2629     return hr;
2630 }
2631
2632 static HRESULT WINAPI domdoc_putref_schemas(
2633     IXMLDOMDocument3* iface,
2634     VARIANT var1)
2635 {
2636     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2637     HRESULT hr = E_FAIL;
2638     IXMLDOMSchemaCollection2* new_schema = NULL;
2639
2640     FIXME("(%p): semi-stub\n", This);
2641     switch(V_VT(&var1))
2642     {
2643     case VT_UNKNOWN:
2644         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2645         break;
2646
2647     case VT_DISPATCH:
2648         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2649         break;
2650
2651     case VT_NULL:
2652     case VT_EMPTY:
2653         hr = S_OK;
2654         break;
2655
2656     default:
2657         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2658     }
2659
2660     if(SUCCEEDED(hr))
2661     {
2662         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2663         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2664     }
2665
2666     return hr;
2667 }
2668
2669 static inline BOOL is_wellformed(xmlDocPtr doc)
2670 {
2671 #ifdef HAVE_XMLDOC_PROPERTIES
2672     return doc->properties & XML_DOC_WELLFORMED;
2673 #else
2674     /* Not a full check, but catches the worst violations */
2675     xmlNodePtr child;
2676     int root = 0;
2677
2678     for (child = doc->children; child != NULL; child = child->next)
2679     {
2680         switch (child->type)
2681         {
2682         case XML_ELEMENT_NODE:
2683             if (++root > 1)
2684                 return FALSE;
2685             break;
2686         case XML_TEXT_NODE:
2687         case XML_CDATA_SECTION_NODE:
2688             return FALSE;
2689             break;
2690         default:
2691             break;
2692         }
2693     }
2694
2695     return root == 1;
2696 #endif
2697 }
2698
2699 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2700 {
2701     va_list ap;
2702     va_start(ap, msg);
2703     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2704     va_end(ap);
2705 }
2706
2707 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2708 {
2709     va_list ap;
2710     va_start(ap, msg);
2711     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2712     va_end(ap);
2713 }
2714
2715 static HRESULT WINAPI domdoc_validateNode(
2716     IXMLDOMDocument3* iface,
2717     IXMLDOMNode* node,
2718     IXMLDOMParseError** err)
2719 {
2720     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2721     LONG state, err_code = 0;
2722     HRESULT hr = S_OK;
2723     int validated = 0;
2724
2725     TRACE("(%p)->(%p, %p)\n", This, node, err);
2726     domdoc_get_readyState(iface, &state);
2727     if (state != READYSTATE_COMPLETE)
2728     {
2729         if (err)
2730            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2731         return E_PENDING;
2732     }
2733
2734     if (!node)
2735     {
2736         if (err)
2737             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2738         return E_POINTER;
2739     }
2740
2741     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2742     {
2743         if (err)
2744             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2745         return E_FAIL;
2746     }
2747
2748     if (!is_wellformed(get_doc(This)))
2749     {
2750         ERR("doc not well-formed\n");
2751         if (err)
2752             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2753         return S_FALSE;
2754     }
2755
2756     /* DTD validation */
2757     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2758     {
2759         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2760         vctx->error = validate_error;
2761         vctx->warning = validate_warning;
2762         ++validated;
2763
2764         if (!((node == (IXMLDOMNode*)iface)?
2765               xmlValidateDocument(vctx, get_doc(This)) :
2766               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2767         {
2768             /* TODO: get a real error code here */
2769             TRACE("DTD validation failed\n");
2770             err_code = E_XML_INVALID;
2771             hr = S_FALSE;
2772         }
2773         xmlFreeValidCtxt(vctx);
2774     }
2775
2776     /* Schema validation */
2777     if (hr == S_OK && This->properties->schemaCache != NULL)
2778     {
2779
2780         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2781         if (!FAILED(hr))
2782         {
2783             ++validated;
2784             /* TODO: get a real error code here */
2785             if (hr == S_OK)
2786             {
2787                 TRACE("schema validation succeeded\n");
2788             }
2789             else
2790             {
2791                 ERR("schema validation failed\n");
2792                 err_code = E_XML_INVALID;
2793             }
2794         }
2795         else
2796         {
2797             /* not really OK, just didn't find a schema for the ns */
2798             hr = S_OK;
2799         }
2800     }
2801
2802     if (!validated)
2803     {
2804         ERR("no DTD or schema found\n");
2805         err_code = E_XML_NODTD;
2806         hr = S_FALSE;
2807     }
2808
2809     if (err)
2810         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2811
2812     return hr;
2813 }
2814
2815 static HRESULT WINAPI domdoc_validate(
2816     IXMLDOMDocument3* iface,
2817     IXMLDOMParseError** err)
2818 {
2819     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2820     TRACE("(%p)->(%p)\n", This, err);
2821     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2822 }
2823
2824 static HRESULT WINAPI domdoc_setProperty(
2825     IXMLDOMDocument3* iface,
2826     BSTR p,
2827     VARIANT var)
2828 {
2829     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2830
2831     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2832
2833     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2834     {
2835         VARIANT varStr;
2836         HRESULT hr;
2837         BSTR bstr;
2838
2839         V_VT(&varStr) = VT_EMPTY;
2840         if (V_VT(&var) != VT_BSTR)
2841         {
2842             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2843                 return hr;
2844             bstr = V_BSTR(&varStr);
2845         }
2846         else
2847             bstr = V_BSTR(&var);
2848
2849         hr = S_OK;
2850         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2851             This->properties->XPath = TRUE;
2852         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2853             This->properties->XPath = FALSE;
2854         else
2855             hr = E_FAIL;
2856
2857         VariantClear(&varStr);
2858         return hr;
2859     }
2860     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2861     {
2862         VARIANT varStr;
2863         HRESULT hr;
2864         BSTR bstr;
2865         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2866         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2867         xmlXPathContextPtr ctx;
2868         struct list *pNsList;
2869         select_ns_entry* pNsEntry = NULL;
2870
2871         V_VT(&varStr) = VT_EMPTY;
2872         if (V_VT(&var) != VT_BSTR)
2873         {
2874             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2875                 return hr;
2876             bstr = V_BSTR(&varStr);
2877         }
2878         else
2879             bstr = V_BSTR(&var);
2880
2881         hr = S_OK;
2882
2883         pNsList = &(This->properties->selectNsList);
2884         clear_selectNsList(pNsList);
2885         heap_free(nsStr);
2886         nsStr = xmlchar_from_wchar(bstr);
2887
2888         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2889
2890         This->properties->selectNsStr = nsStr;
2891         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2892         if (bstr && *bstr)
2893         {
2894             ctx = xmlXPathNewContext(This->node.node->doc);
2895             pTokBegin = nsStr;
2896             pTokEnd = nsStr;
2897             for (; *pTokBegin; pTokBegin = pTokEnd)
2898             {
2899                 if (pNsEntry != NULL)
2900                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2901                 else
2902                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2903
2904                 while (*pTokBegin == ' ')
2905                     ++pTokBegin;
2906                 pTokEnd = pTokBegin;
2907                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2908                     ++pTokEnd;
2909
2910                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2911                 {
2912                     hr = E_FAIL;
2913                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2914                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2915                     continue;
2916                 }
2917
2918                 pTokBegin += 5;
2919                 if (*pTokBegin == '=')
2920                 {
2921                     /*valid for XSLPattern?*/
2922                     FIXME("Setting default xmlns not supported - skipping.\n");
2923                     pTokBegin = pTokEnd;
2924                     continue;
2925                 }
2926                 else if (*pTokBegin == ':')
2927                 {
2928                     pNsEntry->prefix = ++pTokBegin;
2929                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2930                         ;
2931
2932                     if (pTokInner == pTokEnd)
2933                     {
2934                         hr = E_FAIL;
2935                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2936                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2937                         continue;
2938                     }
2939
2940                     pNsEntry->prefix_end = *pTokInner;
2941                     *pTokInner = 0;
2942                     ++pTokInner;
2943
2944                     if (pTokEnd-pTokInner > 1 &&
2945                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2946                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2947                     {
2948                         pNsEntry->href = ++pTokInner;
2949                         pNsEntry->href_end = *(pTokEnd-1);
2950                         *(pTokEnd-1) = 0;
2951                         list_add_tail(pNsList, &pNsEntry->entry);
2952                         /*let libxml figure out if they're valid from here ;)*/
2953                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2954                         {
2955                             hr = E_FAIL;
2956                         }
2957                         pNsEntry = NULL;
2958                         continue;
2959                     }
2960                     else
2961                     {
2962                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2963                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2964                         list_add_tail(pNsList, &pNsEntry->entry);
2965
2966                         pNsEntry = NULL;
2967                         hr = E_FAIL;
2968                         continue;
2969                     }
2970                 }
2971                 else
2972                 {
2973                     hr = E_FAIL;
2974                     continue;
2975                 }
2976             }
2977             heap_free(pNsEntry);
2978             xmlXPathFreeContext(ctx);
2979         }
2980
2981         VariantClear(&varStr);
2982         return hr;
2983     }
2984     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2985              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2986              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2987     {
2988         /* Ignore */
2989         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2990         return S_OK;
2991     }
2992
2993     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2994     return E_FAIL;
2995 }
2996
2997 static HRESULT WINAPI domdoc_getProperty(
2998     IXMLDOMDocument3* iface,
2999     BSTR p,
3000     VARIANT* var)
3001 {
3002     domdoc *This = impl_from_IXMLDOMDocument3( iface );
3003
3004     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
3005
3006     if (!var)
3007         return E_INVALIDARG;
3008
3009     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3010     {
3011         V_VT(var) = VT_BSTR;
3012         V_BSTR(var) = This->properties->XPath ?
3013                       SysAllocString(PropValueXPathW) :
3014                       SysAllocString(PropValueXSLPatternW);
3015         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3016     }
3017     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3018     {
3019         int lenA, lenW;
3020         BSTR rebuiltStr, cur;
3021         const xmlChar *nsStr;
3022         struct list *pNsList;
3023         select_ns_entry* pNsEntry;
3024
3025         V_VT(var) = VT_BSTR;
3026         nsStr = This->properties->selectNsStr;
3027         pNsList = &This->properties->selectNsList;
3028         lenA = This->properties->selectNsStr_len;
3029         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3030         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3031         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3032         cur = rebuiltStr;
3033         /* this is fine because all of the chars that end tokens are ASCII*/
3034         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3035         {
3036             while (*cur != 0) ++cur;
3037             if (pNsEntry->prefix_end)
3038             {
3039                 *cur = pNsEntry->prefix_end;
3040                 while (*cur != 0) ++cur;
3041             }
3042
3043             if (pNsEntry->href_end)
3044             {
3045                 *cur = pNsEntry->href_end;
3046             }
3047         }
3048         V_BSTR(var) = SysAllocString(rebuiltStr);
3049         heap_free(rebuiltStr);
3050         return S_OK;
3051     }
3052
3053     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
3054     return E_FAIL;
3055 }
3056
3057 static HRESULT WINAPI domdoc_importNode(
3058     IXMLDOMDocument3* iface,
3059     IXMLDOMNode* node,
3060     VARIANT_BOOL deep,
3061     IXMLDOMNode** clone)
3062 {
3063     domdoc *This = impl_from_IXMLDOMDocument3( iface );
3064     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3065     return E_NOTIMPL;
3066 }
3067
3068 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
3069 {
3070     domdoc_QueryInterface,
3071     domdoc_AddRef,
3072     domdoc_Release,
3073     domdoc_GetTypeInfoCount,
3074     domdoc_GetTypeInfo,
3075     domdoc_GetIDsOfNames,
3076     domdoc_Invoke,
3077     domdoc_get_nodeName,
3078     domdoc_get_nodeValue,
3079     domdoc_put_nodeValue,
3080     domdoc_get_nodeType,
3081     domdoc_get_parentNode,
3082     domdoc_get_childNodes,
3083     domdoc_get_firstChild,
3084     domdoc_get_lastChild,
3085     domdoc_get_previousSibling,
3086     domdoc_get_nextSibling,
3087     domdoc_get_attributes,
3088     domdoc_insertBefore,
3089     domdoc_replaceChild,
3090     domdoc_removeChild,
3091     domdoc_appendChild,
3092     domdoc_hasChildNodes,
3093     domdoc_get_ownerDocument,
3094     domdoc_cloneNode,
3095     domdoc_get_nodeTypeString,
3096     domdoc_get_text,
3097     domdoc_put_text,
3098     domdoc_get_specified,
3099     domdoc_get_definition,
3100     domdoc_get_nodeTypedValue,
3101     domdoc_put_nodeTypedValue,
3102     domdoc_get_dataType,
3103     domdoc_put_dataType,
3104     domdoc_get_xml,
3105     domdoc_transformNode,
3106     domdoc_selectNodes,
3107     domdoc_selectSingleNode,
3108     domdoc_get_parsed,
3109     domdoc_get_namespaceURI,
3110     domdoc_get_prefix,
3111     domdoc_get_baseName,
3112     domdoc_transformNodeToObject,
3113     domdoc_get_doctype,
3114     domdoc_get_implementation,
3115     domdoc_get_documentElement,
3116     domdoc_put_documentElement,
3117     domdoc_createElement,
3118     domdoc_createDocumentFragment,
3119     domdoc_createTextNode,
3120     domdoc_createComment,
3121     domdoc_createCDATASection,
3122     domdoc_createProcessingInstruction,
3123     domdoc_createAttribute,
3124     domdoc_createEntityReference,
3125     domdoc_getElementsByTagName,
3126     domdoc_createNode,
3127     domdoc_nodeFromID,
3128     domdoc_load,
3129     domdoc_get_readyState,
3130     domdoc_get_parseError,
3131     domdoc_get_url,
3132     domdoc_get_async,
3133     domdoc_put_async,
3134     domdoc_abort,
3135     domdoc_loadXML,
3136     domdoc_save,
3137     domdoc_get_validateOnParse,
3138     domdoc_put_validateOnParse,
3139     domdoc_get_resolveExternals,
3140     domdoc_put_resolveExternals,
3141     domdoc_get_preserveWhiteSpace,
3142     domdoc_put_preserveWhiteSpace,
3143     domdoc_put_onreadystatechange,
3144     domdoc_put_onDataAvailable,
3145     domdoc_put_onTransformNode,
3146     domdoc_get_namespaces,
3147     domdoc_get_schemas,
3148     domdoc_putref_schemas,
3149     domdoc_validate,
3150     domdoc_setProperty,
3151     domdoc_getProperty,
3152     domdoc_validateNode,
3153     domdoc_importNode
3154 };
3155
3156 /* IConnectionPointContainer */
3157 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3158                                                               REFIID riid, void **ppv)
3159 {
3160     domdoc *This = impl_from_IConnectionPointContainer(iface);
3161     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3162 }
3163
3164 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3165 {
3166     domdoc *This = impl_from_IConnectionPointContainer(iface);
3167     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3168 }
3169
3170 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3171 {
3172     domdoc *This = impl_from_IConnectionPointContainer(iface);
3173     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3174 }
3175
3176 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3177         IEnumConnectionPoints **ppEnum)
3178 {
3179     domdoc *This = impl_from_IConnectionPointContainer(iface);
3180     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3181     return E_NOTIMPL;
3182 }
3183
3184 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3185         REFIID riid, IConnectionPoint **cp)
3186 {
3187     domdoc *This = impl_from_IConnectionPointContainer(iface);
3188     ConnectionPoint *iter;
3189
3190     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3191
3192     *cp = NULL;
3193
3194     for(iter = This->cp_list; iter; iter = iter->next)
3195     {
3196         if (IsEqualGUID(iter->iid, riid))
3197             *cp = &iter->IConnectionPoint_iface;
3198     }
3199
3200     if (*cp)
3201     {
3202         IConnectionPoint_AddRef(*cp);
3203         return S_OK;
3204     }
3205
3206     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3207     return CONNECT_E_NOCONNECTION;
3208
3209 }
3210
3211 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3212 {
3213     ConnectionPointContainer_QueryInterface,
3214     ConnectionPointContainer_AddRef,
3215     ConnectionPointContainer_Release,
3216     ConnectionPointContainer_EnumConnectionPoints,
3217     ConnectionPointContainer_FindConnectionPoint
3218 };
3219
3220 /* IConnectionPoint */
3221 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3222                                                      REFIID riid, void **ppv)
3223 {
3224     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3225
3226     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3227
3228     *ppv = NULL;
3229
3230     if (IsEqualGUID(&IID_IUnknown, riid) ||
3231         IsEqualGUID(&IID_IConnectionPoint, riid))
3232     {
3233         *ppv = iface;
3234     }
3235
3236     if (*ppv)
3237     {
3238         IConnectionPoint_AddRef(iface);
3239         return S_OK;
3240     }
3241
3242     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3243     return E_NOINTERFACE;
3244 }
3245
3246 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3247 {
3248     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3249     return IConnectionPointContainer_AddRef(This->container);
3250 }
3251
3252 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3253 {
3254     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3255     return IConnectionPointContainer_Release(This->container);
3256 }
3257
3258 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3259 {
3260     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3261
3262     TRACE("(%p)->(%p)\n", This, iid);
3263
3264     if (!iid) return E_POINTER;
3265
3266     *iid = *This->iid;
3267     return S_OK;
3268 }
3269
3270 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3271         IConnectionPointContainer **container)
3272 {
3273     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3274
3275     TRACE("(%p)->(%p)\n", This, container);
3276
3277     if (!container) return E_POINTER;
3278
3279     *container = This->container;
3280     IConnectionPointContainer_AddRef(*container);
3281     return S_OK;
3282 }
3283
3284 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3285                                              DWORD *pdwCookie)
3286 {
3287     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3288     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3289     return E_NOTIMPL;
3290 }
3291
3292 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3293 {
3294     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3295
3296     TRACE("(%p)->(%d)\n", This, cookie);
3297
3298     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3299         return CONNECT_E_NOCONNECTION;
3300
3301     IUnknown_Release(This->sinks[cookie-1].unk);
3302     This->sinks[cookie-1].unk = NULL;
3303
3304     return S_OK;
3305 }
3306
3307 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3308                                                       IEnumConnections **ppEnum)
3309 {
3310     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3311     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3312     return E_NOTIMPL;
3313 }
3314
3315 static const IConnectionPointVtbl ConnectionPointVtbl =
3316 {
3317     ConnectionPoint_QueryInterface,
3318     ConnectionPoint_AddRef,
3319     ConnectionPoint_Release,
3320     ConnectionPoint_GetConnectionInterface,
3321     ConnectionPoint_GetConnectionPointContainer,
3322     ConnectionPoint_Advise,
3323     ConnectionPoint_Unadvise,
3324     ConnectionPoint_EnumConnections
3325 };
3326
3327 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3328 {
3329     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3330     cp->doc = doc;
3331     cp->iid = riid;
3332     cp->sinks = NULL;
3333     cp->sinks_size = 0;
3334
3335     cp->next = doc->cp_list;
3336     doc->cp_list = cp;
3337
3338     cp->container = &doc->IConnectionPointContainer_iface;
3339 }
3340
3341 /* domdoc implementation of IObjectWithSite */
3342 static HRESULT WINAPI
3343 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3344 {
3345     domdoc *This = impl_from_IObjectWithSite(iface);
3346     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3347 }
3348
3349 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3350 {
3351     domdoc *This = impl_from_IObjectWithSite(iface);
3352     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3353 }
3354
3355 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3356 {
3357     domdoc *This = impl_from_IObjectWithSite(iface);
3358     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3359 }
3360
3361 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3362 {
3363     domdoc *This = impl_from_IObjectWithSite(iface);
3364
3365     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3366
3367     if ( !This->site )
3368         return E_FAIL;
3369
3370     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3371 }
3372
3373 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3374 {
3375     domdoc *This = impl_from_IObjectWithSite(iface);
3376
3377     TRACE("(%p)->(%p)\n", iface, punk);
3378
3379     if(!punk)
3380     {
3381         if(This->site)
3382         {
3383             IUnknown_Release( This->site );
3384             This->site = NULL;
3385         }
3386
3387         return S_OK;
3388     }
3389
3390     IUnknown_AddRef( punk );
3391
3392     if(This->site)
3393         IUnknown_Release( This->site );
3394
3395     This->site = punk;
3396
3397     return S_OK;
3398 }
3399
3400 static const IObjectWithSiteVtbl domdocObjectSite =
3401 {
3402     domdoc_ObjectWithSite_QueryInterface,
3403     domdoc_ObjectWithSite_AddRef,
3404     domdoc_ObjectWithSite_Release,
3405     domdoc_ObjectWithSite_SetSite,
3406     domdoc_ObjectWithSite_GetSite
3407 };
3408
3409 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3410 {
3411     domdoc *This = impl_from_IObjectSafety(iface);
3412     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3413 }
3414
3415 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3416 {
3417     domdoc *This = impl_from_IObjectSafety(iface);
3418     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3419 }
3420
3421 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3422 {
3423     domdoc *This = impl_from_IObjectSafety(iface);
3424     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3425 }
3426
3427 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3428
3429 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3430         DWORD *supported, DWORD *enabled)
3431 {
3432     domdoc *This = impl_from_IObjectSafety(iface);
3433
3434     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3435
3436     if(!supported || !enabled) return E_POINTER;
3437
3438     *supported = SAFETY_SUPPORTED_OPTIONS;
3439     *enabled = This->safeopt;
3440
3441     return S_OK;
3442 }
3443
3444 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3445         DWORD mask, DWORD enabled)
3446 {
3447     domdoc *This = impl_from_IObjectSafety(iface);
3448     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3449
3450     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3451         return E_FAIL;
3452
3453     This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3454     return S_OK;
3455 }
3456
3457 #undef SAFETY_SUPPORTED_OPTIONS
3458
3459 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3460     domdoc_Safety_QueryInterface,
3461     domdoc_Safety_AddRef,
3462     domdoc_Safety_Release,
3463     domdoc_Safety_GetInterfaceSafetyOptions,
3464     domdoc_Safety_SetInterfaceSafetyOptions
3465 };
3466
3467 static const tid_t domdoc_iface_tids[] = {
3468     IXMLDOMNode_tid,
3469     IXMLDOMDocument_tid,
3470     IXMLDOMDocument2_tid,
3471     0
3472 };
3473 static dispex_static_data_t domdoc_dispex = {
3474     NULL,
3475     IXMLDOMDocument2_tid,
3476     NULL,
3477     domdoc_iface_tids
3478 };
3479
3480 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3481 {
3482     domdoc *doc;
3483
3484     doc = heap_alloc( sizeof (*doc) );
3485     if( !doc )
3486         return E_OUTOFMEMORY;
3487
3488     doc->IXMLDOMDocument3_iface.lpVtbl = &domdoc_vtbl;
3489     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3490     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3491     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3492     doc->ISupportErrorInfo_iface.lpVtbl = &support_error_vtbl;
3493     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3494     doc->ref = 1;
3495     doc->async = VARIANT_TRUE;
3496     doc->validating = 0;
3497     doc->resolving = 0;
3498     doc->properties = properties_from_xmlDocPtr(xmldoc);
3499     doc->error = S_OK;
3500     doc->stream = NULL;
3501     doc->site = NULL;
3502     doc->safeopt = 0;
3503     doc->bsc = NULL;
3504     doc->cp_list = NULL;
3505     memset(doc->events, 0, sizeof(doc->events));
3506
3507     /* events connection points */
3508     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3509     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3510     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3511
3512     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3513             &domdoc_dispex);
3514
3515     *document = &doc->IXMLDOMDocument3_iface;
3516
3517     TRACE("returning iface %p\n", *document);
3518     return S_OK;
3519 }
3520
3521 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3522 {
3523     xmlDocPtr xmldoc;
3524     HRESULT hr;
3525
3526     TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3527
3528     xmldoc = xmlNewDoc(NULL);
3529     if(!xmldoc)
3530         return E_OUTOFMEMORY;
3531
3532     xmldoc->_private = create_priv();
3533     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3534
3535     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3536     if(FAILED(hr))
3537     {
3538         free_properties(properties_from_xmlDocPtr(xmldoc));
3539         heap_free(xmldoc->_private);
3540         xmlFreeDoc(xmldoc);
3541         return hr;
3542     }
3543
3544     return hr;
3545 }
3546
3547 IUnknown* create_domdoc( xmlNodePtr document )
3548 {
3549     void* pObj = NULL;
3550     HRESULT hr;
3551
3552     TRACE("(%p)\n", document);
3553
3554     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3555     if (FAILED(hr))
3556         return NULL;
3557
3558     return pObj;
3559 }
3560
3561 #else
3562
3563 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3564 {
3565     MESSAGE("This program tried to use a DOMDocument object, but\n"
3566             "libxml2 support was not present at compile time.\n");
3567     return E_NOTIMPL;
3568 }
3569
3570 #endif