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