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