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