b6cdfc760b8f2f3be1026ccc60a992323afaac03
[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 outputObject)
1490 {
1491 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1492 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1493 return E_NOTIMPL;
1494 }
1495
1496
1497 static HRESULT WINAPI domdoc_get_doctype(
1498 IXMLDOMDocument3 *iface,
1499 IXMLDOMDocumentType** doctype )
1500 {
1501 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1502 IXMLDOMNode *node;
1503 xmlDtdPtr dtd;
1504 HRESULT hr;
1505
1506 TRACE("(%p)->(%p)\n", This, doctype);
1507
1508 if (!doctype) return E_INVALIDARG;
1509
1510 *doctype = NULL;
1511
1512 dtd = xmlGetIntSubset(get_doc(This));
1513 if (!dtd) return S_FALSE;
1514
1515 node = create_node((xmlNodePtr)dtd);
1516 if (!node) return S_FALSE;
1517
1518 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1519 IXMLDOMNode_Release(node);
1520
1521 return hr;
1522 }
1523
1524
1525 static HRESULT WINAPI domdoc_get_implementation(
1526 IXMLDOMDocument3 *iface,
1527 IXMLDOMImplementation** impl )
1528 {
1529 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1530
1531 TRACE("(%p)->(%p)\n", This, impl);
1532
1533 if(!impl)
1534 return E_INVALIDARG;
1535
1536 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1537
1538 return S_OK;
1539 }
1540
1541 static HRESULT WINAPI domdoc_get_documentElement(
1542 IXMLDOMDocument3 *iface,
1543 IXMLDOMElement** DOMElement )
1544 {
1545 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1546 IXMLDOMNode *element_node;
1547 xmlNodePtr root;
1548 HRESULT hr;
1549
1550 TRACE("(%p)->(%p)\n", This, DOMElement);
1551
1552 if(!DOMElement)
1553 return E_INVALIDARG;
1554
1555 *DOMElement = NULL;
1556
1557 root = xmlDocGetRootElement( get_doc(This) );
1558 if ( !root )
1559 return S_FALSE;
1560
1561 element_node = create_node( root );
1562 if(!element_node) return S_FALSE;
1563
1564 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1565 IXMLDOMNode_Release(element_node);
1566
1567 return hr;
1568 }
1569
1570
1571 static HRESULT WINAPI domdoc_put_documentElement(
1572 IXMLDOMDocument3 *iface,
1573 IXMLDOMElement* DOMElement )
1574 {
1575 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1576 IXMLDOMNode *elementNode;
1577 xmlNodePtr oldRoot;
1578 xmlDocPtr old_doc;
1579 xmlnode *xmlNode;
1580 int refcount = 0;
1581 HRESULT hr;
1582
1583 TRACE("(%p)->(%p)\n", This, DOMElement);
1584
1585 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1586 if(FAILED(hr))
1587 return hr;
1588
1589 xmlNode = get_node_obj( elementNode );
1590 if(!xmlNode) return E_FAIL;
1591
1592 if(!xmlNode->node->parent)
1593 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1594 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1595
1596 old_doc = xmlNode->node->doc;
1597 if (old_doc != get_doc(This))
1598 refcount = xmlnode_get_inst_cnt(xmlNode);
1599
1600 /* old root is still orphaned by its document, update refcount from new root */
1601 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1602 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1603 if (refcount) xmldoc_release_refs(old_doc, refcount);
1604 IXMLDOMNode_Release( elementNode );
1605
1606 if(oldRoot)
1607 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1608
1609 return S_OK;
1610 }
1611
1612
1613 static HRESULT WINAPI domdoc_createElement(
1614 IXMLDOMDocument3 *iface,
1615 BSTR tagname,
1616 IXMLDOMElement** element )
1617 {
1618 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1619 IXMLDOMNode *node;
1620 VARIANT type;
1621 HRESULT hr;
1622
1623 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1624
1625 if (!element || !tagname) return E_INVALIDARG;
1626
1627 V_VT(&type) = VT_I1;
1628 V_I1(&type) = NODE_ELEMENT;
1629
1630 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1631 if (hr == S_OK)
1632 {
1633 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1634 IXMLDOMNode_Release(node);
1635 }
1636
1637 return hr;
1638 }
1639
1640
1641 static HRESULT WINAPI domdoc_createDocumentFragment(
1642 IXMLDOMDocument3 *iface,
1643 IXMLDOMDocumentFragment** frag )
1644 {
1645 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1646 IXMLDOMNode *node;
1647 VARIANT type;
1648 HRESULT hr;
1649
1650 TRACE("(%p)->(%p)\n", This, frag);
1651
1652 if (!frag) return E_INVALIDARG;
1653
1654 *frag = NULL;
1655
1656 V_VT(&type) = VT_I1;
1657 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1658
1659 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1660 if (hr == S_OK)
1661 {
1662 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1663 IXMLDOMNode_Release(node);
1664 }
1665
1666 return hr;
1667 }
1668
1669
1670 static HRESULT WINAPI domdoc_createTextNode(
1671 IXMLDOMDocument3 *iface,
1672 BSTR data,
1673 IXMLDOMText** text )
1674 {
1675 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1676 IXMLDOMNode *node;
1677 VARIANT type;
1678 HRESULT hr;
1679
1680 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1681
1682 if (!text) return E_INVALIDARG;
1683
1684 *text = NULL;
1685
1686 V_VT(&type) = VT_I1;
1687 V_I1(&type) = NODE_TEXT;
1688
1689 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1690 if (hr == S_OK)
1691 {
1692 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1693 IXMLDOMNode_Release(node);
1694 hr = IXMLDOMText_put_data(*text, data);
1695 }
1696
1697 return hr;
1698 }
1699
1700
1701 static HRESULT WINAPI domdoc_createComment(
1702 IXMLDOMDocument3 *iface,
1703 BSTR data,
1704 IXMLDOMComment** comment )
1705 {
1706 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1707 VARIANT type;
1708 HRESULT hr;
1709 IXMLDOMNode *node;
1710
1711 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1712
1713 if (!comment) return E_INVALIDARG;
1714
1715 *comment = NULL;
1716
1717 V_VT(&type) = VT_I1;
1718 V_I1(&type) = NODE_COMMENT;
1719
1720 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1721 if (hr == S_OK)
1722 {
1723 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1724 IXMLDOMNode_Release(node);
1725 hr = IXMLDOMComment_put_data(*comment, data);
1726 }
1727
1728 return hr;
1729 }
1730
1731
1732 static HRESULT WINAPI domdoc_createCDATASection(
1733 IXMLDOMDocument3 *iface,
1734 BSTR data,
1735 IXMLDOMCDATASection** cdata )
1736 {
1737 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1738 IXMLDOMNode *node;
1739 VARIANT type;
1740 HRESULT hr;
1741
1742 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1743
1744 if (!cdata) return E_INVALIDARG;
1745
1746 *cdata = NULL;
1747
1748 V_VT(&type) = VT_I1;
1749 V_I1(&type) = NODE_CDATA_SECTION;
1750
1751 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1752 if (hr == S_OK)
1753 {
1754 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1755 IXMLDOMNode_Release(node);
1756 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1757 }
1758
1759 return hr;
1760 }
1761
1762
1763 static HRESULT WINAPI domdoc_createProcessingInstruction(
1764 IXMLDOMDocument3 *iface,
1765 BSTR target,
1766 BSTR data,
1767 IXMLDOMProcessingInstruction** pi )
1768 {
1769 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1770 IXMLDOMNode *node;
1771 VARIANT type;
1772 HRESULT hr;
1773
1774 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1775
1776 if (!pi) return E_INVALIDARG;
1777
1778 *pi = NULL;
1779
1780 V_VT(&type) = VT_I1;
1781 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1782
1783 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1784 if (hr == S_OK)
1785 {
1786 xmlnode *node_obj;
1787
1788 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1789 node_obj = get_node_obj(node);
1790 hr = node_set_content(node_obj, data);
1791
1792 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1793 IXMLDOMNode_Release(node);
1794 }
1795
1796 return hr;
1797 }
1798
1799
1800 static HRESULT WINAPI domdoc_createAttribute(
1801 IXMLDOMDocument3 *iface,
1802 BSTR name,
1803 IXMLDOMAttribute** attribute )
1804 {
1805 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1806 IXMLDOMNode *node;
1807 VARIANT type;
1808 HRESULT hr;
1809
1810 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1811
1812 if (!attribute || !name) return E_INVALIDARG;
1813
1814 V_VT(&type) = VT_I1;
1815 V_I1(&type) = NODE_ATTRIBUTE;
1816
1817 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1818 if (hr == S_OK)
1819 {
1820 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1821 IXMLDOMNode_Release(node);
1822 }
1823
1824 return hr;
1825 }
1826
1827
1828 static HRESULT WINAPI domdoc_createEntityReference(
1829 IXMLDOMDocument3 *iface,
1830 BSTR name,
1831 IXMLDOMEntityReference** entityref )
1832 {
1833 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1834 IXMLDOMNode *node;
1835 VARIANT type;
1836 HRESULT hr;
1837
1838 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1839
1840 if (!entityref) return E_INVALIDARG;
1841
1842 *entityref = NULL;
1843
1844 V_VT(&type) = VT_I1;
1845 V_I1(&type) = NODE_ENTITY_REFERENCE;
1846
1847 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1848 if (hr == S_OK)
1849 {
1850 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1851 IXMLDOMNode_Release(node);
1852 }
1853
1854 return hr;
1855 }
1856
1857 xmlChar* tagName_to_XPath(const BSTR tagName)
1858 {
1859 xmlChar *query, *tmp;
1860 static const xmlChar everything[] = "/descendant::node()";
1861 static const xmlChar mod_pre[] = "*[local-name()='";
1862 static const xmlChar mod_post[] = "']";
1863 static const xmlChar prefix[] = "descendant::";
1864 const WCHAR *tokBegin, *tokEnd;
1865 int len;
1866
1867 /* Special case - empty tagname - means select all nodes,
1868 except document itself. */
1869 if (!*tagName)
1870 return xmlStrdup(everything);
1871
1872 query = xmlStrdup(prefix);
1873
1874 tokBegin = tagName;
1875 while (tokBegin && *tokBegin)
1876 {
1877 switch (*tokBegin)
1878 {
1879 case '/':
1880 query = xmlStrcat(query, BAD_CAST "/");
1881 ++tokBegin;
1882 break;
1883 case '*':
1884 query = xmlStrcat(query, BAD_CAST "*");
1885 ++tokBegin;
1886 break;
1887 default:
1888 query = xmlStrcat(query, mod_pre);
1889 tokEnd = tokBegin;
1890 while (*tokEnd && *tokEnd != '/')
1891 ++tokEnd;
1892 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1893 tmp = xmlMalloc(len);
1894 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1895 query = xmlStrncat(query, tmp, len);
1896 xmlFree(tmp);
1897 tokBegin = tokEnd;
1898 query = xmlStrcat(query, mod_post);
1899 }
1900 }
1901
1902 return query;
1903 }
1904
1905 static HRESULT WINAPI domdoc_getElementsByTagName(
1906 IXMLDOMDocument3 *iface,
1907 BSTR tagName,
1908 IXMLDOMNodeList** resultList )
1909 {
1910 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1911 xmlChar *query;
1912 HRESULT hr;
1913 BOOL XPath;
1914
1915 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1916
1917 if (!tagName || !resultList) return E_INVALIDARG;
1918
1919 XPath = This->properties->XPath;
1920 This->properties->XPath = TRUE;
1921 query = tagName_to_XPath(tagName);
1922 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1923 xmlFree(query);
1924 This->properties->XPath = XPath;
1925
1926 return hr;
1927 }
1928
1929 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1930 {
1931 VARIANT tmp;
1932 HRESULT hr;
1933
1934 VariantInit(&tmp);
1935 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1936 if(FAILED(hr))
1937 return E_INVALIDARG;
1938
1939 *type = V_I4(&tmp);
1940
1941 return S_OK;
1942 }
1943
1944 static HRESULT WINAPI domdoc_createNode(
1945 IXMLDOMDocument3 *iface,
1946 VARIANT Type,
1947 BSTR name,
1948 BSTR namespaceURI,
1949 IXMLDOMNode** node )
1950 {
1951 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1952 DOMNodeType node_type;
1953 xmlNodePtr xmlnode;
1954 xmlChar *xml_name, *href;
1955 HRESULT hr;
1956
1957 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1958
1959 if(!node) return E_INVALIDARG;
1960
1961 hr = get_node_type(Type, &node_type);
1962 if(FAILED(hr)) return hr;
1963
1964 TRACE("node_type %d\n", node_type);
1965
1966 /* exit earlier for types that need name */
1967 switch(node_type)
1968 {
1969 case NODE_ELEMENT:
1970 case NODE_ATTRIBUTE:
1971 case NODE_ENTITY_REFERENCE:
1972 case NODE_PROCESSING_INSTRUCTION:
1973 if (!name || *name == 0) return E_FAIL;
1974 break;
1975 default:
1976 break;
1977 }
1978
1979 xml_name = xmlchar_from_wchar(name);
1980 /* prevent empty href from being allocated */
1981 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1982
1983 switch(node_type)
1984 {
1985 case NODE_ELEMENT:
1986 {
1987 xmlChar *local, *prefix;
1988
1989 local = xmlSplitQName2(xml_name, &prefix);
1990
1991 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1992
1993 /* allow creating the default namespace xmlns= */
1994 if (local || (href && *href))
1995 {
1996 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1997 xmlSetNs(xmlnode, ns);
1998 }
1999
2000 xmlFree(local);
2001 xmlFree(prefix);
2002
2003 break;
2004 }
2005 case NODE_ATTRIBUTE:
2006 {
2007 xmlChar *local, *prefix;
2008
2009 local = xmlSplitQName2(xml_name, &prefix);
2010
2011 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2012
2013 if (local || (href && *href))
2014 {
2015 /* we need a floating namespace here, it can't be created linked to attribute from
2016 a start */
2017 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2018 xmlSetNs(xmlnode, ns);
2019 }
2020
2021 xmlFree(local);
2022 xmlFree(prefix);
2023
2024 break;
2025 }
2026 case NODE_TEXT:
2027 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2028 break;
2029 case NODE_CDATA_SECTION:
2030 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2031 break;
2032 case NODE_ENTITY_REFERENCE:
2033 xmlnode = xmlNewReference(get_doc(This), xml_name);
2034 break;
2035 case NODE_PROCESSING_INSTRUCTION:
2036 #ifdef HAVE_XMLNEWDOCPI
2037 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2038 #else
2039 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2040 xmlnode = NULL;
2041 #endif
2042 break;
2043 case NODE_COMMENT:
2044 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2045 break;
2046 case NODE_DOCUMENT_FRAGMENT:
2047 xmlnode = xmlNewDocFragment(get_doc(This));
2048 break;
2049 /* unsupported types */
2050 case NODE_DOCUMENT:
2051 case NODE_DOCUMENT_TYPE:
2052 case NODE_ENTITY:
2053 case NODE_NOTATION:
2054 heap_free(xml_name);
2055 return E_INVALIDARG;
2056 default:
2057 FIXME("unhandled node type %d\n", node_type);
2058 xmlnode = NULL;
2059 break;
2060 }
2061
2062 *node = create_node(xmlnode);
2063 heap_free(xml_name);
2064 heap_free(href);
2065
2066 if(*node)
2067 {
2068 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2069 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2070 return S_OK;
2071 }
2072
2073 return E_FAIL;
2074 }
2075
2076 static HRESULT WINAPI domdoc_nodeFromID(
2077 IXMLDOMDocument3 *iface,
2078 BSTR idString,
2079 IXMLDOMNode** node )
2080 {
2081 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2082 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2083 return E_NOTIMPL;
2084 }
2085
2086 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2087 {
2088 domdoc *This = obj;
2089 xmlDocPtr xmldoc;
2090
2091 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2092 if(xmldoc) {
2093 xmldoc->_private = create_priv();
2094 return attach_xmldoc(This, xmldoc);
2095 }
2096
2097 return E_FAIL;
2098 }
2099
2100 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2101 {
2102 bsc_t *bsc;
2103 HRESULT hr;
2104
2105 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2106 if(FAILED(hr))
2107 return hr;
2108
2109 return detach_bsc(bsc);
2110 }
2111
2112 static HRESULT WINAPI domdoc_load(
2113 IXMLDOMDocument3 *iface,
2114 VARIANT source,
2115 VARIANT_BOOL* isSuccessful )
2116 {
2117 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2118 LPWSTR filename = NULL;
2119 HRESULT hr = S_FALSE;
2120 xmlDocPtr xmldoc;
2121
2122 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2123
2124 if (!isSuccessful)
2125 return E_POINTER;
2126 *isSuccessful = VARIANT_FALSE;
2127
2128 assert( &This->node );
2129
2130 switch( V_VT(&source) )
2131 {
2132 case VT_BSTR:
2133 filename = V_BSTR(&source);
2134 break;
2135 case VT_BSTR|VT_BYREF:
2136 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2137 filename = *V_BSTRREF(&source);
2138 break;
2139 case VT_ARRAY|VT_UI1:
2140 {
2141 SAFEARRAY *psa = V_ARRAY(&source);
2142 char *str;
2143 LONG len;
2144 UINT dim = SafeArrayGetDim(psa);
2145
2146 switch (dim)
2147 {
2148 case 0:
2149 ERR("SAFEARRAY == NULL\n");
2150 hr = This->error = E_INVALIDARG;
2151 break;
2152 case 1:
2153 /* Only takes UTF-8 strings.
2154 * NOT NULL-terminated. */
2155 hr = SafeArrayAccessData(psa, (void**)&str);
2156 if (FAILED(hr))
2157 {
2158 This->error = hr;
2159 WARN("failed to access array data, 0x%08x\n", hr);
2160 break;
2161 }
2162 SafeArrayGetUBound(psa, 1, &len);
2163
2164 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2165 {
2166 hr = This->error = S_OK;
2167 *isSuccessful = VARIANT_TRUE;
2168 TRACE("parsed document %p\n", xmldoc);
2169 }
2170 else
2171 {
2172 This->error = E_FAIL;
2173 TRACE("failed to parse document\n");
2174 }
2175
2176 SafeArrayUnaccessData(psa);
2177
2178 if(xmldoc)
2179 {
2180 xmldoc->_private = create_priv();
2181 return attach_xmldoc(This, xmldoc);
2182 }
2183 break;
2184 default:
2185 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2186 hr = This->error = E_NOTIMPL;
2187 }
2188 }
2189 break;
2190 case VT_UNKNOWN:
2191 {
2192 ISequentialStream *stream = NULL;
2193 IXMLDOMDocument3 *newdoc = NULL;
2194
2195 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2196
2197 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2198 if(hr == S_OK)
2199 {
2200 if(newdoc)
2201 {
2202 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2203
2204 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2205 xmldoc->_private = create_priv();
2206 hr = attach_xmldoc(This, xmldoc);
2207
2208 if(SUCCEEDED(hr))
2209 *isSuccessful = VARIANT_TRUE;
2210
2211 return hr;
2212 }
2213 }
2214
2215 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2216 if (FAILED(hr))
2217 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2218
2219 if (hr == S_OK)
2220 {
2221 hr = domdoc_load_from_stream(This, stream);
2222 if (hr == S_OK)
2223 *isSuccessful = VARIANT_TRUE;
2224 ISequentialStream_Release(stream);
2225 return hr;
2226 }
2227
2228 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2229 break;
2230 }
2231 default:
2232 FIXME("VT type not supported (%d)\n", V_VT(&source));
2233 }
2234
2235 if ( filename )
2236 {
2237 IMoniker *mon;
2238
2239 CoTaskMemFree(This->properties->url);
2240 This->properties->url = NULL;
2241
2242 hr = create_moniker_from_url( filename, &mon);
2243 if ( SUCCEEDED(hr) )
2244 {
2245 hr = domdoc_load_moniker( This, mon );
2246 if (hr == S_OK)
2247 IMoniker_GetDisplayName(mon, NULL, NULL, &This->properties->url);
2248 IMoniker_Release(mon);
2249 }
2250
2251 if ( FAILED(hr) )
2252 This->error = E_FAIL;
2253 else
2254 {
2255 hr = This->error = S_OK;
2256 *isSuccessful = VARIANT_TRUE;
2257 }
2258 }
2259
2260 if(!filename || FAILED(hr)) {
2261 xmldoc = xmlNewDoc(NULL);
2262 xmldoc->_private = create_priv();
2263 hr = attach_xmldoc(This, xmldoc);
2264 if(SUCCEEDED(hr))
2265 hr = S_FALSE;
2266 }
2267
2268 TRACE("ret (%d)\n", hr);
2269
2270 return hr;
2271 }
2272
2273
2274 static HRESULT WINAPI domdoc_get_readyState(
2275 IXMLDOMDocument3 *iface,
2276 LONG *value )
2277 {
2278 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2279 FIXME("stub! (%p)->(%p)\n", This, value);
2280
2281 if (!value)
2282 return E_INVALIDARG;
2283
2284 *value = READYSTATE_COMPLETE;
2285 return S_OK;
2286 }
2287
2288
2289 static HRESULT WINAPI domdoc_get_parseError(
2290 IXMLDOMDocument3 *iface,
2291 IXMLDOMParseError** errorObj )
2292 {
2293 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2294 static const WCHAR err[] = {'e','r','r','o','r',0};
2295 BSTR error_string = NULL;
2296
2297 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2298
2299 if(This->error)
2300 error_string = SysAllocString(err);
2301
2302 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2303 if(!*errorObj) return E_OUTOFMEMORY;
2304 return S_OK;
2305 }
2306
2307
2308 static HRESULT WINAPI domdoc_get_url(
2309 IXMLDOMDocument3 *iface,
2310 BSTR* url )
2311 {
2312 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2313
2314 TRACE("(%p)->(%p)\n", This, url);
2315
2316 if (!url)
2317 return E_INVALIDARG;
2318
2319 if (This->properties->url)
2320 {
2321 *url = SysAllocString(This->properties->url);
2322 if (!*url)
2323 return E_OUTOFMEMORY;
2324
2325 return S_OK;
2326 }
2327 else
2328 return return_null_bstr(url);
2329 }
2330
2331
2332 static HRESULT WINAPI domdoc_get_async(
2333 IXMLDOMDocument3 *iface,
2334 VARIANT_BOOL* isAsync )
2335 {
2336 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2337
2338 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2339 *isAsync = This->async;
2340 return S_OK;
2341 }
2342
2343
2344 static HRESULT WINAPI domdoc_put_async(
2345 IXMLDOMDocument3 *iface,
2346 VARIANT_BOOL isAsync )
2347 {
2348 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2349
2350 TRACE("(%p)->(%d)\n", This, isAsync);
2351 This->async = isAsync;
2352 return S_OK;
2353 }
2354
2355
2356 static HRESULT WINAPI domdoc_abort(
2357 IXMLDOMDocument3 *iface )
2358 {
2359 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2360 FIXME("%p\n", This);
2361 return E_NOTIMPL;
2362 }
2363
2364 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2365 static HRESULT WINAPI domdoc_loadXML(
2366 IXMLDOMDocument3 *iface,
2367 BSTR data,
2368 VARIANT_BOOL* isSuccessful )
2369 {
2370 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2371 xmlDocPtr xmldoc = NULL;
2372 HRESULT hr = S_FALSE, hr2;
2373
2374 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2375
2376 assert ( &This->node );
2377
2378 if ( isSuccessful )
2379 {
2380 *isSuccessful = VARIANT_FALSE;
2381
2382 if (data)
2383 {
2384 WCHAR *ptr = data;
2385
2386 /* skip leading spaces if needed */
2387 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2388 while (*ptr && isspaceW(*ptr)) ptr++;
2389
2390 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2391 if ( !xmldoc )
2392 {
2393 This->error = E_FAIL;
2394 TRACE("failed to parse document\n");
2395 }
2396 else
2397 {
2398 hr = This->error = S_OK;
2399 *isSuccessful = VARIANT_TRUE;
2400 TRACE("parsed document %p\n", xmldoc);
2401 }
2402 }
2403 }
2404
2405 if(!xmldoc)
2406 xmldoc = xmlNewDoc(NULL);
2407 xmldoc->_private = create_priv();
2408 hr2 = attach_xmldoc(This, xmldoc);
2409 if( FAILED(hr2) )
2410 hr = hr2;
2411
2412 return hr;
2413 }
2414
2415 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2416 {
2417 DWORD written = -1;
2418
2419 if(!WriteFile(ctx, buffer, len, &written, NULL))
2420 {
2421 WARN("write error\n");
2422 return -1;
2423 }
2424 else
2425 return written;
2426 }
2427
2428 static int XMLCALL domdoc_save_closecallback(void *ctx)
2429 {
2430 return CloseHandle(ctx) ? 0 : -1;
2431 }
2432
2433 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2434 {
2435 ULONG written = 0;
2436 HRESULT hr;
2437
2438 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2439 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2440 if (hr != S_OK)
2441 {
2442 WARN("stream write error: 0x%08x\n", hr);
2443 return -1;
2444 }
2445 else
2446 return len;
2447 }
2448
2449 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2450 {
2451 IStream_Release((IStream*)ctx);
2452 return 0;
2453 }
2454
2455 static HRESULT WINAPI domdoc_save(
2456 IXMLDOMDocument3 *iface,
2457 VARIANT destination )
2458 {
2459 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2460 xmlSaveCtxtPtr ctx = NULL;
2461 xmlNodePtr xmldecl;
2462 HRESULT ret = S_OK;
2463
2464 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2465
2466 switch (V_VT(&destination))
2467 {
2468 case VT_UNKNOWN:
2469 {
2470 IUnknown *pUnk = V_UNKNOWN(&destination);
2471 IXMLDOMDocument3 *document;
2472 IStream *stream;
2473
2474 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2475 if(ret == S_OK)
2476 {
2477 VARIANT_BOOL success;
2478 BSTR xml;
2479
2480 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2481 if(ret == S_OK)
2482 {
2483 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2484 SysFreeString(xml);
2485 }
2486
2487 IXMLDOMDocument3_Release(document);
2488 return ret;
2489 }
2490
2491 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2492 if(ret == S_OK)
2493 {
2494 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2495 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2496 domdoc_stream_save_closecallback, stream, NULL, options);
2497
2498 if(!ctx)
2499 {
2500 IStream_Release(stream);
2501 return E_FAIL;
2502 }
2503 }
2504 }
2505 break;
2506
2507 case VT_BSTR:
2508 case VT_BSTR | VT_BYREF:
2509 {
2510 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2511
2512 /* save with file path */
2513 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2514 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2515 if( handle == INVALID_HANDLE_VALUE )
2516 {
2517 WARN("failed to create file\n");
2518 return E_FAIL;
2519 }
2520
2521 /* disable top XML declaration */
2522 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2523 handle, NULL, options);
2524 if (!ctx)
2525 {
2526 CloseHandle(handle);
2527 return E_FAIL;
2528 }
2529 }
2530 break;
2531
2532 default:
2533 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2534 return S_FALSE;
2535 }
2536
2537 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2538 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2539 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2540
2541 /* will release resources through close callback */
2542 xmlSaveClose(ctx);
2543
2544 return ret;
2545 }
2546
2547 static HRESULT WINAPI domdoc_get_validateOnParse(
2548 IXMLDOMDocument3 *iface,
2549 VARIANT_BOOL* isValidating )
2550 {
2551 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2552 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2553 *isValidating = This->validating;
2554 return S_OK;
2555 }
2556
2557
2558 static HRESULT WINAPI domdoc_put_validateOnParse(
2559 IXMLDOMDocument3 *iface,
2560 VARIANT_BOOL isValidating )
2561 {
2562 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2563 TRACE("(%p)->(%d)\n", This, isValidating);
2564 This->validating = isValidating;
2565 return S_OK;
2566 }
2567
2568
2569 static HRESULT WINAPI domdoc_get_resolveExternals(
2570 IXMLDOMDocument3 *iface,
2571 VARIANT_BOOL* isResolving )
2572 {
2573 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2574 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2575 *isResolving = This->resolving;
2576 return S_OK;
2577 }
2578
2579
2580 static HRESULT WINAPI domdoc_put_resolveExternals(
2581 IXMLDOMDocument3 *iface,
2582 VARIANT_BOOL isResolving )
2583 {
2584 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2585 TRACE("(%p)->(%d)\n", This, isResolving);
2586 This->resolving = isResolving;
2587 return S_OK;
2588 }
2589
2590
2591 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2592 IXMLDOMDocument3 *iface,
2593 VARIANT_BOOL* isPreserving )
2594 {
2595 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2596 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2597 *isPreserving = This->properties->preserving;
2598 return S_OK;
2599 }
2600
2601
2602 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2603 IXMLDOMDocument3 *iface,
2604 VARIANT_BOOL isPreserving )
2605 {
2606 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2607 TRACE("(%p)->(%d)\n", This, isPreserving);
2608 This->properties->preserving = isPreserving;
2609 return S_OK;
2610 }
2611
2612
2613 static HRESULT WINAPI domdoc_put_onreadystatechange(
2614 IXMLDOMDocument3 *iface,
2615 VARIANT event )
2616 {
2617 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2618
2619 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2620 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2621 }
2622
2623
2624 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2625 {
2626 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2627 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2628 return E_NOTIMPL;
2629 }
2630
2631 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2632 {
2633 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2634 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2635 return E_NOTIMPL;
2636 }
2637
2638 static HRESULT WINAPI domdoc_get_namespaces(
2639 IXMLDOMDocument3* iface,
2640 IXMLDOMSchemaCollection** collection )
2641 {
2642 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2643 HRESULT hr;
2644
2645 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2646
2647 if (!collection) return E_POINTER;
2648
2649 if (!This->namespaces)
2650 {
2651 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2652 if (hr != S_OK) return hr;
2653
2654 hr = cache_from_doc_ns(This->namespaces, &This->node);
2655 if (hr != S_OK)
2656 release_namespaces(This);
2657 }
2658
2659 if (This->namespaces)
2660 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2661 &IID_IXMLDOMSchemaCollection, (void**)collection);
2662
2663 return hr;
2664 }
2665
2666 static HRESULT WINAPI domdoc_get_schemas(
2667 IXMLDOMDocument3* iface,
2668 VARIANT* schema )
2669 {
2670 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2671 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2672 HRESULT hr = S_FALSE;
2673
2674 TRACE("(%p)->(%p)\n", This, schema);
2675
2676 V_VT(schema) = VT_NULL;
2677 /* just to reset pointer part, cause that's what application is expected to use */
2678 V_DISPATCH(schema) = NULL;
2679
2680 if(cur_schema)
2681 {
2682 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2683 if(SUCCEEDED(hr))
2684 V_VT(schema) = VT_DISPATCH;
2685 }
2686 return hr;
2687 }
2688
2689 static HRESULT WINAPI domdoc_putref_schemas(
2690 IXMLDOMDocument3* iface,
2691 VARIANT schema)
2692 {
2693 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2694 HRESULT hr = E_FAIL;
2695 IXMLDOMSchemaCollection2* new_schema = NULL;
2696
2697 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2698 switch(V_VT(&schema))
2699 {
2700 case VT_UNKNOWN:
2701 if (V_UNKNOWN(&schema))
2702 {
2703 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2704 break;
2705 }
2706 /* fallthrough */
2707 case VT_DISPATCH:
2708 if (V_DISPATCH(&schema))
2709 {
2710 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2711 break;
2712 }
2713 /* fallthrough */
2714 case VT_NULL:
2715 case VT_EMPTY:
2716 hr = S_OK;
2717 break;
2718
2719 default:
2720 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2721 }
2722
2723 if(SUCCEEDED(hr))
2724 {
2725 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2726 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2727 }
2728
2729 return hr;
2730 }
2731
2732 static inline BOOL is_wellformed(xmlDocPtr doc)
2733 {
2734 #ifdef HAVE_XMLDOC_PROPERTIES
2735 return doc->properties & XML_DOC_WELLFORMED;
2736 #else
2737 /* Not a full check, but catches the worst violations */
2738 xmlNodePtr child;
2739 int root = 0;
2740
2741 for (child = doc->children; child != NULL; child = child->next)
2742 {
2743 switch (child->type)
2744 {
2745 case XML_ELEMENT_NODE:
2746 if (++root > 1)
2747 return FALSE;
2748 break;
2749 case XML_TEXT_NODE:
2750 case XML_CDATA_SECTION_NODE:
2751 return FALSE;
2752 break;
2753 default:
2754 break;
2755 }
2756 }
2757
2758 return root == 1;
2759 #endif
2760 }
2761
2762 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2763 {
2764 va_list ap;
2765 va_start(ap, msg);
2766 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2767 va_end(ap);
2768 }
2769
2770 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2771 {
2772 va_list ap;
2773 va_start(ap, msg);
2774 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2775 va_end(ap);
2776 }
2777
2778 static HRESULT WINAPI domdoc_validateNode(
2779 IXMLDOMDocument3* iface,
2780 IXMLDOMNode* node,
2781 IXMLDOMParseError** err)
2782 {
2783 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2784 LONG state, err_code = 0;
2785 HRESULT hr = S_OK;
2786 int validated = 0;
2787
2788 TRACE("(%p)->(%p, %p)\n", This, node, err);
2789 IXMLDOMDocument3_get_readyState(iface, &state);
2790 if (state != READYSTATE_COMPLETE)
2791 {
2792 if (err)
2793 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2794 return E_PENDING;
2795 }
2796
2797 if (!node)
2798 {
2799 if (err)
2800 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2801 return E_POINTER;
2802 }
2803
2804 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2805 {
2806 if (err)
2807 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2808 return E_FAIL;
2809 }
2810
2811 if (!is_wellformed(get_doc(This)))
2812 {
2813 ERR("doc not well-formed\n");
2814 if (err)
2815 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2816 return S_FALSE;
2817 }
2818
2819 /* DTD validation */
2820 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2821 {
2822 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2823 vctx->error = validate_error;
2824 vctx->warning = validate_warning;
2825 ++validated;
2826
2827 if (!((node == (IXMLDOMNode*)iface)?
2828 xmlValidateDocument(vctx, get_doc(This)) :
2829 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2830 {
2831 /* TODO: get a real error code here */
2832 TRACE("DTD validation failed\n");
2833 err_code = E_XML_INVALID;
2834 hr = S_FALSE;
2835 }
2836 xmlFreeValidCtxt(vctx);
2837 }
2838
2839 /* Schema validation */
2840 if (hr == S_OK && This->properties->schemaCache != NULL)
2841 {
2842
2843 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2844 if (SUCCEEDED(hr))
2845 {
2846 ++validated;
2847 /* TODO: get a real error code here */
2848 if (hr == S_OK)
2849 {
2850 TRACE("schema validation succeeded\n");
2851 }
2852 else
2853 {
2854 ERR("schema validation failed\n");
2855 err_code = E_XML_INVALID;
2856 }
2857 }
2858 else
2859 {
2860 /* not really OK, just didn't find a schema for the ns */
2861 hr = S_OK;
2862 }
2863 }
2864
2865 if (!validated)
2866 {
2867 ERR("no DTD or schema found\n");
2868 err_code = E_XML_NODTD;
2869 hr = S_FALSE;
2870 }
2871
2872 if (err)
2873 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2874
2875 return hr;
2876 }
2877
2878 static HRESULT WINAPI domdoc_validate(
2879 IXMLDOMDocument3* iface,
2880 IXMLDOMParseError** err)
2881 {
2882 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2883 TRACE("(%p)->(%p)\n", This, err);
2884 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2885 }
2886
2887 static HRESULT WINAPI domdoc_setProperty(
2888 IXMLDOMDocument3* iface,
2889 BSTR p,
2890 VARIANT value)
2891 {
2892 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2893
2894 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2895
2896 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2897 {
2898 VARIANT varStr;
2899 HRESULT hr;
2900 BSTR bstr;
2901
2902 V_VT(&varStr) = VT_EMPTY;
2903 if (V_VT(&value) != VT_BSTR)
2904 {
2905 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2906 return hr;
2907 bstr = V_BSTR(&varStr);
2908 }
2909 else
2910 bstr = V_BSTR(&value);
2911
2912 hr = S_OK;
2913 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2914 This->properties->XPath = TRUE;
2915 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2916 This->properties->XPath = FALSE;
2917 else
2918 hr = E_FAIL;
2919
2920 VariantClear(&varStr);
2921 return hr;
2922 }
2923 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2924 {
2925 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2926 struct list *pNsList;
2927 VARIANT varStr;
2928 HRESULT hr;
2929 BSTR bstr;
2930
2931 V_VT(&varStr) = VT_EMPTY;
2932 if (V_VT(&value) != VT_BSTR)
2933 {
2934 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2935 return hr;
2936 bstr = V_BSTR(&varStr);
2937 }
2938 else
2939 bstr = V_BSTR(&value);
2940
2941 hr = S_OK;
2942
2943 pNsList = &(This->properties->selectNsList);
2944 clear_selectNsList(pNsList);
2945 heap_free(nsStr);
2946 nsStr = xmlchar_from_wchar(bstr);
2947
2948 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2949
2950 This->properties->selectNsStr = nsStr;
2951 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2952 if (bstr && *bstr)
2953 {
2954 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2955 select_ns_entry* ns_entry = NULL;
2956 xmlXPathContextPtr ctx;
2957
2958 ctx = xmlXPathNewContext(This->node.node->doc);
2959 pTokBegin = nsStr;
2960
2961 /* skip leading spaces */
2962 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2963 *pTokBegin == '\t' || *pTokBegin == '\r')
2964 ++pTokBegin;
2965
2966 for (; *pTokBegin; pTokBegin = pTokEnd)
2967 {
2968 if (ns_entry)
2969 memset(ns_entry, 0, sizeof(select_ns_entry));
2970 else
2971 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2972
2973 while (*pTokBegin == ' ')
2974 ++pTokBegin;
2975 pTokEnd = pTokBegin;
2976 while (*pTokEnd != ' ' && *pTokEnd != 0)
2977 ++pTokEnd;
2978
2979 /* so it failed to advance which means we've got some trailing spaces */
2980 if (pTokEnd == pTokBegin) break;
2981
2982 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2983 {
2984 hr = E_FAIL;
2985 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2986 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2987 continue;
2988 }
2989
2990 pTokBegin += 5;
2991 if (*pTokBegin == '=')
2992 {
2993 /*valid for XSLPattern?*/
2994 FIXME("Setting default xmlns not supported - skipping.\n");
2995 continue;
2996 }
2997 else if (*pTokBegin == ':')
2998 {
2999 ns_entry->prefix = ++pTokBegin;
3000 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
3001 ;
3002
3003 if (pTokInner == pTokEnd)
3004 {
3005 hr = E_FAIL;
3006 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3007 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3008 continue;
3009 }
3010
3011 ns_entry->prefix_end = *pTokInner;
3012 *pTokInner = 0;
3013 ++pTokInner;
3014
3015 if (pTokEnd-pTokInner > 1 &&
3016 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3017 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3018 {
3019 ns_entry->href = ++pTokInner;
3020 ns_entry->href_end = *(pTokEnd-1);
3021 *(pTokEnd-1) = 0;
3022 list_add_tail(pNsList, &ns_entry->entry);
3023 /*let libxml figure out if they're valid from here ;)*/
3024 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3025 {
3026 hr = E_FAIL;
3027 }
3028 ns_entry = NULL;
3029 continue;
3030 }
3031 else
3032 {
3033 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3034 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3035 list_add_tail(pNsList, &ns_entry->entry);
3036
3037 ns_entry = NULL;
3038 hr = E_FAIL;
3039 continue;
3040 }
3041 }
3042 else
3043 {
3044 hr = E_FAIL;
3045 continue;
3046 }
3047 }
3048 heap_free(ns_entry);
3049 xmlXPathFreeContext(ctx);
3050 }
3051
3052 VariantClear(&varStr);
3053 return hr;
3054 }
3055 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3056 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3057 lstrcmpiW(p, PropertyResolveExternalsW) == 0 ||
3058 lstrcmpiW(p, PropertyAllowXsltScriptW) == 0 ||
3059 lstrcmpiW(p, PropertyAllowDocumentFunctionW) == 0)
3060 {
3061 /* Ignore */
3062 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3063 return S_OK;
3064 }
3065
3066 FIXME("Unknown property %s\n", debugstr_w(p));
3067 return E_FAIL;
3068 }
3069
3070 static HRESULT WINAPI domdoc_getProperty(
3071 IXMLDOMDocument3* iface,
3072 BSTR p,
3073 VARIANT* var)
3074 {
3075 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3076
3077 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3078
3079 if (!var)
3080 return E_INVALIDARG;
3081
3082 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3083 {
3084 V_VT(var) = VT_BSTR;
3085 V_BSTR(var) = This->properties->XPath ?
3086 SysAllocString(PropValueXPathW) :
3087 SysAllocString(PropValueXSLPatternW);
3088 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3089 }
3090 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3091 {
3092 int lenA, lenW;
3093 BSTR rebuiltStr, cur;
3094 const xmlChar *nsStr;
3095 struct list *pNsList;
3096 select_ns_entry* pNsEntry;
3097
3098 V_VT(var) = VT_BSTR;
3099 nsStr = This->properties->selectNsStr;
3100 pNsList = &This->properties->selectNsList;
3101 lenA = This->properties->selectNsStr_len;
3102 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3103 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3104 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3105 cur = rebuiltStr;
3106 /* this is fine because all of the chars that end tokens are ASCII*/
3107 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3108 {
3109 while (*cur != 0) ++cur;
3110 if (pNsEntry->prefix_end)
3111 {
3112 *cur = pNsEntry->prefix_end;
3113 while (*cur != 0) ++cur;
3114 }
3115
3116 if (pNsEntry->href_end)
3117 {
3118 *cur = pNsEntry->href_end;
3119 }
3120 }
3121 V_BSTR(var) = SysAllocString(rebuiltStr);
3122 heap_free(rebuiltStr);
3123 return S_OK;
3124 }
3125
3126 FIXME("Unknown property %s\n", debugstr_w(p));
3127 return E_FAIL;
3128 }
3129
3130 static HRESULT WINAPI domdoc_importNode(
3131 IXMLDOMDocument3* iface,
3132 IXMLDOMNode* node,
3133 VARIANT_BOOL deep,
3134 IXMLDOMNode** clone)
3135 {
3136 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3137 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3138 return E_NOTIMPL;
3139 }
3140
3141 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3142 {
3143 domdoc_QueryInterface,
3144 domdoc_AddRef,
3145 domdoc_Release,
3146 domdoc_GetTypeInfoCount,
3147 domdoc_GetTypeInfo,
3148 domdoc_GetIDsOfNames,
3149 domdoc_Invoke,
3150 domdoc_get_nodeName,
3151 domdoc_get_nodeValue,
3152 domdoc_put_nodeValue,
3153 domdoc_get_nodeType,
3154 domdoc_get_parentNode,
3155 domdoc_get_childNodes,
3156 domdoc_get_firstChild,
3157 domdoc_get_lastChild,
3158 domdoc_get_previousSibling,
3159 domdoc_get_nextSibling,
3160 domdoc_get_attributes,
3161 domdoc_insertBefore,
3162 domdoc_replaceChild,
3163 domdoc_removeChild,
3164 domdoc_appendChild,
3165 domdoc_hasChildNodes,
3166 domdoc_get_ownerDocument,
3167 domdoc_cloneNode,
3168 domdoc_get_nodeTypeString,
3169 domdoc_get_text,
3170 domdoc_put_text,
3171 domdoc_get_specified,
3172 domdoc_get_definition,
3173 domdoc_get_nodeTypedValue,
3174 domdoc_put_nodeTypedValue,
3175 domdoc_get_dataType,
3176 domdoc_put_dataType,
3177 domdoc_get_xml,
3178 domdoc_transformNode,
3179 domdoc_selectNodes,
3180 domdoc_selectSingleNode,
3181 domdoc_get_parsed,
3182 domdoc_get_namespaceURI,
3183 domdoc_get_prefix,
3184 domdoc_get_baseName,
3185 domdoc_transformNodeToObject,
3186 domdoc_get_doctype,
3187 domdoc_get_implementation,
3188 domdoc_get_documentElement,
3189 domdoc_put_documentElement,
3190 domdoc_createElement,
3191 domdoc_createDocumentFragment,
3192 domdoc_createTextNode,
3193 domdoc_createComment,
3194 domdoc_createCDATASection,
3195 domdoc_createProcessingInstruction,
3196 domdoc_createAttribute,
3197 domdoc_createEntityReference,
3198 domdoc_getElementsByTagName,
3199 domdoc_createNode,
3200 domdoc_nodeFromID,
3201 domdoc_load,
3202 domdoc_get_readyState,
3203 domdoc_get_parseError,
3204 domdoc_get_url,
3205 domdoc_get_async,
3206 domdoc_put_async,
3207 domdoc_abort,
3208 domdoc_loadXML,
3209 domdoc_save,
3210 domdoc_get_validateOnParse,
3211 domdoc_put_validateOnParse,
3212 domdoc_get_resolveExternals,
3213 domdoc_put_resolveExternals,
3214 domdoc_get_preserveWhiteSpace,
3215 domdoc_put_preserveWhiteSpace,
3216 domdoc_put_onreadystatechange,
3217 domdoc_put_onDataAvailable,
3218 domdoc_put_onTransformNode,
3219 domdoc_get_namespaces,
3220 domdoc_get_schemas,
3221 domdoc_putref_schemas,
3222 domdoc_validate,
3223 domdoc_setProperty,
3224 domdoc_getProperty,
3225 domdoc_validateNode,
3226 domdoc_importNode
3227 };
3228
3229 /* IConnectionPointContainer */
3230 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3231 REFIID riid, void **ppv)
3232 {
3233 domdoc *This = impl_from_IConnectionPointContainer(iface);
3234 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3235 }
3236
3237 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3238 {
3239 domdoc *This = impl_from_IConnectionPointContainer(iface);
3240 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3241 }
3242
3243 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3244 {
3245 domdoc *This = impl_from_IConnectionPointContainer(iface);
3246 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3247 }
3248
3249 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3250 IEnumConnectionPoints **ppEnum)
3251 {
3252 domdoc *This = impl_from_IConnectionPointContainer(iface);
3253 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3254 return E_NOTIMPL;
3255 }
3256
3257 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3258 REFIID riid, IConnectionPoint **cp)
3259 {
3260 domdoc *This = impl_from_IConnectionPointContainer(iface);
3261 ConnectionPoint *iter;
3262
3263 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3264
3265 *cp = NULL;
3266
3267 for(iter = This->cp_list; iter; iter = iter->next)
3268 {
3269 if (IsEqualGUID(iter->iid, riid))
3270 *cp = &iter->IConnectionPoint_iface;
3271 }
3272
3273 if (*cp)
3274 {
3275 IConnectionPoint_AddRef(*cp);
3276 return S_OK;
3277 }
3278
3279 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3280 return CONNECT_E_NOCONNECTION;
3281
3282 }
3283
3284 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3285 {
3286 ConnectionPointContainer_QueryInterface,
3287 ConnectionPointContainer_AddRef,
3288 ConnectionPointContainer_Release,
3289 ConnectionPointContainer_EnumConnectionPoints,
3290 ConnectionPointContainer_FindConnectionPoint
3291 };
3292
3293 /* IConnectionPoint */
3294 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3295 REFIID riid, void **ppv)
3296 {
3297 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3298
3299 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3300
3301 *ppv = NULL;
3302
3303 if (IsEqualGUID(&IID_IUnknown, riid) ||
3304 IsEqualGUID(&IID_IConnectionPoint, riid))
3305 {
3306 *ppv = iface;
3307 }
3308
3309 if (*ppv)
3310 {
3311 IConnectionPoint_AddRef(iface);
3312 return S_OK;
3313 }
3314
3315 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3316 return E_NOINTERFACE;
3317 }
3318
3319 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3320 {
3321 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3322 return IConnectionPointContainer_AddRef(This->container);
3323 }
3324
3325 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3326 {
3327 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3328 return IConnectionPointContainer_Release(This->container);
3329 }
3330
3331 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3332 {
3333 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3334
3335 TRACE("(%p)->(%p)\n", This, iid);
3336
3337 if (!iid) return E_POINTER;
3338
3339 *iid = *This->iid;
3340 return S_OK;
3341 }
3342
3343 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3344 IConnectionPointContainer **container)
3345 {
3346 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3347
3348 TRACE("(%p)->(%p)\n", This, container);
3349
3350 if (!container) return E_POINTER;
3351
3352 *container = This->container;
3353 IConnectionPointContainer_AddRef(*container);
3354 return S_OK;
3355 }
3356
3357 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3358 DWORD *cookie)
3359 {
3360 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3361 IUnknown *sink;
3362 HRESULT hr;
3363 DWORD i;
3364
3365 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3366
3367 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3368 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3369 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3370 if(FAILED(hr))
3371 return CONNECT_E_CANNOTCONNECT;
3372
3373 if(This->sinks)
3374 {
3375 for (i = 0; i < This->sinks_size; i++)
3376 if (!This->sinks[i].unk)
3377 break;
3378
3379 if (i == This->sinks_size)
3380 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3381 }
3382 else
3383 {
3384 This->sinks = heap_alloc(sizeof(*This->sinks));
3385 This->sinks_size = 1;
3386 i = 0;
3387 }
3388
3389 This->sinks[i].unk = sink;
3390 if (cookie)
3391 *cookie = i+1;
3392
3393 return S_OK;
3394 }
3395
3396 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3397 {
3398 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3399
3400 TRACE("(%p)->(%d)\n", This, cookie);
3401
3402 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3403 return CONNECT_E_NOCONNECTION;
3404
3405 IUnknown_Release(This->sinks[cookie-1].unk);
3406 This->sinks[cookie-1].unk = NULL;
3407
3408 return S_OK;
3409 }
3410
3411 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3412 IEnumConnections **ppEnum)
3413 {
3414 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3415 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3416 return E_NOTIMPL;
3417 }
3418
3419 static const IConnectionPointVtbl ConnectionPointVtbl =
3420 {
3421 ConnectionPoint_QueryInterface,
3422 ConnectionPoint_AddRef,
3423 ConnectionPoint_Release,
3424 ConnectionPoint_GetConnectionInterface,
3425 ConnectionPoint_GetConnectionPointContainer,
3426 ConnectionPoint_Advise,
3427 ConnectionPoint_Unadvise,
3428 ConnectionPoint_EnumConnections
3429 };
3430
3431 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3432 {
3433 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3434 cp->doc = doc;
3435 cp->iid = riid;
3436 cp->sinks = NULL;
3437 cp->sinks_size = 0;
3438
3439 cp->next = doc->cp_list;
3440 doc->cp_list = cp;
3441
3442 cp->container = &doc->IConnectionPointContainer_iface;
3443 }
3444
3445 /* domdoc implementation of IObjectWithSite */
3446 static HRESULT WINAPI
3447 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3448 {
3449 domdoc *This = impl_from_IObjectWithSite(iface);
3450 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3451 }
3452
3453 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3454 {
3455 domdoc *This = impl_from_IObjectWithSite(iface);
3456 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3457 }
3458
3459 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3460 {
3461 domdoc *This = impl_from_IObjectWithSite(iface);
3462 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3463 }
3464
3465 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3466 {
3467 domdoc *This = impl_from_IObjectWithSite(iface);
3468
3469 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3470
3471 if ( !This->site )
3472 return E_FAIL;
3473
3474 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3475 }
3476
3477 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3478 {
3479 domdoc *This = impl_from_IObjectWithSite(iface);
3480
3481 TRACE("(%p)->(%p)\n", iface, punk);
3482
3483 if(!punk)
3484 {
3485 if(This->site)
3486 {
3487 IUnknown_Release( This->site );
3488 This->site = NULL;
3489 }
3490
3491 return S_OK;
3492 }
3493
3494 IUnknown_AddRef( punk );
3495
3496 if(This->site)
3497 IUnknown_Release( This->site );
3498
3499 This->site = punk;
3500
3501 return S_OK;
3502 }
3503
3504 static const IObjectWithSiteVtbl domdocObjectSite =
3505 {
3506 domdoc_ObjectWithSite_QueryInterface,
3507 domdoc_ObjectWithSite_AddRef,
3508 domdoc_ObjectWithSite_Release,
3509 domdoc_ObjectWithSite_SetSite,
3510 domdoc_ObjectWithSite_GetSite
3511 };
3512
3513 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3514 {
3515 domdoc *This = impl_from_IObjectSafety(iface);
3516 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3517 }
3518
3519 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3520 {
3521 domdoc *This = impl_from_IObjectSafety(iface);
3522 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3523 }
3524
3525 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3526 {
3527 domdoc *This = impl_from_IObjectSafety(iface);
3528 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3529 }
3530
3531 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3532
3533 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3534 DWORD *supported, DWORD *enabled)
3535 {
3536 domdoc *This = impl_from_IObjectSafety(iface);
3537
3538 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3539
3540 if(!supported || !enabled) return E_POINTER;
3541
3542 *supported = SAFETY_SUPPORTED_OPTIONS;
3543 *enabled = This->safeopt;
3544
3545 return S_OK;
3546 }
3547
3548 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3549 DWORD mask, DWORD enabled)
3550 {
3551 domdoc *This = impl_from_IObjectSafety(iface);
3552 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3553
3554 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3555 return E_FAIL;
3556
3557 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3558
3559 return S_OK;
3560 }
3561
3562 #undef SAFETY_SUPPORTED_OPTIONS
3563
3564 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3565 domdoc_Safety_QueryInterface,
3566 domdoc_Safety_AddRef,
3567 domdoc_Safety_Release,
3568 domdoc_Safety_GetInterfaceSafetyOptions,
3569 domdoc_Safety_SetInterfaceSafetyOptions
3570 };
3571
3572 static const tid_t domdoc_iface_tids[] = {
3573 IXMLDOMDocument3_tid,
3574 0
3575 };
3576
3577 static dispex_static_data_t domdoc_dispex = {
3578 NULL,
3579 IXMLDOMDocument3_tid,
3580 NULL,
3581 domdoc_iface_tids
3582 };
3583
3584 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3585 {
3586 domdoc *doc;
3587
3588 doc = heap_alloc( sizeof (*doc) );
3589 if( !doc )
3590 return E_OUTOFMEMORY;
3591
3592 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3593 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3594 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3595 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3596 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3597 doc->ref = 1;
3598 doc->async = VARIANT_TRUE;
3599 doc->validating = 0;
3600 doc->resolving = 0;
3601 doc->properties = properties_from_xmlDocPtr(xmldoc);
3602 doc->error = S_OK;
3603 doc->site = NULL;
3604 doc->safeopt = 0;
3605 doc->cp_list = NULL;
3606 doc->namespaces = NULL;
3607 memset(doc->events, 0, sizeof(doc->events));
3608
3609 /* events connection points */
3610 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3611 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3612 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3613
3614 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3615 &domdoc_dispex);
3616
3617 *document = &doc->IXMLDOMDocument3_iface;
3618
3619 TRACE("returning iface %p\n", *document);
3620 return S_OK;
3621 }
3622
3623 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3624 {
3625 xmlDocPtr xmldoc;
3626 HRESULT hr;
3627
3628 TRACE("(%d, %p)\n", version, ppObj);
3629
3630 xmldoc = xmlNewDoc(NULL);
3631 if(!xmldoc)
3632 return E_OUTOFMEMORY;
3633
3634 xmldoc_init(xmldoc, version);
3635
3636 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3637 if(FAILED(hr))
3638 {
3639 free_properties(properties_from_xmlDocPtr(xmldoc));
3640 heap_free(xmldoc->_private);
3641 xmlFreeDoc(xmldoc);
3642 return hr;
3643 }
3644
3645 return hr;
3646 }
3647
3648 IUnknown* create_domdoc( xmlNodePtr document )
3649 {
3650 IUnknown *obj = NULL;
3651 HRESULT hr;
3652
3653 TRACE("(%p)\n", document);
3654
3655 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&obj);
3656 if (FAILED(hr))
3657 return NULL;
3658
3659 return obj;
3660 }
3661
3662 #else
3663
3664 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3665 {
3666 MESSAGE("This program tried to use a DOMDocument object, but\n"
3667 "libxml2 support was not present at compile time.\n");
3668 return E_NOTIMPL;
3669 }
3670
3671 #endif