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