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