usp10: Return the set of Indic syllables after reorder.
[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)->(var(vt %d, %s))\n", This, V_VT(&destination),
2427           V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2428
2429     if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2430     {
2431         FIXME("Unhandled vt %d\n", V_VT(&destination));
2432         return S_FALSE;
2433     }
2434
2435     if(V_VT(&destination) == VT_UNKNOWN)
2436     {
2437         IUnknown *pUnk = V_UNKNOWN(&destination);
2438         IXMLDOMDocument2 *document;
2439         IStream *stream;
2440
2441         ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2442         if(ret == S_OK)
2443         {
2444             VARIANT_BOOL success;
2445             BSTR xml;
2446
2447             ret = IXMLDOMDocument3_get_xml(iface, &xml);
2448             if(ret == S_OK)
2449             {
2450                 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2451                 SysFreeString(xml);
2452             }
2453
2454             IXMLDOMDocument3_Release(document);
2455             return ret;
2456         }
2457
2458         ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2459         if(ret == S_OK)
2460         {
2461             ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2462                 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2463
2464             if(!ctx)
2465             {
2466                 IStream_Release(stream);
2467                 return E_FAIL;
2468             }
2469         }
2470     }
2471     else
2472     {
2473         /* save with file path */
2474         HANDLE handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2475                                     NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2476         if( handle == INVALID_HANDLE_VALUE )
2477         {
2478             WARN("failed to create file\n");
2479             return E_FAIL;
2480         }
2481
2482         /* disable top XML declaration */
2483         ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2484                           handle, NULL, XML_SAVE_NO_DECL);
2485         if (!ctx)
2486         {
2487             CloseHandle(handle);
2488             return E_FAIL;
2489         }
2490     }
2491
2492     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2493     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2494     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2495
2496     /* will release resources through close callback */
2497     xmlSaveClose(ctx);
2498
2499     return ret;
2500 }
2501
2502 static HRESULT WINAPI domdoc_get_validateOnParse(
2503     IXMLDOMDocument3 *iface,
2504     VARIANT_BOOL* isValidating )
2505 {
2506     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2507     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2508     *isValidating = This->validating;
2509     return S_OK;
2510 }
2511
2512
2513 static HRESULT WINAPI domdoc_put_validateOnParse(
2514     IXMLDOMDocument3 *iface,
2515     VARIANT_BOOL isValidating )
2516 {
2517     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2518     TRACE("(%p)->(%d)\n", This, isValidating);
2519     This->validating = isValidating;
2520     return S_OK;
2521 }
2522
2523
2524 static HRESULT WINAPI domdoc_get_resolveExternals(
2525     IXMLDOMDocument3 *iface,
2526     VARIANT_BOOL* isResolving )
2527 {
2528     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2529     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2530     *isResolving = This->resolving;
2531     return S_OK;
2532 }
2533
2534
2535 static HRESULT WINAPI domdoc_put_resolveExternals(
2536     IXMLDOMDocument3 *iface,
2537     VARIANT_BOOL isResolving )
2538 {
2539     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2540     TRACE("(%p)->(%d)\n", This, isResolving);
2541     This->resolving = isResolving;
2542     return S_OK;
2543 }
2544
2545
2546 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2547     IXMLDOMDocument3 *iface,
2548     VARIANT_BOOL* isPreserving )
2549 {
2550     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2551     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2552     *isPreserving = This->properties->preserving;
2553     return S_OK;
2554 }
2555
2556
2557 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2558     IXMLDOMDocument3 *iface,
2559     VARIANT_BOOL isPreserving )
2560 {
2561     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2562     TRACE("(%p)->(%d)\n", This, isPreserving);
2563     This->properties->preserving = isPreserving;
2564     return S_OK;
2565 }
2566
2567
2568 static HRESULT WINAPI domdoc_put_onreadystatechange(
2569     IXMLDOMDocument3 *iface,
2570     VARIANT event )
2571 {
2572     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2573
2574     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2575     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2576 }
2577
2578
2579 static HRESULT WINAPI domdoc_put_onDataAvailable(
2580     IXMLDOMDocument3 *iface,
2581     VARIANT onDataAvailableSink )
2582 {
2583     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2584     FIXME("%p\n", This);
2585     return E_NOTIMPL;
2586 }
2587
2588 static HRESULT WINAPI domdoc_put_onTransformNode(
2589     IXMLDOMDocument3 *iface,
2590     VARIANT onTransformNodeSink )
2591 {
2592     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2593     FIXME("%p\n", This);
2594     return E_NOTIMPL;
2595 }
2596
2597 static HRESULT WINAPI domdoc_get_namespaces(
2598     IXMLDOMDocument3* iface,
2599     IXMLDOMSchemaCollection** schemaCollection )
2600 {
2601     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2602     FIXME("(%p)->(%p)\n", This, schemaCollection);
2603     return E_NOTIMPL;
2604 }
2605
2606 static HRESULT WINAPI domdoc_get_schemas(
2607     IXMLDOMDocument3* iface,
2608     VARIANT* var1 )
2609 {
2610     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2611     HRESULT hr = S_FALSE;
2612     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2613
2614     TRACE("(%p)->(%p)\n", This, var1);
2615
2616     VariantInit(var1); /* Test shows we don't call VariantClear here */
2617     V_VT(var1) = VT_NULL;
2618
2619     if(cur_schema)
2620     {
2621         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2622         if(SUCCEEDED(hr))
2623             V_VT(var1) = VT_DISPATCH;
2624     }
2625     return hr;
2626 }
2627
2628 static HRESULT WINAPI domdoc_putref_schemas(
2629     IXMLDOMDocument3* iface,
2630     VARIANT var1)
2631 {
2632     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2633     HRESULT hr = E_FAIL;
2634     IXMLDOMSchemaCollection2* new_schema = NULL;
2635
2636     FIXME("(%p): semi-stub\n", This);
2637     switch(V_VT(&var1))
2638     {
2639     case VT_UNKNOWN:
2640         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2641         break;
2642
2643     case VT_DISPATCH:
2644         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2645         break;
2646
2647     case VT_NULL:
2648     case VT_EMPTY:
2649         hr = S_OK;
2650         break;
2651
2652     default:
2653         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2654     }
2655
2656     if(SUCCEEDED(hr))
2657     {
2658         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2659         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2660     }
2661
2662     return hr;
2663 }
2664
2665 static inline BOOL is_wellformed(xmlDocPtr doc)
2666 {
2667 #ifdef HAVE_XMLDOC_PROPERTIES
2668     return doc->properties & XML_DOC_WELLFORMED;
2669 #else
2670     /* Not a full check, but catches the worst violations */
2671     xmlNodePtr child;
2672     int root = 0;
2673
2674     for (child = doc->children; child != NULL; child = child->next)
2675     {
2676         switch (child->type)
2677         {
2678         case XML_ELEMENT_NODE:
2679             if (++root > 1)
2680                 return FALSE;
2681             break;
2682         case XML_TEXT_NODE:
2683         case XML_CDATA_SECTION_NODE:
2684             return FALSE;
2685             break;
2686         default:
2687             break;
2688         }
2689     }
2690
2691     return root == 1;
2692 #endif
2693 }
2694
2695 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2696 {
2697     va_list ap;
2698     va_start(ap, msg);
2699     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2700     va_end(ap);
2701 }
2702
2703 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2704 {
2705     va_list ap;
2706     va_start(ap, msg);
2707     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2708     va_end(ap);
2709 }
2710
2711 static HRESULT WINAPI domdoc_validateNode(
2712     IXMLDOMDocument3* iface,
2713     IXMLDOMNode* node,
2714     IXMLDOMParseError** err)
2715 {
2716     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2717     LONG state, err_code = 0;
2718     HRESULT hr = S_OK;
2719     int validated = 0;
2720
2721     TRACE("(%p)->(%p, %p)\n", This, node, err);
2722     domdoc_get_readyState(iface, &state);
2723     if (state != READYSTATE_COMPLETE)
2724     {
2725         if (err)
2726            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2727         return E_PENDING;
2728     }
2729
2730     if (!node)
2731     {
2732         if (err)
2733             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2734         return E_POINTER;
2735     }
2736
2737     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2738     {
2739         if (err)
2740             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2741         return E_FAIL;
2742     }
2743
2744     if (!is_wellformed(get_doc(This)))
2745     {
2746         ERR("doc not well-formed\n");
2747         if (err)
2748             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2749         return S_FALSE;
2750     }
2751
2752     /* DTD validation */
2753     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2754     {
2755         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2756         vctx->error = validate_error;
2757         vctx->warning = validate_warning;
2758         ++validated;
2759
2760         if (!((node == (IXMLDOMNode*)iface)?
2761               xmlValidateDocument(vctx, get_doc(This)) :
2762               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2763         {
2764             /* TODO: get a real error code here */
2765             TRACE("DTD validation failed\n");
2766             err_code = E_XML_INVALID;
2767             hr = S_FALSE;
2768         }
2769         xmlFreeValidCtxt(vctx);
2770     }
2771
2772     /* Schema validation */
2773     if (hr == S_OK && This->properties->schemaCache != NULL)
2774     {
2775
2776         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2777         if (!FAILED(hr))
2778         {
2779             ++validated;
2780             /* TODO: get a real error code here */
2781             if (hr == S_OK)
2782             {
2783                 TRACE("schema validation succeeded\n");
2784             }
2785             else
2786             {
2787                 ERR("schema validation failed\n");
2788                 err_code = E_XML_INVALID;
2789             }
2790         }
2791         else
2792         {
2793             /* not really OK, just didn't find a schema for the ns */
2794             hr = S_OK;
2795         }
2796     }
2797
2798     if (!validated)
2799     {
2800         ERR("no DTD or schema found\n");
2801         err_code = E_XML_NODTD;
2802         hr = S_FALSE;
2803     }
2804
2805     if (err)
2806         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2807
2808     return hr;
2809 }
2810
2811 static HRESULT WINAPI domdoc_validate(
2812     IXMLDOMDocument3* iface,
2813     IXMLDOMParseError** err)
2814 {
2815     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2816     TRACE("(%p)->(%p)\n", This, err);
2817     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2818 }
2819
2820 static HRESULT WINAPI domdoc_setProperty(
2821     IXMLDOMDocument3* iface,
2822     BSTR p,
2823     VARIANT var)
2824 {
2825     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2826
2827     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2828
2829     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2830     {
2831         VARIANT varStr;
2832         HRESULT hr;
2833         BSTR bstr;
2834
2835         V_VT(&varStr) = VT_EMPTY;
2836         if (V_VT(&var) != VT_BSTR)
2837         {
2838             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2839                 return hr;
2840             bstr = V_BSTR(&varStr);
2841         }
2842         else
2843             bstr = V_BSTR(&var);
2844
2845         hr = S_OK;
2846         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2847             This->properties->XPath = TRUE;
2848         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2849             This->properties->XPath = FALSE;
2850         else
2851             hr = E_FAIL;
2852
2853         VariantClear(&varStr);
2854         return hr;
2855     }
2856     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2857     {
2858         VARIANT varStr;
2859         HRESULT hr;
2860         BSTR bstr;
2861         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2862         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2863         xmlXPathContextPtr ctx;
2864         struct list *pNsList;
2865         select_ns_entry* pNsEntry = NULL;
2866
2867         V_VT(&varStr) = VT_EMPTY;
2868         if (V_VT(&var) != VT_BSTR)
2869         {
2870             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2871                 return hr;
2872             bstr = V_BSTR(&varStr);
2873         }
2874         else
2875             bstr = V_BSTR(&var);
2876
2877         hr = S_OK;
2878
2879         pNsList = &(This->properties->selectNsList);
2880         clear_selectNsList(pNsList);
2881         heap_free(nsStr);
2882         nsStr = xmlchar_from_wchar(bstr);
2883
2884         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2885
2886         This->properties->selectNsStr = nsStr;
2887         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2888         if (bstr && *bstr)
2889         {
2890             ctx = xmlXPathNewContext(This->node.node->doc);
2891             pTokBegin = nsStr;
2892             pTokEnd = nsStr;
2893             for (; *pTokBegin; pTokBegin = pTokEnd)
2894             {
2895                 if (pNsEntry != NULL)
2896                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2897                 else
2898                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2899
2900                 while (*pTokBegin == ' ')
2901                     ++pTokBegin;
2902                 pTokEnd = pTokBegin;
2903                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2904                     ++pTokEnd;
2905
2906                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2907                 {
2908                     hr = E_FAIL;
2909                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2910                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2911                     continue;
2912                 }
2913
2914                 pTokBegin += 5;
2915                 if (*pTokBegin == '=')
2916                 {
2917                     /*valid for XSLPattern?*/
2918                     FIXME("Setting default xmlns not supported - skipping.\n");
2919                     pTokBegin = pTokEnd;
2920                     continue;
2921                 }
2922                 else if (*pTokBegin == ':')
2923                 {
2924                     pNsEntry->prefix = ++pTokBegin;
2925                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2926                         ;
2927
2928                     if (pTokInner == pTokEnd)
2929                     {
2930                         hr = E_FAIL;
2931                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2932                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2933                         continue;
2934                     }
2935
2936                     pNsEntry->prefix_end = *pTokInner;
2937                     *pTokInner = 0;
2938                     ++pTokInner;
2939
2940                     if (pTokEnd-pTokInner > 1 &&
2941                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2942                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2943                     {
2944                         pNsEntry->href = ++pTokInner;
2945                         pNsEntry->href_end = *(pTokEnd-1);
2946                         *(pTokEnd-1) = 0;
2947                         list_add_tail(pNsList, &pNsEntry->entry);
2948                         /*let libxml figure out if they're valid from here ;)*/
2949                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2950                         {
2951                             hr = E_FAIL;
2952                         }
2953                         pNsEntry = NULL;
2954                         continue;
2955                     }
2956                     else
2957                     {
2958                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2959                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2960                         list_add_tail(pNsList, &pNsEntry->entry);
2961
2962                         pNsEntry = NULL;
2963                         hr = E_FAIL;
2964                         continue;
2965                     }
2966                 }
2967                 else
2968                 {
2969                     hr = E_FAIL;
2970                     continue;
2971                 }
2972             }
2973             heap_free(pNsEntry);
2974             xmlXPathFreeContext(ctx);
2975         }
2976
2977         VariantClear(&varStr);
2978         return hr;
2979     }
2980     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2981              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2982              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2983     {
2984         /* Ignore */
2985         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2986         return S_OK;
2987     }
2988
2989     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2990     return E_FAIL;
2991 }
2992
2993 static HRESULT WINAPI domdoc_getProperty(
2994     IXMLDOMDocument3* iface,
2995     BSTR p,
2996     VARIANT* var)
2997 {
2998     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2999
3000     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
3001
3002     if (!var)
3003         return E_INVALIDARG;
3004
3005     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3006     {
3007         V_VT(var) = VT_BSTR;
3008         V_BSTR(var) = This->properties->XPath ?
3009                       SysAllocString(PropValueXPathW) :
3010                       SysAllocString(PropValueXSLPatternW);
3011         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3012     }
3013     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3014     {
3015         int lenA, lenW;
3016         BSTR rebuiltStr, cur;
3017         const xmlChar *nsStr;
3018         struct list *pNsList;
3019         select_ns_entry* pNsEntry;
3020
3021         V_VT(var) = VT_BSTR;
3022         nsStr = This->properties->selectNsStr;
3023         pNsList = &This->properties->selectNsList;
3024         lenA = This->properties->selectNsStr_len;
3025         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3026         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3027         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3028         cur = rebuiltStr;
3029         /* this is fine because all of the chars that end tokens are ASCII*/
3030         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3031         {
3032             while (*cur != 0) ++cur;
3033             if (pNsEntry->prefix_end)
3034             {
3035                 *cur = pNsEntry->prefix_end;
3036                 while (*cur != 0) ++cur;
3037             }
3038
3039             if (pNsEntry->href_end)
3040             {
3041                 *cur = pNsEntry->href_end;
3042             }
3043         }
3044         V_BSTR(var) = SysAllocString(rebuiltStr);
3045         heap_free(rebuiltStr);
3046         return S_OK;
3047     }
3048
3049     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
3050     return E_FAIL;
3051 }
3052
3053 static HRESULT WINAPI domdoc_importNode(
3054     IXMLDOMDocument3* iface,
3055     IXMLDOMNode* node,
3056     VARIANT_BOOL deep,
3057     IXMLDOMNode** clone)
3058 {
3059     domdoc *This = impl_from_IXMLDOMDocument3( iface );
3060     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3061     return E_NOTIMPL;
3062 }
3063
3064 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
3065 {
3066     domdoc_QueryInterface,
3067     domdoc_AddRef,
3068     domdoc_Release,
3069     domdoc_GetTypeInfoCount,
3070     domdoc_GetTypeInfo,
3071     domdoc_GetIDsOfNames,
3072     domdoc_Invoke,
3073     domdoc_get_nodeName,
3074     domdoc_get_nodeValue,
3075     domdoc_put_nodeValue,
3076     domdoc_get_nodeType,
3077     domdoc_get_parentNode,
3078     domdoc_get_childNodes,
3079     domdoc_get_firstChild,
3080     domdoc_get_lastChild,
3081     domdoc_get_previousSibling,
3082     domdoc_get_nextSibling,
3083     domdoc_get_attributes,
3084     domdoc_insertBefore,
3085     domdoc_replaceChild,
3086     domdoc_removeChild,
3087     domdoc_appendChild,
3088     domdoc_hasChildNodes,
3089     domdoc_get_ownerDocument,
3090     domdoc_cloneNode,
3091     domdoc_get_nodeTypeString,
3092     domdoc_get_text,
3093     domdoc_put_text,
3094     domdoc_get_specified,
3095     domdoc_get_definition,
3096     domdoc_get_nodeTypedValue,
3097     domdoc_put_nodeTypedValue,
3098     domdoc_get_dataType,
3099     domdoc_put_dataType,
3100     domdoc_get_xml,
3101     domdoc_transformNode,
3102     domdoc_selectNodes,
3103     domdoc_selectSingleNode,
3104     domdoc_get_parsed,
3105     domdoc_get_namespaceURI,
3106     domdoc_get_prefix,
3107     domdoc_get_baseName,
3108     domdoc_transformNodeToObject,
3109     domdoc_get_doctype,
3110     domdoc_get_implementation,
3111     domdoc_get_documentElement,
3112     domdoc_put_documentElement,
3113     domdoc_createElement,
3114     domdoc_createDocumentFragment,
3115     domdoc_createTextNode,
3116     domdoc_createComment,
3117     domdoc_createCDATASection,
3118     domdoc_createProcessingInstruction,
3119     domdoc_createAttribute,
3120     domdoc_createEntityReference,
3121     domdoc_getElementsByTagName,
3122     domdoc_createNode,
3123     domdoc_nodeFromID,
3124     domdoc_load,
3125     domdoc_get_readyState,
3126     domdoc_get_parseError,
3127     domdoc_get_url,
3128     domdoc_get_async,
3129     domdoc_put_async,
3130     domdoc_abort,
3131     domdoc_loadXML,
3132     domdoc_save,
3133     domdoc_get_validateOnParse,
3134     domdoc_put_validateOnParse,
3135     domdoc_get_resolveExternals,
3136     domdoc_put_resolveExternals,
3137     domdoc_get_preserveWhiteSpace,
3138     domdoc_put_preserveWhiteSpace,
3139     domdoc_put_onreadystatechange,
3140     domdoc_put_onDataAvailable,
3141     domdoc_put_onTransformNode,
3142     domdoc_get_namespaces,
3143     domdoc_get_schemas,
3144     domdoc_putref_schemas,
3145     domdoc_validate,
3146     domdoc_setProperty,
3147     domdoc_getProperty,
3148     domdoc_validateNode,
3149     domdoc_importNode
3150 };
3151
3152 /* IConnectionPointContainer */
3153 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3154                                                               REFIID riid, void **ppv)
3155 {
3156     domdoc *This = impl_from_IConnectionPointContainer(iface);
3157     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3158 }
3159
3160 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3161 {
3162     domdoc *This = impl_from_IConnectionPointContainer(iface);
3163     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3164 }
3165
3166 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3167 {
3168     domdoc *This = impl_from_IConnectionPointContainer(iface);
3169     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3170 }
3171
3172 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3173         IEnumConnectionPoints **ppEnum)
3174 {
3175     domdoc *This = impl_from_IConnectionPointContainer(iface);
3176     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3177     return E_NOTIMPL;
3178 }
3179
3180 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3181         REFIID riid, IConnectionPoint **cp)
3182 {
3183     domdoc *This = impl_from_IConnectionPointContainer(iface);
3184     ConnectionPoint *iter;
3185
3186     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3187
3188     *cp = NULL;
3189
3190     for(iter = This->cp_list; iter; iter = iter->next)
3191     {
3192         if (IsEqualGUID(iter->iid, riid))
3193             *cp = &iter->IConnectionPoint_iface;
3194     }
3195
3196     if (*cp)
3197     {
3198         IConnectionPoint_AddRef(*cp);
3199         return S_OK;
3200     }
3201
3202     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3203     return CONNECT_E_NOCONNECTION;
3204
3205 }
3206
3207 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3208 {
3209     ConnectionPointContainer_QueryInterface,
3210     ConnectionPointContainer_AddRef,
3211     ConnectionPointContainer_Release,
3212     ConnectionPointContainer_EnumConnectionPoints,
3213     ConnectionPointContainer_FindConnectionPoint
3214 };
3215
3216 /* IConnectionPoint */
3217 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3218                                                      REFIID riid, void **ppv)
3219 {
3220     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3221
3222     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3223
3224     *ppv = NULL;
3225
3226     if (IsEqualGUID(&IID_IUnknown, riid) ||
3227         IsEqualGUID(&IID_IConnectionPoint, riid))
3228     {
3229         *ppv = iface;
3230     }
3231
3232     if (*ppv)
3233     {
3234         IConnectionPoint_AddRef(iface);
3235         return S_OK;
3236     }
3237
3238     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3239     return E_NOINTERFACE;
3240 }
3241
3242 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3243 {
3244     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3245     return IConnectionPointContainer_AddRef(This->container);
3246 }
3247
3248 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3249 {
3250     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3251     return IConnectionPointContainer_Release(This->container);
3252 }
3253
3254 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3255 {
3256     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3257
3258     TRACE("(%p)->(%p)\n", This, iid);
3259
3260     if (!iid) return E_POINTER;
3261
3262     *iid = *This->iid;
3263     return S_OK;
3264 }
3265
3266 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3267         IConnectionPointContainer **container)
3268 {
3269     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3270
3271     TRACE("(%p)->(%p)\n", This, container);
3272
3273     if (!container) return E_POINTER;
3274
3275     *container = This->container;
3276     IConnectionPointContainer_AddRef(*container);
3277     return S_OK;
3278 }
3279
3280 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3281                                              DWORD *pdwCookie)
3282 {
3283     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3284     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3285     return E_NOTIMPL;
3286 }
3287
3288 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3289 {
3290     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3291
3292     TRACE("(%p)->(%d)\n", This, cookie);
3293
3294     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3295         return CONNECT_E_NOCONNECTION;
3296
3297     IUnknown_Release(This->sinks[cookie-1].unk);
3298     This->sinks[cookie-1].unk = NULL;
3299
3300     return S_OK;
3301 }
3302
3303 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3304                                                       IEnumConnections **ppEnum)
3305 {
3306     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3307     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3308     return E_NOTIMPL;
3309 }
3310
3311 static const IConnectionPointVtbl ConnectionPointVtbl =
3312 {
3313     ConnectionPoint_QueryInterface,
3314     ConnectionPoint_AddRef,
3315     ConnectionPoint_Release,
3316     ConnectionPoint_GetConnectionInterface,
3317     ConnectionPoint_GetConnectionPointContainer,
3318     ConnectionPoint_Advise,
3319     ConnectionPoint_Unadvise,
3320     ConnectionPoint_EnumConnections
3321 };
3322
3323 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3324 {
3325     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3326     cp->doc = doc;
3327     cp->iid = riid;
3328     cp->sinks = NULL;
3329     cp->sinks_size = 0;
3330
3331     cp->next = doc->cp_list;
3332     doc->cp_list = cp;
3333
3334     cp->container = &doc->IConnectionPointContainer_iface;
3335 }
3336
3337 /* domdoc implementation of IObjectWithSite */
3338 static HRESULT WINAPI
3339 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3340 {
3341     domdoc *This = impl_from_IObjectWithSite(iface);
3342     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3343 }
3344
3345 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3346 {
3347     domdoc *This = impl_from_IObjectWithSite(iface);
3348     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3349 }
3350
3351 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3352 {
3353     domdoc *This = impl_from_IObjectWithSite(iface);
3354     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3355 }
3356
3357 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3358 {
3359     domdoc *This = impl_from_IObjectWithSite(iface);
3360
3361     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3362
3363     if ( !This->site )
3364         return E_FAIL;
3365
3366     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3367 }
3368
3369 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3370 {
3371     domdoc *This = impl_from_IObjectWithSite(iface);
3372
3373     TRACE("(%p)->(%p)\n", iface, punk);
3374
3375     if(!punk)
3376     {
3377         if(This->site)
3378         {
3379             IUnknown_Release( This->site );
3380             This->site = NULL;
3381         }
3382
3383         return S_OK;
3384     }
3385
3386     IUnknown_AddRef( punk );
3387
3388     if(This->site)
3389         IUnknown_Release( This->site );
3390
3391     This->site = punk;
3392
3393     return S_OK;
3394 }
3395
3396 static const IObjectWithSiteVtbl domdocObjectSite =
3397 {
3398     domdoc_ObjectWithSite_QueryInterface,
3399     domdoc_ObjectWithSite_AddRef,
3400     domdoc_ObjectWithSite_Release,
3401     domdoc_ObjectWithSite_SetSite,
3402     domdoc_ObjectWithSite_GetSite
3403 };
3404
3405 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3406 {
3407     domdoc *This = impl_from_IObjectSafety(iface);
3408     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3409 }
3410
3411 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3412 {
3413     domdoc *This = impl_from_IObjectSafety(iface);
3414     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3415 }
3416
3417 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3418 {
3419     domdoc *This = impl_from_IObjectSafety(iface);
3420     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3421 }
3422
3423 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3424
3425 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3426         DWORD *supported, DWORD *enabled)
3427 {
3428     domdoc *This = impl_from_IObjectSafety(iface);
3429
3430     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3431
3432     if(!supported || !enabled) return E_POINTER;
3433
3434     *supported = SAFETY_SUPPORTED_OPTIONS;
3435     *enabled = This->safeopt;
3436
3437     return S_OK;
3438 }
3439
3440 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3441         DWORD mask, DWORD enabled)
3442 {
3443     domdoc *This = impl_from_IObjectSafety(iface);
3444     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3445
3446     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3447         return E_FAIL;
3448
3449     This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3450     return S_OK;
3451 }
3452
3453 #undef SAFETY_SUPPORTED_OPTIONS
3454
3455 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3456     domdoc_Safety_QueryInterface,
3457     domdoc_Safety_AddRef,
3458     domdoc_Safety_Release,
3459     domdoc_Safety_GetInterfaceSafetyOptions,
3460     domdoc_Safety_SetInterfaceSafetyOptions
3461 };
3462
3463 static const tid_t domdoc_iface_tids[] = {
3464     IXMLDOMNode_tid,
3465     IXMLDOMDocument_tid,
3466     IXMLDOMDocument2_tid,
3467     0
3468 };
3469 static dispex_static_data_t domdoc_dispex = {
3470     NULL,
3471     IXMLDOMDocument2_tid,
3472     NULL,
3473     domdoc_iface_tids
3474 };
3475
3476 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3477 {
3478     domdoc *doc;
3479
3480     doc = heap_alloc( sizeof (*doc) );
3481     if( !doc )
3482         return E_OUTOFMEMORY;
3483
3484     doc->IXMLDOMDocument3_iface.lpVtbl = &domdoc_vtbl;
3485     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3486     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3487     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3488     doc->ISupportErrorInfo_iface.lpVtbl = &support_error_vtbl;
3489     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3490     doc->ref = 1;
3491     doc->async = VARIANT_TRUE;
3492     doc->validating = 0;
3493     doc->resolving = 0;
3494     doc->properties = properties_from_xmlDocPtr(xmldoc);
3495     doc->error = S_OK;
3496     doc->stream = NULL;
3497     doc->site = NULL;
3498     doc->safeopt = 0;
3499     doc->bsc = NULL;
3500     doc->cp_list = NULL;
3501     memset(doc->events, 0, sizeof(doc->events));
3502
3503     /* events connection points */
3504     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3505     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3506     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3507
3508     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3509             &domdoc_dispex);
3510
3511     *document = &doc->IXMLDOMDocument3_iface;
3512
3513     TRACE("returning iface %p\n", *document);
3514     return S_OK;
3515 }
3516
3517 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3518 {
3519     xmlDocPtr xmldoc;
3520     HRESULT hr;
3521
3522     TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3523
3524     xmldoc = xmlNewDoc(NULL);
3525     if(!xmldoc)
3526         return E_OUTOFMEMORY;
3527
3528     xmldoc->_private = create_priv();
3529     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3530
3531     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3532     if(FAILED(hr))
3533     {
3534         free_properties(properties_from_xmlDocPtr(xmldoc));
3535         heap_free(xmldoc->_private);
3536         xmlFreeDoc(xmldoc);
3537         return hr;
3538     }
3539
3540     return hr;
3541 }
3542
3543 IUnknown* create_domdoc( xmlNodePtr document )
3544 {
3545     void* pObj = NULL;
3546     HRESULT hr;
3547
3548     TRACE("(%p)\n", document);
3549
3550     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3551     if (FAILED(hr))
3552         return NULL;
3553
3554     return pObj;
3555 }
3556
3557 #else
3558
3559 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3560 {
3561     MESSAGE("This program tried to use a DOMDocument object, but\n"
3562             "libxml2 support was not present at compile time.\n");
3563     return E_NOTIMPL;
3564 }
3565
3566 #endif