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