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