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