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