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