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