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