hlink: Site data should only be set if the hlink has an HlinkSite.
[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* prefix )
1335 {
1336     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1337     TRACE("(%p)->(%p)\n", This, prefix);
1338     return return_null_bstr( prefix );
1339 }
1340
1341
1342 static HRESULT WINAPI domdoc_get_baseName(
1343     IXMLDOMDocument3 *iface,
1344     BSTR* name )
1345 {
1346     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1347     TRACE("(%p)->(%p)\n", This, name);
1348     return return_null_bstr( name );
1349 }
1350
1351
1352 static HRESULT WINAPI domdoc_transformNodeToObject(
1353     IXMLDOMDocument3 *iface,
1354     IXMLDOMNode* stylesheet,
1355     VARIANT outputObject)
1356 {
1357     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1358     return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), stylesheet, outputObject );
1359 }
1360
1361
1362 static HRESULT WINAPI domdoc_get_doctype(
1363     IXMLDOMDocument3 *iface,
1364     IXMLDOMDocumentType** documentType )
1365 {
1366     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1367     FIXME("(%p)\n", This);
1368     return E_NOTIMPL;
1369 }
1370
1371
1372 static HRESULT WINAPI domdoc_get_implementation(
1373     IXMLDOMDocument3 *iface,
1374     IXMLDOMImplementation** impl )
1375 {
1376     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1377
1378     TRACE("(%p)->(%p)\n", This, impl);
1379
1380     if(!impl)
1381         return E_INVALIDARG;
1382
1383     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1384
1385     return S_OK;
1386 }
1387
1388 static HRESULT WINAPI domdoc_get_documentElement(
1389     IXMLDOMDocument3 *iface,
1390     IXMLDOMElement** DOMElement )
1391 {
1392     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1393     IXMLDOMNode *element_node;
1394     xmlNodePtr root;
1395     HRESULT hr;
1396
1397     TRACE("(%p)->(%p)\n", This, DOMElement);
1398
1399     if(!DOMElement)
1400         return E_INVALIDARG;
1401
1402     *DOMElement = NULL;
1403
1404     root = xmlDocGetRootElement( get_doc(This) );
1405     if ( !root )
1406         return S_FALSE;
1407
1408     element_node = create_node( root );
1409     if(!element_node) return S_FALSE;
1410
1411     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1412     IXMLDOMNode_Release(element_node);
1413
1414     return hr;
1415 }
1416
1417
1418 static HRESULT WINAPI domdoc_put_documentElement(
1419     IXMLDOMDocument3 *iface,
1420     IXMLDOMElement* DOMElement )
1421 {
1422     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1423     IXMLDOMNode *elementNode;
1424     xmlNodePtr oldRoot;
1425     xmlnode *xmlNode;
1426     HRESULT hr;
1427
1428     TRACE("(%p)->(%p)\n", This, DOMElement);
1429
1430     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1431     if(FAILED(hr))
1432         return hr;
1433
1434     xmlNode = get_node_obj( elementNode );
1435     if(!xmlNode) {
1436         FIXME("elementNode is not our object\n");
1437         return E_FAIL;
1438     }
1439
1440     if(!xmlNode->node->parent)
1441         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1442             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1443
1444     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1445     IXMLDOMNode_Release( elementNode );
1446
1447     if(oldRoot)
1448         xmldoc_add_orphan(oldRoot->doc, oldRoot);
1449
1450     return S_OK;
1451 }
1452
1453
1454 static HRESULT WINAPI domdoc_createElement(
1455     IXMLDOMDocument3 *iface,
1456     BSTR tagname,
1457     IXMLDOMElement** element )
1458 {
1459     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1460     IXMLDOMNode *node;
1461     VARIANT type;
1462     HRESULT hr;
1463
1464     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1465
1466     if (!element || !tagname) return E_INVALIDARG;
1467
1468     V_VT(&type) = VT_I1;
1469     V_I1(&type) = NODE_ELEMENT;
1470
1471     hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1472     if (hr == S_OK)
1473     {
1474         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1475         IXMLDOMNode_Release(node);
1476     }
1477
1478     return hr;
1479 }
1480
1481
1482 static HRESULT WINAPI domdoc_createDocumentFragment(
1483     IXMLDOMDocument3 *iface,
1484     IXMLDOMDocumentFragment** frag )
1485 {
1486     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1487     IXMLDOMNode *node;
1488     VARIANT type;
1489     HRESULT hr;
1490
1491     TRACE("(%p)->(%p)\n", This, frag);
1492
1493     if (!frag) return E_INVALIDARG;
1494
1495     *frag = NULL;
1496
1497     V_VT(&type) = VT_I1;
1498     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1499
1500     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1501     if (hr == S_OK)
1502     {
1503         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1504         IXMLDOMNode_Release(node);
1505     }
1506
1507     return hr;
1508 }
1509
1510
1511 static HRESULT WINAPI domdoc_createTextNode(
1512     IXMLDOMDocument3 *iface,
1513     BSTR data,
1514     IXMLDOMText** text )
1515 {
1516     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1517     IXMLDOMNode *node;
1518     VARIANT type;
1519     HRESULT hr;
1520
1521     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1522
1523     if (!text) return E_INVALIDARG;
1524
1525     *text = NULL;
1526
1527     V_VT(&type) = VT_I1;
1528     V_I1(&type) = NODE_TEXT;
1529
1530     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1531     if (hr == S_OK)
1532     {
1533         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1534         IXMLDOMNode_Release(node);
1535         hr = IXMLDOMText_put_data(*text, data);
1536     }
1537
1538     return hr;
1539 }
1540
1541
1542 static HRESULT WINAPI domdoc_createComment(
1543     IXMLDOMDocument3 *iface,
1544     BSTR data,
1545     IXMLDOMComment** comment )
1546 {
1547     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1548     VARIANT type;
1549     HRESULT hr;
1550     IXMLDOMNode *node;
1551
1552     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1553
1554     if (!comment) return E_INVALIDARG;
1555
1556     *comment = NULL;
1557
1558     V_VT(&type) = VT_I1;
1559     V_I1(&type) = NODE_COMMENT;
1560
1561     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1562     if (hr == S_OK)
1563     {
1564         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1565         IXMLDOMNode_Release(node);
1566         hr = IXMLDOMComment_put_data(*comment, data);
1567     }
1568
1569     return hr;
1570 }
1571
1572
1573 static HRESULT WINAPI domdoc_createCDATASection(
1574     IXMLDOMDocument3 *iface,
1575     BSTR data,
1576     IXMLDOMCDATASection** cdata )
1577 {
1578     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1579     IXMLDOMNode *node;
1580     VARIANT type;
1581     HRESULT hr;
1582
1583     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1584
1585     if (!cdata) return E_INVALIDARG;
1586
1587     *cdata = NULL;
1588
1589     V_VT(&type) = VT_I1;
1590     V_I1(&type) = NODE_CDATA_SECTION;
1591
1592     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1593     if (hr == S_OK)
1594     {
1595         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1596         IXMLDOMNode_Release(node);
1597         hr = IXMLDOMCDATASection_put_data(*cdata, data);
1598     }
1599
1600     return hr;
1601 }
1602
1603
1604 static HRESULT WINAPI domdoc_createProcessingInstruction(
1605     IXMLDOMDocument3 *iface,
1606     BSTR target,
1607     BSTR data,
1608     IXMLDOMProcessingInstruction** pi )
1609 {
1610     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1611     IXMLDOMNode *node;
1612     VARIANT type;
1613     HRESULT hr;
1614
1615     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1616
1617     if (!pi) return E_INVALIDARG;
1618
1619     *pi = NULL;
1620
1621     V_VT(&type) = VT_I1;
1622     V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1623
1624     hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1625     if (hr == S_OK)
1626     {
1627         xmlnode *node_obj;
1628
1629         /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1630         node_obj = get_node_obj(node);
1631         hr = node_set_content(node_obj, data);
1632
1633         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1634         IXMLDOMNode_Release(node);
1635     }
1636
1637     return hr;
1638 }
1639
1640
1641 static HRESULT WINAPI domdoc_createAttribute(
1642     IXMLDOMDocument3 *iface,
1643     BSTR name,
1644     IXMLDOMAttribute** attribute )
1645 {
1646     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1647     IXMLDOMNode *node;
1648     VARIANT type;
1649     HRESULT hr;
1650
1651     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1652
1653     if (!attribute || !name) return E_INVALIDARG;
1654
1655     V_VT(&type) = VT_I1;
1656     V_I1(&type) = NODE_ATTRIBUTE;
1657
1658     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1659     if (hr == S_OK)
1660     {
1661         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1662         IXMLDOMNode_Release(node);
1663     }
1664
1665     return hr;
1666 }
1667
1668
1669 static HRESULT WINAPI domdoc_createEntityReference(
1670     IXMLDOMDocument3 *iface,
1671     BSTR name,
1672     IXMLDOMEntityReference** entityref )
1673 {
1674     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1675     IXMLDOMNode *node;
1676     VARIANT type;
1677     HRESULT hr;
1678
1679     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1680
1681     if (!entityref) return E_INVALIDARG;
1682
1683     *entityref = NULL;
1684
1685     V_VT(&type) = VT_I1;
1686     V_I1(&type) = NODE_ENTITY_REFERENCE;
1687
1688     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1689     if (hr == S_OK)
1690     {
1691         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1692         IXMLDOMNode_Release(node);
1693     }
1694
1695     return hr;
1696 }
1697
1698
1699 static HRESULT WINAPI domdoc_getElementsByTagName(
1700     IXMLDOMDocument3 *iface,
1701     BSTR tagName,
1702     IXMLDOMNodeList** resultList )
1703 {
1704     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1705     HRESULT hr;
1706
1707     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagName), resultList);
1708
1709     if (!tagName || !resultList) return E_INVALIDARG;
1710
1711     if (tagName[0] == '*' && tagName[1] == 0)
1712     {
1713         static const WCHAR formatallW[] = {'/','/','*',0};
1714         hr = queryresult_create((xmlNodePtr)get_doc(This), formatallW, resultList);
1715     }
1716     else
1717     {
1718         static const WCHAR xpathformat[] =
1719             { '/','/','*','[','l','o','c','a','l','-','n','a','m','e','(',')','=','\'' };
1720         static const WCHAR closeW[] = { '\'',']',0 };
1721
1722         LPWSTR pattern;
1723         WCHAR *ptr;
1724         INT length;
1725
1726         length = lstrlenW(tagName);
1727
1728         /* without two WCHARs from format specifier */
1729         ptr = pattern = heap_alloc(sizeof(xpathformat) + length*sizeof(WCHAR) + sizeof(closeW));
1730
1731         memcpy(ptr, xpathformat, sizeof(xpathformat));
1732         ptr += sizeof(xpathformat)/sizeof(WCHAR);
1733         memcpy(ptr, tagName, length*sizeof(WCHAR));
1734         ptr += length;
1735         memcpy(ptr, closeW, sizeof(closeW));
1736
1737         hr = queryresult_create((xmlNodePtr)get_doc(This), pattern, resultList);
1738         heap_free(pattern);
1739     }
1740
1741     return hr;
1742 }
1743
1744 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1745 {
1746     VARIANT tmp;
1747     HRESULT hr;
1748
1749     VariantInit(&tmp);
1750     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1751     if(FAILED(hr))
1752         return E_INVALIDARG;
1753
1754     *type = V_I4(&tmp);
1755
1756     return S_OK;
1757 }
1758
1759 static HRESULT WINAPI domdoc_createNode(
1760     IXMLDOMDocument3 *iface,
1761     VARIANT Type,
1762     BSTR name,
1763     BSTR namespaceURI,
1764     IXMLDOMNode** node )
1765 {
1766     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1767     DOMNodeType node_type;
1768     xmlNodePtr xmlnode;
1769     xmlChar *xml_name, *href;
1770     HRESULT hr;
1771
1772     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1773
1774     if(!node) return E_INVALIDARG;
1775
1776     hr = get_node_type(Type, &node_type);
1777     if(FAILED(hr)) return hr;
1778
1779     if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1780         FIXME("nodes with namespaces currently not supported.\n");
1781
1782     TRACE("node_type %d\n", node_type);
1783
1784     /* exit earlier for types that need name */
1785     switch(node_type)
1786     {
1787     case NODE_ELEMENT:
1788     case NODE_ATTRIBUTE:
1789     case NODE_ENTITY_REFERENCE:
1790     case NODE_PROCESSING_INSTRUCTION:
1791         if (!name || *name == 0) return E_FAIL;
1792     default:
1793         break;
1794     }
1795
1796     xml_name = xmlChar_from_wchar(name);
1797     /* prevent empty href to be allocated */
1798     href = namespaceURI ? xmlChar_from_wchar(namespaceURI) : NULL;
1799
1800     switch(node_type)
1801     {
1802     case NODE_ELEMENT:
1803     {
1804         xmlChar *local, *prefix;
1805
1806         local = xmlSplitQName2(xml_name, &prefix);
1807
1808         xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1809
1810         /* allow to create default namespace xmlns= */
1811         if (local || (href && *href))
1812         {
1813             xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1814             xmlSetNs(xmlnode, ns);
1815         }
1816
1817         xmlFree(local);
1818         xmlFree(prefix);
1819
1820         break;
1821     }
1822     case NODE_ATTRIBUTE:
1823         xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1824         break;
1825     case NODE_TEXT:
1826         xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1827         break;
1828     case NODE_CDATA_SECTION:
1829         xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1830         break;
1831     case NODE_ENTITY_REFERENCE:
1832         xmlnode = xmlNewReference(get_doc(This), xml_name);
1833         break;
1834     case NODE_PROCESSING_INSTRUCTION:
1835 #ifdef HAVE_XMLNEWDOCPI
1836         xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1837 #else
1838         FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1839         xmlnode = NULL;
1840 #endif
1841         break;
1842     case NODE_COMMENT:
1843         xmlnode = xmlNewDocComment(get_doc(This), NULL);
1844         break;
1845     case NODE_DOCUMENT_FRAGMENT:
1846         xmlnode = xmlNewDocFragment(get_doc(This));
1847         break;
1848     /* unsupported types */
1849     case NODE_DOCUMENT:
1850     case NODE_DOCUMENT_TYPE:
1851     case NODE_ENTITY:
1852     case NODE_NOTATION:
1853         heap_free(xml_name);
1854         return E_INVALIDARG;
1855     default:
1856         FIXME("unhandled node type %d\n", node_type);
1857         xmlnode = NULL;
1858         break;
1859     }
1860
1861     *node = create_node(xmlnode);
1862     heap_free(xml_name);
1863     heap_free(href);
1864
1865     if(*node)
1866     {
1867         TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1868         xmldoc_add_orphan(xmlnode->doc, xmlnode);
1869         return S_OK;
1870     }
1871
1872     return E_FAIL;
1873 }
1874
1875 static HRESULT WINAPI domdoc_nodeFromID(
1876     IXMLDOMDocument3 *iface,
1877     BSTR idString,
1878     IXMLDOMNode** node )
1879 {
1880     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1881     FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1882     return E_NOTIMPL;
1883 }
1884
1885 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1886 {
1887     domdoc *This = obj;
1888     xmlDocPtr xmldoc;
1889
1890     xmldoc = doparse(This, ptr, len, NULL);
1891     if(xmldoc) {
1892         xmldoc->_private = create_priv();
1893         return attach_xmldoc(This, xmldoc);
1894     }
1895
1896     return S_OK;
1897 }
1898
1899 static HRESULT doread( domdoc *This, LPWSTR filename )
1900 {
1901     bsc_t *bsc;
1902     HRESULT hr;
1903
1904     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
1905     if(FAILED(hr))
1906         return hr;
1907
1908     if(This->bsc)
1909         detach_bsc(This->bsc);
1910
1911     This->bsc = bsc;
1912     return S_OK;
1913 }
1914
1915 static HRESULT WINAPI domdoc_load(
1916     IXMLDOMDocument3 *iface,
1917     VARIANT xmlSource,
1918     VARIANT_BOOL* isSuccessful )
1919 {
1920     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1921     LPWSTR filename = NULL;
1922     HRESULT hr = S_FALSE;
1923     IXMLDOMDocument3 *pNewDoc = NULL;
1924     IStream *pStream = NULL;
1925     xmlDocPtr xmldoc;
1926
1927     TRACE("(%p)->type %d\n", This, V_VT(&xmlSource) );
1928
1929     *isSuccessful = VARIANT_FALSE;
1930
1931     assert( &This->node );
1932
1933     switch( V_VT(&xmlSource) )
1934     {
1935     case VT_BSTR:
1936         filename = V_BSTR(&xmlSource);
1937         break;
1938     case VT_UNKNOWN:
1939         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
1940         if(hr == S_OK)
1941         {
1942             if(pNewDoc)
1943             {
1944                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
1945                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
1946                 hr = attach_xmldoc(This, xmldoc);
1947
1948                 if(SUCCEEDED(hr))
1949                     *isSuccessful = VARIANT_TRUE;
1950
1951                 return hr;
1952             }
1953         }
1954         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
1955         if(hr == S_OK)
1956         {
1957             IPersistStream *pDocStream;
1958             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
1959             if(hr == S_OK)
1960             {
1961                 hr = IPersistStream_Load(pDocStream, pStream);
1962                 IStream_Release(pStream);
1963                 if(hr == S_OK)
1964                 {
1965                     *isSuccessful = VARIANT_TRUE;
1966
1967                     TRACE("Using IStream to load Document\n");
1968                     return S_OK;
1969                 }
1970                 else
1971                 {
1972                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
1973                 }
1974             }
1975             else
1976             {
1977                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
1978             }
1979         }
1980         else
1981         {
1982             /* ISequentialStream */
1983             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
1984         }
1985         break;
1986      default:
1987             FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
1988      }
1989
1990     TRACE("filename (%s)\n", debugstr_w(filename));
1991
1992     if ( filename )
1993     {
1994         hr = doread( This, filename );
1995
1996         if ( FAILED(hr) )
1997             This->error = E_FAIL;
1998         else
1999         {
2000             hr = This->error = S_OK;
2001             *isSuccessful = VARIANT_TRUE;
2002         }
2003     }
2004
2005     if(!filename || FAILED(hr)) {
2006         xmldoc = xmlNewDoc(NULL);
2007         xmldoc->_private = create_priv();
2008         hr = attach_xmldoc(This, xmldoc);
2009         if(SUCCEEDED(hr))
2010             hr = S_FALSE;
2011     }
2012
2013     TRACE("ret (%d)\n", hr);
2014
2015     return hr;
2016 }
2017
2018
2019 static HRESULT WINAPI domdoc_get_readyState(
2020     IXMLDOMDocument3 *iface,
2021     LONG *value )
2022 {
2023     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2024     FIXME("stub! (%p)->(%p)\n", This, value);
2025
2026     if (!value)
2027         return E_INVALIDARG;
2028
2029     *value = READYSTATE_COMPLETE;
2030     return S_OK;
2031 }
2032
2033
2034 static HRESULT WINAPI domdoc_get_parseError(
2035     IXMLDOMDocument3 *iface,
2036     IXMLDOMParseError** errorObj )
2037 {
2038     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2039     static const WCHAR err[] = {'e','r','r','o','r',0};
2040     BSTR error_string = NULL;
2041
2042     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2043
2044     if(This->error)
2045         error_string = SysAllocString(err);
2046
2047     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2048     if(!*errorObj) return E_OUTOFMEMORY;
2049     return S_OK;
2050 }
2051
2052
2053 static HRESULT WINAPI domdoc_get_url(
2054     IXMLDOMDocument3 *iface,
2055     BSTR* urlString )
2056 {
2057     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2058     FIXME("(%p)->(%p)\n", This, urlString);
2059     return E_NOTIMPL;
2060 }
2061
2062
2063 static HRESULT WINAPI domdoc_get_async(
2064     IXMLDOMDocument3 *iface,
2065     VARIANT_BOOL* isAsync )
2066 {
2067     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2068
2069     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2070     *isAsync = This->async;
2071     return S_OK;
2072 }
2073
2074
2075 static HRESULT WINAPI domdoc_put_async(
2076     IXMLDOMDocument3 *iface,
2077     VARIANT_BOOL isAsync )
2078 {
2079     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2080
2081     TRACE("(%p)->(%d)\n", This, isAsync);
2082     This->async = isAsync;
2083     return S_OK;
2084 }
2085
2086
2087 static HRESULT WINAPI domdoc_abort(
2088     IXMLDOMDocument3 *iface )
2089 {
2090     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2091     FIXME("%p\n", This);
2092     return E_NOTIMPL;
2093 }
2094
2095
2096 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
2097 {
2098     UINT len;
2099     LPSTR str;
2100
2101     len = WideCharToMultiByte( CP_UTF8, 0, bstr, -1, NULL, 0, NULL, NULL );
2102     str = heap_alloc( len );
2103     if ( !str )
2104         return FALSE;
2105     WideCharToMultiByte( CP_UTF8, 0, bstr, -1, str, len, NULL, NULL );
2106     *plen = len;
2107     *pstr = str;
2108     return TRUE;
2109 }
2110
2111 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2112 static HRESULT WINAPI domdoc_loadXML(
2113     IXMLDOMDocument3 *iface,
2114     BSTR bstrXML,
2115     VARIANT_BOOL* isSuccessful )
2116 {
2117     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2118     static const xmlChar encoding[] = "UTF-8";
2119     xmlDocPtr xmldoc = NULL;
2120     HRESULT hr = S_FALSE, hr2;
2121     char *str;
2122     int len;
2123
2124     TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2125
2126     assert ( &This->node );
2127
2128     if ( isSuccessful )
2129     {
2130         *isSuccessful = VARIANT_FALSE;
2131
2132         if ( bstrXML && bstr_to_utf8( bstrXML, &str, &len ) )
2133         {
2134             xmldoc = doparse(This, str, len, encoding);
2135             heap_free( str );
2136             if ( !xmldoc )
2137             {
2138                 This->error = E_FAIL;
2139                 TRACE("failed to parse document\n");
2140             }
2141             else
2142             {
2143                 hr = This->error = S_OK;
2144                 *isSuccessful = VARIANT_TRUE;
2145                 TRACE("parsed document %p\n", xmldoc);
2146             }
2147         }
2148     }
2149     if(!xmldoc)
2150         xmldoc = xmlNewDoc(NULL);
2151
2152     xmldoc->_private = create_priv();
2153
2154     hr2 = attach_xmldoc(This, xmldoc);
2155     if( FAILED(hr2) )
2156         hr = hr2;
2157
2158     return hr;
2159 }
2160
2161 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2162 {
2163     DWORD written = -1;
2164
2165     if(!WriteFile(ctx, buffer, len, &written, NULL))
2166     {
2167         WARN("write error\n");
2168         return -1;
2169     }
2170     else
2171         return written;
2172 }
2173
2174 static int XMLCALL domdoc_save_closecallback(void *ctx)
2175 {
2176     return CloseHandle(ctx) ? 0 : -1;
2177 }
2178
2179 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2180 {
2181     ULONG written = 0;
2182     HRESULT hr;
2183
2184     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2185     if (hr != S_OK)
2186     {
2187         WARN("stream write error: 0x%08x\n", hr);
2188         return -1;
2189     }
2190     else
2191         return written;
2192 }
2193
2194 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2195 {
2196     IStream_Release((IStream*)ctx);
2197     return 0;
2198 }
2199
2200 static HRESULT WINAPI domdoc_save(
2201     IXMLDOMDocument3 *iface,
2202     VARIANT destination )
2203 {
2204     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2205     xmlSaveCtxtPtr ctx = NULL;
2206     xmlNodePtr xmldecl;
2207     HRESULT ret = S_OK;
2208
2209     TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
2210           V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2211
2212     if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2213     {
2214         FIXME("Unhandled vt %d\n", V_VT(&destination));
2215         return S_FALSE;
2216     }
2217
2218     if(V_VT(&destination) == VT_UNKNOWN)
2219     {
2220         IUnknown *pUnk = V_UNKNOWN(&destination);
2221         IXMLDOMDocument2 *document;
2222         IStream *stream;
2223
2224         ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2225         if(ret == S_OK)
2226         {
2227             VARIANT_BOOL success;
2228             BSTR xml;
2229
2230             ret = IXMLDOMDocument3_get_xml(iface, &xml);
2231             if(ret == S_OK)
2232             {
2233                 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2234                 SysFreeString(xml);
2235             }
2236
2237             IXMLDOMDocument3_Release(document);
2238             return ret;
2239         }
2240
2241         ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2242         if(ret == S_OK)
2243         {
2244             ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2245                 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2246
2247             if(!ctx)
2248             {
2249                 IStream_Release(stream);
2250                 return E_FAIL;
2251             }
2252         }
2253     }
2254     else
2255     {
2256         /* save with file path */
2257         HANDLE handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2258                                     NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2259         if( handle == INVALID_HANDLE_VALUE )
2260         {
2261             WARN("failed to create file\n");
2262             return E_FAIL;
2263         }
2264
2265         /* disable top XML declaration */
2266         ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2267                           handle, NULL, XML_SAVE_NO_DECL);
2268         if (!ctx)
2269         {
2270             CloseHandle(handle);
2271             return E_FAIL;
2272         }
2273     }
2274
2275     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2276     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2277     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2278
2279     /* will release resources through close callback */
2280     xmlSaveClose(ctx);
2281
2282     return ret;
2283 }
2284
2285 static HRESULT WINAPI domdoc_get_validateOnParse(
2286     IXMLDOMDocument3 *iface,
2287     VARIANT_BOOL* isValidating )
2288 {
2289     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2290     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2291     *isValidating = This->validating;
2292     return S_OK;
2293 }
2294
2295
2296 static HRESULT WINAPI domdoc_put_validateOnParse(
2297     IXMLDOMDocument3 *iface,
2298     VARIANT_BOOL isValidating )
2299 {
2300     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2301     TRACE("(%p)->(%d)\n", This, isValidating);
2302     This->validating = isValidating;
2303     return S_OK;
2304 }
2305
2306
2307 static HRESULT WINAPI domdoc_get_resolveExternals(
2308     IXMLDOMDocument3 *iface,
2309     VARIANT_BOOL* isResolving )
2310 {
2311     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2312     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2313     *isResolving = This->resolving;
2314     return S_OK;
2315 }
2316
2317
2318 static HRESULT WINAPI domdoc_put_resolveExternals(
2319     IXMLDOMDocument3 *iface,
2320     VARIANT_BOOL isResolving )
2321 {
2322     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2323     TRACE("(%p)->(%d)\n", This, isResolving);
2324     This->resolving = isResolving;
2325     return S_OK;
2326 }
2327
2328
2329 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2330     IXMLDOMDocument3 *iface,
2331     VARIANT_BOOL* isPreserving )
2332 {
2333     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2334     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->preserving);
2335     *isPreserving = This->preserving;
2336     return S_OK;
2337 }
2338
2339
2340 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2341     IXMLDOMDocument3 *iface,
2342     VARIANT_BOOL isPreserving )
2343 {
2344     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2345     TRACE("(%p)->(%d)\n", This, isPreserving);
2346     This->preserving = isPreserving;
2347     return S_OK;
2348 }
2349
2350
2351 static HRESULT WINAPI domdoc_put_onReadyStateChange(
2352     IXMLDOMDocument3 *iface,
2353     VARIANT readyStateChangeSink )
2354 {
2355     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2356     FIXME("%p\n", This);
2357     return E_NOTIMPL;
2358 }
2359
2360
2361 static HRESULT WINAPI domdoc_put_onDataAvailable(
2362     IXMLDOMDocument3 *iface,
2363     VARIANT onDataAvailableSink )
2364 {
2365     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2366     FIXME("%p\n", This);
2367     return E_NOTIMPL;
2368 }
2369
2370 static HRESULT WINAPI domdoc_put_onTransformNode(
2371     IXMLDOMDocument3 *iface,
2372     VARIANT onTransformNodeSink )
2373 {
2374     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2375     FIXME("%p\n", This);
2376     return E_NOTIMPL;
2377 }
2378
2379 static HRESULT WINAPI domdoc_get_namespaces(
2380     IXMLDOMDocument3* iface,
2381     IXMLDOMSchemaCollection** schemaCollection )
2382 {
2383     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2384     FIXME("(%p)->(%p)\n", This, schemaCollection);
2385     return E_NOTIMPL;
2386 }
2387
2388 static HRESULT WINAPI domdoc_get_schemas(
2389     IXMLDOMDocument3* iface,
2390     VARIANT* var1 )
2391 {
2392     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2393     HRESULT hr = S_FALSE;
2394     IXMLDOMSchemaCollection *cur_schema = This->schema;
2395
2396     TRACE("(%p)->(%p)\n", This, var1);
2397
2398     VariantInit(var1); /* Test shows we don't call VariantClear here */
2399     V_VT(var1) = VT_NULL;
2400
2401     if(cur_schema)
2402     {
2403         hr = IXMLDOMSchemaCollection_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2404         if(SUCCEEDED(hr))
2405             V_VT(var1) = VT_DISPATCH;
2406     }
2407     return hr;
2408 }
2409
2410 static HRESULT WINAPI domdoc_putref_schemas(
2411     IXMLDOMDocument3* iface,
2412     VARIANT var1)
2413 {
2414     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2415     HRESULT hr = E_FAIL;
2416     IXMLDOMSchemaCollection *new_schema = NULL;
2417
2418     FIXME("(%p): semi-stub\n", This);
2419     switch(V_VT(&var1))
2420     {
2421     case VT_UNKNOWN:
2422         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2423         break;
2424
2425     case VT_DISPATCH:
2426         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2427         break;
2428
2429     case VT_NULL:
2430     case VT_EMPTY:
2431         hr = S_OK;
2432         break;
2433
2434     default:
2435         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2436     }
2437
2438     if(SUCCEEDED(hr))
2439     {
2440         IXMLDOMSchemaCollection *old_schema = InterlockedExchangePointer((void**)&This->schema, new_schema);
2441         if(old_schema) IXMLDOMSchemaCollection_Release(old_schema);
2442     }
2443
2444     return hr;
2445 }
2446
2447 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2448 {
2449     va_list ap;
2450     va_start(ap, msg);
2451     LIBXML2_CALLBACK_ERR(domdoc_validate, msg, ap);
2452     va_end(ap);
2453 }
2454
2455 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2456 {
2457     va_list ap;
2458     va_start(ap, msg);
2459     LIBXML2_CALLBACK_WARN(domdoc_validate, msg, ap);
2460     va_end(ap);
2461 }
2462
2463 static HRESULT WINAPI domdoc_validate(
2464     IXMLDOMDocument3* iface,
2465     IXMLDOMParseError** err)
2466 {
2467     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2468     LONG state;
2469     xmlValidCtxtPtr vctx;
2470
2471     TRACE("(%p)->(%p)\n", This, err);
2472     domdoc_get_readyState(iface, &state);
2473     if (state != READYSTATE_COMPLETE)
2474     {
2475         if (err)
2476             *err = create_parseError(0, NULL, NULL, NULL, 0, 0, 0);
2477         return E_PENDING;
2478     }
2479
2480     vctx = xmlNewValidCtxt();
2481     vctx->error = validate_error;
2482     vctx->warning = validate_warning;
2483
2484     if (xmlValidateDocument(vctx, get_doc(This)))
2485     {
2486         if (err)
2487             *err = create_parseError(0, NULL, NULL, NULL, 0, 0, 0);
2488         xmlFreeValidCtxt(vctx);
2489         return S_OK;
2490     }
2491
2492     FIXME("partial stub!\n");
2493     if (err)
2494         *err = create_parseError(0xC00CE223, NULL, NULL, NULL, 0, 0, 0);
2495     xmlFreeValidCtxt(vctx);
2496     return S_FALSE;
2497 }
2498
2499 static HRESULT WINAPI domdoc_setProperty(
2500     IXMLDOMDocument3* iface,
2501     BSTR p,
2502     VARIANT var)
2503 {
2504     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2505
2506     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2507
2508     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2509     {
2510         VARIANT varStr;
2511         HRESULT hr;
2512         BSTR bstr;
2513
2514         V_VT(&varStr) = VT_EMPTY;
2515         if (V_VT(&var) != VT_BSTR)
2516         {
2517             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2518                 return hr;
2519             bstr = V_BSTR(&varStr);
2520         }
2521         else
2522             bstr = V_BSTR(&var);
2523
2524         hr = S_OK;
2525         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2526             This->properties->XPath = TRUE;
2527         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2528             This->properties->XPath = FALSE;
2529         else
2530             hr = E_FAIL;
2531
2532         VariantClear(&varStr);
2533         return hr;
2534     }
2535     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2536     {
2537         VARIANT varStr;
2538         HRESULT hr;
2539         BSTR bstr;
2540         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2541         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2542         xmlXPathContextPtr ctx;
2543         struct list *pNsList;
2544         select_ns_entry* pNsEntry = NULL;
2545
2546         V_VT(&varStr) = VT_EMPTY;
2547         if (V_VT(&var) != VT_BSTR)
2548         {
2549             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2550                 return hr;
2551             bstr = V_BSTR(&varStr);
2552         }
2553         else
2554             bstr = V_BSTR(&var);
2555
2556         hr = S_OK;
2557
2558         pNsList = &(This->properties->selectNsList);
2559         clear_selectNsList(pNsList);
2560         heap_free(nsStr);
2561         nsStr = xmlChar_from_wchar(bstr);
2562
2563
2564         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2565
2566         This->properties->selectNsStr = nsStr;
2567         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2568         if (bstr && *bstr)
2569         {
2570             ctx = xmlXPathNewContext(This->node.node->doc);
2571             pTokBegin = nsStr;
2572             pTokEnd = nsStr;
2573             for (; *pTokBegin; pTokBegin = pTokEnd)
2574             {
2575                 if (pNsEntry != NULL)
2576                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2577                 else
2578                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2579
2580                 while (*pTokBegin == ' ')
2581                     ++pTokBegin;
2582                 pTokEnd = pTokBegin;
2583                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2584                     ++pTokEnd;
2585
2586                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2587                 {
2588                     hr = E_FAIL;
2589                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2590                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2591                     continue;
2592                 }
2593
2594                 pTokBegin += 5;
2595                 if (*pTokBegin == '=')
2596                 {
2597                     /*valid for XSLPattern?*/
2598                     FIXME("Setting default xmlns not supported - skipping.\n");
2599                     pTokBegin = pTokEnd;
2600                     continue;
2601                 }
2602                 else if (*pTokBegin == ':')
2603                 {
2604                     pNsEntry->prefix = ++pTokBegin;
2605                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2606                         ;
2607
2608                     if (pTokInner == pTokEnd)
2609                     {
2610                         hr = E_FAIL;
2611                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2612                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2613                         continue;
2614                     }
2615
2616                     pNsEntry->prefix_end = *pTokInner;
2617                     *pTokInner = 0;
2618                     ++pTokInner;
2619
2620                     if (pTokEnd-pTokInner > 1 &&
2621                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2622                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2623                     {
2624                         pNsEntry->href = ++pTokInner;
2625                         pNsEntry->href_end = *(pTokEnd-1);
2626                         *(pTokEnd-1) = 0;
2627                         list_add_tail(pNsList, &pNsEntry->entry);
2628                         /*let libxml figure out if they're valid from here ;)*/
2629                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2630                         {
2631                             hr = E_FAIL;
2632                         }
2633                         pNsEntry = NULL;
2634                         continue;
2635                     }
2636                     else
2637                     {
2638                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2639                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2640                         list_add_tail(pNsList, &pNsEntry->entry);
2641
2642                         pNsEntry = NULL;
2643                         hr = E_FAIL;
2644                         continue;
2645                     }
2646                 }
2647                 else
2648                 {
2649                     hr = E_FAIL;
2650                     continue;
2651                 }
2652             }
2653             heap_free(pNsEntry);
2654             xmlXPathFreeContext(ctx);
2655         }
2656
2657         VariantClear(&varStr);
2658         return hr;
2659     }
2660     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2661              lstrcmpiW(p, PropertyNewParserW) == 0)
2662     {
2663         /* Ignore */
2664         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2665         return S_OK;
2666     }
2667
2668     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2669     return E_FAIL;
2670 }
2671
2672 static HRESULT WINAPI domdoc_getProperty(
2673     IXMLDOMDocument3* iface,
2674     BSTR p,
2675     VARIANT* var)
2676 {
2677     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2678
2679     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2680
2681     if (!var)
2682         return E_INVALIDARG;
2683
2684     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2685     {
2686         V_VT(var) = VT_BSTR;
2687         V_BSTR(var) = This->properties->XPath ?
2688                       SysAllocString(PropValueXPathW) :
2689                       SysAllocString(PropValueXSLPatternW);
2690         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2691     }
2692     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2693     {
2694         int lenA, lenW;
2695         BSTR rebuiltStr, cur;
2696         const xmlChar *nsStr;
2697         struct list *pNsList;
2698         select_ns_entry* pNsEntry;
2699
2700         V_VT(var) = VT_BSTR;
2701         nsStr = This->properties->selectNsStr;
2702         pNsList = &This->properties->selectNsList;
2703         lenA = This->properties->selectNsStr_len;
2704         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2705         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2706         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2707         cur = rebuiltStr;
2708         /* this is fine because all of the chars that end tokens are ASCII*/
2709         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2710         {
2711             while (*cur != 0) ++cur;
2712             if (pNsEntry->prefix_end)
2713             {
2714                 *cur = pNsEntry->prefix_end;
2715                 while (*cur != 0) ++cur;
2716             }
2717
2718             if (pNsEntry->href_end)
2719             {
2720                 *cur = pNsEntry->href_end;
2721             }
2722         }
2723         V_BSTR(var) = SysAllocString(rebuiltStr);
2724         heap_free(rebuiltStr);
2725         return S_OK;
2726     }
2727
2728     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2729     return E_FAIL;
2730 }
2731
2732 static HRESULT WINAPI domdoc_validateNode(
2733     IXMLDOMDocument3* iface,
2734     IXMLDOMNode* node,
2735     IXMLDOMParseError** error)
2736 {
2737     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2738     FIXME("(%p)->(%p %p): stub\n", This, node, error);
2739     return E_NOTIMPL;
2740 }
2741
2742 static HRESULT WINAPI domdoc_importNode(
2743     IXMLDOMDocument3* iface,
2744     IXMLDOMNode* node,
2745     VARIANT_BOOL deep,
2746     IXMLDOMNode** clone)
2747 {
2748     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2749     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2750     return E_NOTIMPL;
2751 }
2752
2753 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
2754 {
2755     domdoc_QueryInterface,
2756     domdoc_AddRef,
2757     domdoc_Release,
2758     domdoc_GetTypeInfoCount,
2759     domdoc_GetTypeInfo,
2760     domdoc_GetIDsOfNames,
2761     domdoc_Invoke,
2762     domdoc_get_nodeName,
2763     domdoc_get_nodeValue,
2764     domdoc_put_nodeValue,
2765     domdoc_get_nodeType,
2766     domdoc_get_parentNode,
2767     domdoc_get_childNodes,
2768     domdoc_get_firstChild,
2769     domdoc_get_lastChild,
2770     domdoc_get_previousSibling,
2771     domdoc_get_nextSibling,
2772     domdoc_get_attributes,
2773     domdoc_insertBefore,
2774     domdoc_replaceChild,
2775     domdoc_removeChild,
2776     domdoc_appendChild,
2777     domdoc_hasChildNodes,
2778     domdoc_get_ownerDocument,
2779     domdoc_cloneNode,
2780     domdoc_get_nodeTypeString,
2781     domdoc_get_text,
2782     domdoc_put_text,
2783     domdoc_get_specified,
2784     domdoc_get_definition,
2785     domdoc_get_nodeTypedValue,
2786     domdoc_put_nodeTypedValue,
2787     domdoc_get_dataType,
2788     domdoc_put_dataType,
2789     domdoc_get_xml,
2790     domdoc_transformNode,
2791     domdoc_selectNodes,
2792     domdoc_selectSingleNode,
2793     domdoc_get_parsed,
2794     domdoc_get_namespaceURI,
2795     domdoc_get_prefix,
2796     domdoc_get_baseName,
2797     domdoc_transformNodeToObject,
2798     domdoc_get_doctype,
2799     domdoc_get_implementation,
2800     domdoc_get_documentElement,
2801     domdoc_put_documentElement,
2802     domdoc_createElement,
2803     domdoc_createDocumentFragment,
2804     domdoc_createTextNode,
2805     domdoc_createComment,
2806     domdoc_createCDATASection,
2807     domdoc_createProcessingInstruction,
2808     domdoc_createAttribute,
2809     domdoc_createEntityReference,
2810     domdoc_getElementsByTagName,
2811     domdoc_createNode,
2812     domdoc_nodeFromID,
2813     domdoc_load,
2814     domdoc_get_readyState,
2815     domdoc_get_parseError,
2816     domdoc_get_url,
2817     domdoc_get_async,
2818     domdoc_put_async,
2819     domdoc_abort,
2820     domdoc_loadXML,
2821     domdoc_save,
2822     domdoc_get_validateOnParse,
2823     domdoc_put_validateOnParse,
2824     domdoc_get_resolveExternals,
2825     domdoc_put_resolveExternals,
2826     domdoc_get_preserveWhiteSpace,
2827     domdoc_put_preserveWhiteSpace,
2828     domdoc_put_onReadyStateChange,
2829     domdoc_put_onDataAvailable,
2830     domdoc_put_onTransformNode,
2831     domdoc_get_namespaces,
2832     domdoc_get_schemas,
2833     domdoc_putref_schemas,
2834     domdoc_validate,
2835     domdoc_setProperty,
2836     domdoc_getProperty,
2837     domdoc_validateNode,
2838     domdoc_importNode
2839 };
2840
2841 /* IConnectionPointContainer */
2842 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
2843                                                               REFIID riid, void **ppv)
2844 {
2845     domdoc *This = impl_from_IConnectionPointContainer(iface);
2846     return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)This, riid, ppv);
2847 }
2848
2849 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
2850 {
2851     domdoc *This = impl_from_IConnectionPointContainer(iface);
2852     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)This);
2853 }
2854
2855 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
2856 {
2857     domdoc *This = impl_from_IConnectionPointContainer(iface);
2858     return IXMLDOMDocument3_Release((IXMLDOMDocument3*)This);
2859 }
2860
2861 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
2862         IEnumConnectionPoints **ppEnum)
2863 {
2864     domdoc *This = impl_from_IConnectionPointContainer(iface);
2865     FIXME("(%p)->(%p): stub\n", This, ppEnum);
2866     return E_NOTIMPL;
2867 }
2868
2869 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
2870         REFIID riid, IConnectionPoint **cp)
2871 {
2872     domdoc *This = impl_from_IConnectionPointContainer(iface);
2873     ConnectionPoint *iter;
2874
2875     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
2876
2877     *cp = NULL;
2878
2879     for(iter = This->cp_list; iter; iter = iter->next)
2880     {
2881         if (IsEqualGUID(iter->iid, riid))
2882             *cp = (IConnectionPoint*)&iter->lpVtblConnectionPoint;
2883     }
2884
2885     if (*cp)
2886     {
2887         IConnectionPoint_AddRef(*cp);
2888         return S_OK;
2889     }
2890
2891     FIXME("unsupported riid %s\n", debugstr_guid(riid));
2892     return CONNECT_E_NOCONNECTION;
2893
2894 }
2895
2896 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
2897 {
2898     ConnectionPointContainer_QueryInterface,
2899     ConnectionPointContainer_AddRef,
2900     ConnectionPointContainer_Release,
2901     ConnectionPointContainer_EnumConnectionPoints,
2902     ConnectionPointContainer_FindConnectionPoint
2903 };
2904
2905 /* IConnectionPoint */
2906 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
2907                                                      REFIID riid, void **ppv)
2908 {
2909     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
2910
2911     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
2912
2913     *ppv = NULL;
2914
2915     if (IsEqualGUID(&IID_IUnknown, riid) ||
2916         IsEqualGUID(&IID_IConnectionPoint, riid))
2917     {
2918         *ppv = iface;
2919     }
2920
2921     if (*ppv)
2922     {
2923         IConnectionPoint_AddRef(iface);
2924         return S_OK;
2925     }
2926
2927     WARN("Unsupported interface %s\n", debugstr_guid(riid));
2928     return E_NOINTERFACE;
2929 }
2930
2931 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
2932 {
2933     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
2934     return IConnectionPointContainer_AddRef(This->container);
2935 }
2936
2937 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
2938 {
2939     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
2940     return IConnectionPointContainer_Release(This->container);
2941 }
2942
2943 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
2944 {
2945     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
2946
2947     TRACE("(%p)->(%p)\n", This, iid);
2948
2949     if (!iid) return E_POINTER;
2950
2951     *iid = *This->iid;
2952     return S_OK;
2953 }
2954
2955 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
2956         IConnectionPointContainer **container)
2957 {
2958     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
2959
2960     TRACE("(%p)->(%p)\n", This, container);
2961
2962     if (!container) return E_POINTER;
2963
2964     *container = This->container;
2965     IConnectionPointContainer_AddRef(*container);
2966     return S_OK;
2967 }
2968
2969 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
2970                                              DWORD *pdwCookie)
2971 {
2972     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
2973     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
2974     return E_NOTIMPL;
2975 }
2976
2977 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
2978 {
2979     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
2980
2981     TRACE("(%p)->(%d)\n", This, cookie);
2982
2983     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
2984         return CONNECT_E_NOCONNECTION;
2985
2986     IUnknown_Release(This->sinks[cookie-1].unk);
2987     This->sinks[cookie-1].unk = NULL;
2988
2989     return S_OK;
2990 }
2991
2992 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
2993                                                       IEnumConnections **ppEnum)
2994 {
2995     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
2996     FIXME("(%p)->(%p): stub\n", This, ppEnum);
2997     return E_NOTIMPL;
2998 }
2999
3000 static const IConnectionPointVtbl ConnectionPointVtbl =
3001 {
3002     ConnectionPoint_QueryInterface,
3003     ConnectionPoint_AddRef,
3004     ConnectionPoint_Release,
3005     ConnectionPoint_GetConnectionInterface,
3006     ConnectionPoint_GetConnectionPointContainer,
3007     ConnectionPoint_Advise,
3008     ConnectionPoint_Unadvise,
3009     ConnectionPoint_EnumConnections
3010 };
3011
3012 void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3013 {
3014     cp->lpVtblConnectionPoint = &ConnectionPointVtbl;
3015     cp->doc = doc;
3016     cp->iid = riid;
3017     cp->sinks = NULL;
3018     cp->sinks_size = 0;
3019
3020     cp->next = doc->cp_list;
3021     doc->cp_list = cp;
3022
3023     cp->container = (IConnectionPointContainer*)&doc->lpVtblConnectionPointContainer;
3024 }
3025
3026 /* domdoc implementation of IObjectWithSite */
3027 static HRESULT WINAPI
3028 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3029 {
3030     domdoc *This = impl_from_IObjectWithSite(iface);
3031     return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppvObject );
3032 }
3033
3034 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3035 {
3036     domdoc *This = impl_from_IObjectWithSite(iface);
3037     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3038 }
3039
3040 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3041 {
3042     domdoc *This = impl_from_IObjectWithSite(iface);
3043     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3044 }
3045
3046 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3047 {
3048     domdoc *This = impl_from_IObjectWithSite(iface);
3049
3050     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3051
3052     if ( !This->site )
3053         return E_FAIL;
3054
3055     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3056 }
3057
3058 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3059 {
3060     domdoc *This = impl_from_IObjectWithSite(iface);
3061
3062     TRACE("(%p)->(%p)\n", iface, punk);
3063
3064     if(!punk)
3065     {
3066         if(This->site)
3067         {
3068             IUnknown_Release( This->site );
3069             This->site = NULL;
3070         }
3071
3072         return S_OK;
3073     }
3074
3075     IUnknown_AddRef( punk );
3076
3077     if(This->site)
3078         IUnknown_Release( This->site );
3079
3080     This->site = punk;
3081
3082     return S_OK;
3083 }
3084
3085 static const IObjectWithSiteVtbl domdocObjectSite =
3086 {
3087     domdoc_ObjectWithSite_QueryInterface,
3088     domdoc_ObjectWithSite_AddRef,
3089     domdoc_ObjectWithSite_Release,
3090     domdoc_ObjectWithSite_SetSite,
3091     domdoc_ObjectWithSite_GetSite
3092 };
3093
3094 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3095 {
3096     domdoc *This = impl_from_IObjectSafety(iface);
3097     return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppv );
3098 }
3099
3100 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3101 {
3102     domdoc *This = impl_from_IObjectSafety(iface);
3103     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3104 }
3105
3106 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3107 {
3108     domdoc *This = impl_from_IObjectSafety(iface);
3109     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3110 }
3111
3112 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3113
3114 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3115         DWORD *supported, DWORD *enabled)
3116 {
3117     domdoc *This = impl_from_IObjectSafety(iface);
3118
3119     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3120
3121     if(!supported || !enabled) return E_POINTER;
3122
3123     *supported = SAFETY_SUPPORTED_OPTIONS;
3124     *enabled = This->safeopt;
3125
3126     return S_OK;
3127 }
3128
3129 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3130         DWORD mask, DWORD enabled)
3131 {
3132     domdoc *This = impl_from_IObjectSafety(iface);
3133     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3134
3135     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3136         return E_FAIL;
3137
3138     This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3139     return S_OK;
3140 }
3141
3142 #undef SAFETY_SUPPORTED_OPTIONS
3143
3144 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3145     domdoc_Safety_QueryInterface,
3146     domdoc_Safety_AddRef,
3147     domdoc_Safety_Release,
3148     domdoc_Safety_GetInterfaceSafetyOptions,
3149     domdoc_Safety_SetInterfaceSafetyOptions
3150 };
3151
3152 static const tid_t domdoc_iface_tids[] = {
3153     IXMLDOMNode_tid,
3154     IXMLDOMDocument_tid,
3155     IXMLDOMDocument2_tid,
3156     0
3157 };
3158 static dispex_static_data_t domdoc_dispex = {
3159     NULL,
3160     IXMLDOMDocument2_tid,
3161     NULL,
3162     domdoc_iface_tids
3163 };
3164
3165 HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3166 {
3167     domdoc *doc;
3168
3169     doc = heap_alloc( sizeof (*doc) );
3170     if( !doc )
3171         return E_OUTOFMEMORY;
3172
3173     doc->lpVtbl = &domdoc_vtbl;
3174     doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
3175     doc->lpvtblIObjectWithSite = &domdocObjectSite;
3176     doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
3177     doc->lpvtblISupportErrorInfo = &support_error_vtbl;
3178     doc->lpVtblConnectionPointContainer = &ConnectionPointContainerVtbl;
3179     doc->ref = 1;
3180     doc->async = VARIANT_TRUE;
3181     doc->validating = 0;
3182     doc->resolving = 0;
3183     doc->preserving = 0;
3184     doc->properties = properties_from_xmlDocPtr(xmldoc);
3185     doc->error = S_OK;
3186     doc->schema = NULL;
3187     doc->stream = NULL;
3188     doc->site = NULL;
3189     doc->safeopt = 0;
3190     doc->bsc = NULL;
3191     doc->cp_list = NULL;
3192
3193     /* events connection points */
3194     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3195     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3196     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3197
3198     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->lpVtbl, &domdoc_dispex);
3199
3200     *document = (IXMLDOMDocument3*)&doc->lpVtbl;
3201
3202     TRACE("returning iface %p\n", *document);
3203     return S_OK;
3204 }
3205
3206 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3207 {
3208     xmlDocPtr xmldoc;
3209     HRESULT hr;
3210
3211     TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3212
3213     xmldoc = xmlNewDoc(NULL);
3214     if(!xmldoc)
3215         return E_OUTOFMEMORY;
3216
3217     xmldoc->_private = create_priv();
3218     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3219
3220     hr = DOMDocument_create_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3221     if(FAILED(hr))
3222     {
3223         free_properties(properties_from_xmlDocPtr(xmldoc));
3224         heap_free(xmldoc->_private);
3225         xmlFreeDoc(xmldoc);
3226         return hr;
3227     }
3228
3229     return hr;
3230 }
3231
3232 IUnknown* create_domdoc( xmlNodePtr document )
3233 {
3234     void* pObj = NULL;
3235     HRESULT hr;
3236
3237     TRACE("(%p)\n", document);
3238
3239     hr = DOMDocument_create_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3240     if (FAILED(hr))
3241         return NULL;
3242
3243     return pObj;
3244 }
3245
3246 #else
3247
3248 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3249 {
3250     MESSAGE("This program tried to use a DOMDocument object, but\n"
3251             "libxml2 support was not present at compile time.\n");
3252     return E_NOTIMPL;
3253 }
3254
3255 #endif