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