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