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