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