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