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