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