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