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