[SHELL32] Implement support for IID_IDropTarget in CDesktopFolder::GetUIObjectOf...
[reactos.git] / reactos / dll / win32 / msxml3 / node.c
1 /*
2 * Node implementation
3 *
4 * Copyright 2005 Mike McCormack
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 #ifdef HAVE_LIBXML2
24 # include <libxml/HTMLtree.h>
25 # ifdef SONAME_LIBXSLT
26 # ifdef HAVE_LIBXSLT_PATTERN_H
27 # include <libxslt/pattern.h>
28 # endif
29 # ifdef HAVE_LIBXSLT_TRANSFORM_H
30 # include <libxslt/transform.h>
31 # endif
32 # include <libxslt/imports.h>
33 # include <libxslt/variables.h>
34 # include <libxslt/xsltutils.h>
35 # include <libxslt/xsltInternals.h>
36 # endif
37 #endif
38
39 #ifdef HAVE_LIBXML2
40
41 #ifdef SONAME_LIBXSLT
42 extern void* libxslt_handle;
43 # define MAKE_FUNCPTR(f) extern typeof(f) * p##f
44 MAKE_FUNCPTR(xsltApplyStylesheet);
45 MAKE_FUNCPTR(xsltApplyStylesheetUser);
46 MAKE_FUNCPTR(xsltCleanupGlobals);
47 MAKE_FUNCPTR(xsltFreeStylesheet);
48 MAKE_FUNCPTR(xsltFreeTransformContext);
49 MAKE_FUNCPTR(xsltNewTransformContext);
50 MAKE_FUNCPTR(xsltNextImport);
51 MAKE_FUNCPTR(xsltParseStylesheetDoc);
52 MAKE_FUNCPTR(xsltQuoteUserParams);
53 MAKE_FUNCPTR(xsltSaveResultTo);
54 # undef MAKE_FUNCPTR
55 #else
56 WINE_DECLARE_DEBUG_CHANNEL(winediag);
57 #endif
58
59 static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}};
60
61 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
62 {
63 xmlnode *This;
64
65 if ( !iface )
66 return NULL;
67 This = get_node_obj( iface );
68 if ( !This || !This->node )
69 return NULL;
70 if ( type && This->node->type != type )
71 return NULL;
72 return This->node;
73 }
74
75 BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv)
76 {
77 if(IsEqualGUID(&IID_xmlnode, riid)) {
78 TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv);
79 *ppv = This;
80 return TRUE;
81 }
82
83 return dispex_query_interface(&This->dispex, riid, ppv);
84 }
85
86 /* common ISupportErrorInfo implementation */
87 typedef struct {
88 ISupportErrorInfo ISupportErrorInfo_iface;
89 LONG ref;
90
91 const tid_t* iids;
92 } SupportErrorInfo;
93
94 static inline SupportErrorInfo *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
95 {
96 return CONTAINING_RECORD(iface, SupportErrorInfo, ISupportErrorInfo_iface);
97 }
98
99 static HRESULT WINAPI SupportErrorInfo_QueryInterface(ISupportErrorInfo *iface, REFIID riid, void **obj)
100 {
101 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
102 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
103
104 *obj = NULL;
105
106 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISupportErrorInfo)) {
107 *obj = iface;
108 ISupportErrorInfo_AddRef(iface);
109 return S_OK;
110 }
111
112 return E_NOINTERFACE;
113 }
114
115 static ULONG WINAPI SupportErrorInfo_AddRef(ISupportErrorInfo *iface)
116 {
117 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
118 ULONG ref = InterlockedIncrement(&This->ref);
119 TRACE("(%p)->(%d)\n", This, ref );
120 return ref;
121 }
122
123 static ULONG WINAPI SupportErrorInfo_Release(ISupportErrorInfo *iface)
124 {
125 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
126 LONG ref = InterlockedDecrement(&This->ref);
127
128 TRACE("(%p)->(%d)\n", This, ref);
129
130 if (ref == 0)
131 heap_free(This);
132
133 return ref;
134 }
135
136 static HRESULT WINAPI SupportErrorInfo_InterfaceSupportsErrorInfo(ISupportErrorInfo *iface, REFIID riid)
137 {
138 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
139 enum tid_t const *tid;
140
141 TRACE("(%p)->(%s)\n", This, debugstr_guid(riid));
142
143 tid = This->iids;
144 while (*tid != NULL_tid)
145 {
146 if (IsEqualGUID(riid, get_riid_from_tid(*tid)))
147 return S_OK;
148 tid++;
149 }
150
151 return S_FALSE;
152 }
153
154 static const struct ISupportErrorInfoVtbl SupportErrorInfoVtbl = {
155 SupportErrorInfo_QueryInterface,
156 SupportErrorInfo_AddRef,
157 SupportErrorInfo_Release,
158 SupportErrorInfo_InterfaceSupportsErrorInfo
159 };
160
161 HRESULT node_create_supporterrorinfo(enum tid_t const *iids, void **obj)
162 {
163 SupportErrorInfo *This;
164
165 This = heap_alloc(sizeof(*This));
166 if (!This) return E_OUTOFMEMORY;
167
168 This->ISupportErrorInfo_iface.lpVtbl = &SupportErrorInfoVtbl;
169 This->ref = 1;
170 This->iids = iids;
171
172 *obj = &This->ISupportErrorInfo_iface;
173
174 return S_OK;
175 }
176
177 xmlnode *get_node_obj(IXMLDOMNode *node)
178 {
179 xmlnode *obj = NULL;
180 HRESULT hres;
181
182 hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj);
183 if (!obj) WARN("node is not our IXMLDOMNode implementation\n");
184 return SUCCEEDED(hres) ? obj : NULL;
185 }
186
187 HRESULT node_get_nodeName(xmlnode *This, BSTR *name)
188 {
189 BSTR prefix, base;
190 HRESULT hr;
191
192 if (!name)
193 return E_INVALIDARG;
194
195 hr = node_get_base_name(This, &base);
196 if (hr != S_OK) return hr;
197
198 hr = node_get_prefix(This, &prefix);
199 if (hr == S_OK)
200 {
201 static const WCHAR colW = ':';
202 WCHAR *ptr;
203
204 /* +1 for ':' */
205 ptr = *name = SysAllocStringLen(NULL, SysStringLen(base) + SysStringLen(prefix) + 1);
206 memcpy(ptr, prefix, SysStringByteLen(prefix));
207 ptr += SysStringLen(prefix);
208 memcpy(ptr++, &colW, sizeof(WCHAR));
209 memcpy(ptr, base, SysStringByteLen(base));
210
211 SysFreeString(base);
212 SysFreeString(prefix);
213 }
214 else
215 *name = base;
216
217 return S_OK;
218 }
219
220 HRESULT node_get_content(xmlnode *This, VARIANT *value)
221 {
222 xmlChar *content;
223
224 if(!value)
225 return E_INVALIDARG;
226
227 content = xmlNodeGetContent(This->node);
228 V_VT(value) = VT_BSTR;
229 V_BSTR(value) = bstr_from_xmlChar( content );
230 xmlFree(content);
231
232 TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value)));
233 return S_OK;
234 }
235
236 HRESULT node_set_content(xmlnode *This, LPCWSTR value)
237 {
238 xmlChar *str;
239
240 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
241 str = xmlchar_from_wchar(value);
242 if(!str)
243 return E_OUTOFMEMORY;
244
245 xmlNodeSetContent(This->node, str);
246 heap_free(str);
247 return S_OK;
248 }
249
250 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value)
251 {
252 xmlChar *str, *escaped;
253
254 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
255 str = xmlchar_from_wchar(value);
256 if(!str)
257 return E_OUTOFMEMORY;
258
259 escaped = xmlEncodeSpecialChars(NULL, str);
260 if(!escaped)
261 {
262 heap_free(str);
263 return E_OUTOFMEMORY;
264 }
265
266 xmlNodeSetContent(This->node, escaped);
267
268 heap_free(str);
269 xmlFree(escaped);
270
271 return S_OK;
272 }
273
274 HRESULT node_put_value(xmlnode *This, VARIANT *value)
275 {
276 HRESULT hr;
277
278 if (V_VT(value) != VT_BSTR)
279 {
280 VARIANT string_value;
281
282 VariantInit(&string_value);
283 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
284 if(FAILED(hr)) {
285 WARN("Couldn't convert to VT_BSTR\n");
286 return hr;
287 }
288
289 hr = node_set_content(This, V_BSTR(&string_value));
290 VariantClear(&string_value);
291 }
292 else
293 hr = node_set_content(This, V_BSTR(value));
294
295 return hr;
296 }
297
298 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value)
299 {
300 HRESULT hr;
301
302 if (V_VT(value) != VT_BSTR)
303 {
304 VARIANT string_value;
305
306 VariantInit(&string_value);
307 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
308 if(FAILED(hr)) {
309 WARN("Couldn't convert to VT_BSTR\n");
310 return hr;
311 }
312
313 hr = node_set_content_escaped(This, V_BSTR(&string_value));
314 VariantClear(&string_value);
315 }
316 else
317 hr = node_set_content_escaped(This, V_BSTR(value));
318
319 return hr;
320 }
321
322 static HRESULT get_node(
323 xmlnode *This,
324 const char *name,
325 xmlNodePtr node,
326 IXMLDOMNode **out )
327 {
328 TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
329
330 if ( !out )
331 return E_INVALIDARG;
332
333 /* if we don't have a doc, use our parent. */
334 if(node && !node->doc && node->parent)
335 node->doc = node->parent->doc;
336
337 *out = create_node( node );
338 if (!*out)
339 return S_FALSE;
340 return S_OK;
341 }
342
343 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent)
344 {
345 return get_node( This, "parent", This->node->parent, parent );
346 }
347
348 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret)
349 {
350 if(!ret)
351 return E_INVALIDARG;
352
353 *ret = create_children_nodelist(This->node);
354 if(!*ret)
355 return E_OUTOFMEMORY;
356
357 return S_OK;
358 }
359
360 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret)
361 {
362 return get_node(This, "firstChild", This->node->children, ret);
363 }
364
365 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret)
366 {
367 return get_node(This, "lastChild", This->node->last, ret);
368 }
369
370 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret)
371 {
372 return get_node(This, "previous", This->node->prev, ret);
373 }
374
375 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret)
376 {
377 return get_node(This, "next", This->node->next, ret);
378 }
379
380 static int node_get_inst_cnt(xmlNodePtr node)
381 {
382 int ret = *(LONG *)&node->_private & NODE_PRIV_REFCOUNT_MASK;
383 xmlNodePtr child;
384
385 /* add attribute counts */
386 if (node->type == XML_ELEMENT_NODE)
387 {
388 xmlAttrPtr prop = node->properties;
389
390 while (prop)
391 {
392 ret += node_get_inst_cnt((xmlNodePtr)prop);
393 prop = prop->next;
394 }
395 }
396
397 /* add children counts */
398 child = node->children;
399 while (child)
400 {
401 ret += node_get_inst_cnt(child);
402 child = child->next;
403 }
404
405 return ret;
406 }
407
408 int xmlnode_get_inst_cnt(xmlnode *node)
409 {
410 return node_get_inst_cnt(node->node);
411 }
412
413 /* _private field holds a number of COM instances spawned from this libxml2 node
414 * most significant bits are used to store information about ignorrable whitespace nodes */
415 void xmlnode_add_ref(xmlNodePtr node)
416 {
417 if (node->type == XML_DOCUMENT_NODE) return;
418 InterlockedIncrement((LONG*)&node->_private);
419 }
420
421 void xmlnode_release(xmlNodePtr node)
422 {
423 if (node->type == XML_DOCUMENT_NODE) return;
424 InterlockedDecrement((LONG*)&node->_private);
425 }
426
427 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child,
428 IXMLDOMNode **ret)
429 {
430 IXMLDOMNode *before = NULL;
431 xmlnode *node_obj;
432 int refcount = 0;
433 xmlDocPtr doc;
434 HRESULT hr;
435
436 if(!new_child)
437 return E_INVALIDARG;
438
439 node_obj = get_node_obj(new_child);
440 if(!node_obj) return E_FAIL;
441
442 switch(V_VT(ref_child))
443 {
444 case VT_EMPTY:
445 case VT_NULL:
446 break;
447
448 case VT_UNKNOWN:
449 case VT_DISPATCH:
450 if (V_UNKNOWN(ref_child))
451 {
452 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before);
453 if(FAILED(hr)) return hr;
454 }
455 break;
456
457 default:
458 FIXME("refChild var type %x\n", V_VT(ref_child));
459 return E_FAIL;
460 }
461
462 TRACE("new child %p, This->node %p\n", node_obj->node, This->node);
463
464 if(!node_obj->node->parent)
465 if(xmldoc_remove_orphan(node_obj->node->doc, node_obj->node) != S_OK)
466 WARN("%p is not an orphan of %p\n", node_obj->node, node_obj->node->doc);
467
468 refcount = xmlnode_get_inst_cnt(node_obj);
469
470 if(before)
471 {
472 xmlnode *before_node_obj = get_node_obj(before);
473 IXMLDOMNode_Release(before);
474 if(!before_node_obj) return E_FAIL;
475 }
476
477 /* unlink from current parent first */
478 if(node_obj->parent)
479 {
480 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
481 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
482 }
483 doc = node_obj->node->doc;
484
485 if(before)
486 {
487 xmlNodePtr new_node;
488 xmlnode *before_node_obj = get_node_obj(before);
489
490 /* refs count including subtree */
491 if (doc != before_node_obj->node->doc)
492 refcount = xmlnode_get_inst_cnt(node_obj);
493
494 if (refcount) xmldoc_add_refs(before_node_obj->node->doc, refcount);
495 new_node = xmlAddPrevSibling(before_node_obj->node, node_obj->node);
496 if (new_node != node_obj->node)
497 {
498 if (refcount != 1)
499 FIXME("referenced xmlNode was freed, expect crashes\n");
500 xmlnode_add_ref(new_node);
501 node_obj->node = new_node;
502 }
503 if (refcount) xmldoc_release_refs(doc, refcount);
504 node_obj->parent = This->parent;
505 }
506 else
507 {
508 xmlNodePtr new_node;
509
510 if (doc != This->node->doc)
511 refcount = xmlnode_get_inst_cnt(node_obj);
512
513 if (refcount) xmldoc_add_refs(This->node->doc, refcount);
514 /* xmlAddChild doesn't unlink node from previous parent */
515 xmlUnlinkNode(node_obj->node);
516 new_node = xmlAddChild(This->node, node_obj->node);
517 if (new_node != node_obj->node)
518 {
519 if (refcount != 1)
520 FIXME("referenced xmlNode was freed, expect crashes\n");
521 xmlnode_add_ref(new_node);
522 node_obj->node = new_node;
523 }
524 if (refcount) xmldoc_release_refs(doc, refcount);
525 node_obj->parent = This->iface;
526 }
527
528 if(ret)
529 {
530 IXMLDOMNode_AddRef(new_child);
531 *ret = new_child;
532 }
533
534 TRACE("ret S_OK\n");
535 return S_OK;
536 }
537
538 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
539 IXMLDOMNode **ret)
540 {
541 xmlnode *old_child, *new_child;
542 xmlDocPtr leaving_doc;
543 xmlNode *my_ancestor;
544 int refcount = 0;
545
546 /* Do not believe any documentation telling that newChild == NULL
547 means removal. It does certainly *not* apply to msxml3! */
548 if(!newChild || !oldChild)
549 return E_INVALIDARG;
550
551 if(ret)
552 *ret = NULL;
553
554 old_child = get_node_obj(oldChild);
555 if(!old_child) return E_FAIL;
556
557 if(old_child->node->parent != This->node)
558 {
559 WARN("childNode %p is not a child of %p\n", oldChild, This);
560 return E_INVALIDARG;
561 }
562
563 new_child = get_node_obj(newChild);
564 if(!new_child) return E_FAIL;
565
566 my_ancestor = This->node;
567 while(my_ancestor)
568 {
569 if(my_ancestor == new_child->node)
570 {
571 WARN("tried to create loop\n");
572 return E_FAIL;
573 }
574 my_ancestor = my_ancestor->parent;
575 }
576
577 if(!new_child->node->parent)
578 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
579 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
580
581 leaving_doc = new_child->node->doc;
582
583 if (leaving_doc != old_child->node->doc)
584 refcount = xmlnode_get_inst_cnt(new_child);
585
586 if (refcount) xmldoc_add_refs(old_child->node->doc, refcount);
587 xmlReplaceNode(old_child->node, new_child->node);
588 if (refcount) xmldoc_release_refs(leaving_doc, refcount);
589 new_child->parent = old_child->parent;
590 old_child->parent = NULL;
591
592 xmldoc_add_orphan(old_child->node->doc, old_child->node);
593
594 if(ret)
595 {
596 IXMLDOMNode_AddRef(oldChild);
597 *ret = oldChild;
598 }
599
600 return S_OK;
601 }
602
603 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
604 {
605 xmlnode *child_node;
606
607 if(!child) return E_INVALIDARG;
608
609 if(oldChild)
610 *oldChild = NULL;
611
612 child_node = get_node_obj(child);
613 if(!child_node) return E_FAIL;
614
615 if(child_node->node->parent != This->node)
616 {
617 WARN("childNode %p is not a child of %p\n", child, This);
618 return E_INVALIDARG;
619 }
620
621 xmlUnlinkNode(child_node->node);
622 child_node->parent = NULL;
623 xmldoc_add_orphan(child_node->node->doc, child_node->node);
624
625 if(oldChild)
626 {
627 IXMLDOMNode_AddRef(child);
628 *oldChild = child;
629 }
630
631 return S_OK;
632 }
633
634 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
635 {
636 DOMNodeType type;
637 VARIANT var;
638 HRESULT hr;
639
640 if (!child)
641 return E_INVALIDARG;
642
643 hr = IXMLDOMNode_get_nodeType(child, &type);
644 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
645 if (outChild) *outChild = NULL;
646 return E_FAIL;
647 }
648
649 VariantInit(&var);
650 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
651 }
652
653 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
654 {
655 if (!ret) return E_INVALIDARG;
656
657 if (!This->node->children)
658 {
659 *ret = VARIANT_FALSE;
660 return S_FALSE;
661 }
662
663 *ret = VARIANT_TRUE;
664 return S_OK;
665 }
666
667 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
668 {
669 if(!doc)
670 return E_INVALIDARG;
671 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
672 }
673
674 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
675 {
676 IXMLDOMNode *node;
677 xmlNodePtr clone;
678
679 if(!cloneNode) return E_INVALIDARG;
680
681 clone = xmlCopyNode(This->node, deep ? 1 : 2);
682 if (clone)
683 {
684 xmlSetTreeDoc(clone, This->node->doc);
685 xmldoc_add_orphan(clone->doc, clone);
686
687 node = create_node(clone);
688 if (!node)
689 {
690 ERR("Copy failed\n");
691 xmldoc_remove_orphan(clone->doc, clone);
692 xmlFreeNode(clone);
693 return E_FAIL;
694 }
695
696 *cloneNode = node;
697 }
698 else
699 {
700 ERR("Copy failed\n");
701 return E_FAIL;
702 }
703
704 return S_OK;
705 }
706
707 static xmlChar* do_get_text(xmlNodePtr node, BOOL trim, DWORD *first, DWORD *last, BOOL *trail_ig_ws)
708 {
709 xmlNodePtr child;
710 xmlChar* str;
711 BOOL preserving = is_preserving_whitespace(node);
712
713 *first = -1;
714 *last = 0;
715
716 if (!node->children)
717 {
718 str = xmlNodeGetContent(node);
719 *trail_ig_ws = *(DWORD*)&node->_private & NODE_PRIV_CHILD_IGNORABLE_WS;
720 }
721 else
722 {
723 BOOL ig_ws = FALSE;
724 xmlChar* tmp;
725 DWORD pos = 0;
726 str = xmlStrdup(BAD_CAST "");
727
728 if (node->type != XML_DOCUMENT_NODE)
729 ig_ws = *(DWORD*)&node->_private & NODE_PRIV_CHILD_IGNORABLE_WS;
730 *trail_ig_ws = FALSE;
731
732 for (child = node->children; child != NULL; child = child->next)
733 {
734 switch (child->type)
735 {
736 case XML_ELEMENT_NODE: {
737 DWORD node_first, node_last;
738
739 tmp = do_get_text(child, FALSE, &node_first, &node_last, trail_ig_ws);
740
741 if (node_first!=-1 && pos+node_first<*first)
742 *first = pos+node_first;
743 if (node_last && pos+node_last>*last)
744 *last = pos+node_last;
745 break;
746 }
747 case XML_TEXT_NODE:
748 tmp = xmlNodeGetContent(child);
749 if (!preserving && tmp[0])
750 {
751 xmlChar *beg;
752
753 for (beg = tmp; *beg; beg++)
754 if (!isspace(*beg)) break;
755
756 if (!*beg)
757 {
758 ig_ws = TRUE;
759 xmlFree(tmp);
760 tmp = NULL;
761 }
762 }
763 break;
764 case XML_CDATA_SECTION_NODE:
765 case XML_ENTITY_REF_NODE:
766 case XML_ENTITY_NODE:
767 tmp = xmlNodeGetContent(child);
768 break;
769 default:
770 tmp = NULL;
771 break;
772 }
773
774 if ((tmp && *tmp) || child->type==XML_CDATA_SECTION_NODE)
775 {
776 if (ig_ws && str[0])
777 {
778 str = xmlStrcat(str, BAD_CAST " ");
779 pos++;
780 }
781 if (tmp && *tmp) str = xmlStrcat(str, tmp);
782 if (child->type==XML_CDATA_SECTION_NODE && pos<*first)
783 *first = pos;
784 if (tmp && *tmp) pos += xmlStrlen(tmp);
785 if (child->type==XML_CDATA_SECTION_NODE && pos>*last)
786 *last = pos;
787 ig_ws = FALSE;
788 }
789 if (tmp) xmlFree(tmp);
790
791 if (!ig_ws)
792 {
793 ig_ws = *(DWORD*)&child->_private & NODE_PRIV_TRAILING_IGNORABLE_WS;
794 }
795 if (!ig_ws)
796 ig_ws = *trail_ig_ws;
797 *trail_ig_ws = FALSE;
798 }
799
800 *trail_ig_ws = ig_ws;
801 }
802
803 switch (node->type)
804 {
805 case XML_ELEMENT_NODE:
806 case XML_TEXT_NODE:
807 case XML_ENTITY_REF_NODE:
808 case XML_ENTITY_NODE:
809 case XML_DOCUMENT_NODE:
810 case XML_DOCUMENT_FRAG_NODE:
811 if (trim && !preserving)
812 {
813 xmlChar* ret = str;
814 int len;
815
816 if (!str)
817 break;
818
819 for (ret = str; *ret && isspace(*ret) && (*first)--; ret++)
820 if (*last) (*last)--;
821 for (len = xmlStrlen(ret)-1; len >= 0 && len >= *last; len--)
822 if(!isspace(ret[len])) break;
823
824 ret = xmlStrndup(ret, len+1);
825 xmlFree(str);
826 str = ret;
827 break;
828 }
829 break;
830 default:
831 break;
832 }
833
834 return str;
835 }
836
837 HRESULT node_get_text(const xmlnode *This, BSTR *text)
838 {
839 BSTR str = NULL;
840 xmlChar *content;
841 DWORD first, last;
842 BOOL tmp;
843
844 if (!text) return E_INVALIDARG;
845
846 content = do_get_text(This->node, TRUE, &first, &last, &tmp);
847 if (content)
848 {
849 str = bstr_from_xmlChar(content);
850 xmlFree(content);
851 }
852
853 /* Always return a string. */
854 if (!str) str = SysAllocStringLen( NULL, 0 );
855
856 TRACE("%p %s\n", This, debugstr_w(str) );
857 *text = str;
858
859 return S_OK;
860 }
861
862 HRESULT node_put_text(xmlnode *This, BSTR text)
863 {
864 xmlChar *str, *str2;
865
866 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
867
868 str = xmlchar_from_wchar(text);
869
870 /* Escape the string. */
871 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
872 heap_free(str);
873
874 xmlNodeSetContent(This->node, str2);
875 xmlFree(str2);
876
877 return S_OK;
878 }
879
880 BSTR EnsureCorrectEOL(BSTR sInput)
881 {
882 int nNum = 0;
883 BSTR sNew;
884 int nLen;
885 int i;
886
887 nLen = SysStringLen(sInput);
888 /* Count line endings */
889 for(i=0; i < nLen; i++)
890 {
891 if(sInput[i] == '\n')
892 nNum++;
893 }
894
895 TRACE("len=%d, num=%d\n", nLen, nNum);
896
897 /* Add linefeed as needed */
898 if(nNum > 0)
899 {
900 int nPlace = 0;
901 sNew = SysAllocStringLen(NULL, nLen + nNum);
902 for(i=0; i < nLen; i++)
903 {
904 if(sInput[i] == '\n')
905 {
906 sNew[i+nPlace] = '\r';
907 nPlace++;
908 }
909 sNew[i+nPlace] = sInput[i];
910 }
911
912 SysFreeString(sInput);
913 }
914 else
915 {
916 sNew = sInput;
917 }
918
919 TRACE("len %d\n", SysStringLen(sNew));
920
921 return sNew;
922 }
923
924 /*
925 * We are trying to replicate the same behaviour as msxml by converting
926 * line endings to \r\n and using indents as \t. The problem is that msxml
927 * only formats nodes that have a line ending. Using libxml we cannot
928 * reproduce behaviour exactly.
929 *
930 */
931 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BSTR *ret)
932 {
933 xmlBufferPtr xml_buf;
934 xmlNodePtr xmldecl;
935 int size;
936
937 if(!ret)
938 return E_INVALIDARG;
939
940 *ret = NULL;
941
942 xml_buf = xmlBufferCreate();
943 if(!xml_buf)
944 return E_OUTOFMEMORY;
945
946 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
947
948 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
949 if(size > 0) {
950 const xmlChar *buf_content;
951 BSTR content;
952
953 /* Attribute Nodes return a space in front of their name */
954 buf_content = xmlBufferContent(xml_buf);
955
956 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
957 if(ensure_eol)
958 content = EnsureCorrectEOL(content);
959
960 *ret = content;
961 }else {
962 *ret = SysAllocStringLen(NULL, 0);
963 }
964
965 xmlBufferFree(xml_buf);
966 xmldoc_link_xmldecl( This->node->doc, xmldecl );
967 return *ret ? S_OK : E_OUTOFMEMORY;
968 }
969
970 #ifdef SONAME_LIBXSLT
971
972 /* duplicates xmlBufferWriteQuotedString() logic */
973 static void xml_write_quotedstring(xmlOutputBufferPtr buf, const xmlChar *string)
974 {
975 const xmlChar *cur, *base;
976
977 if (xmlStrchr(string, '\"'))
978 {
979 if (xmlStrchr(string, '\''))
980 {
981 xmlOutputBufferWrite(buf, 1, "\"");
982 base = cur = string;
983
984 while (*cur)
985 {
986 if (*cur == '"')
987 {
988 if (base != cur)
989 xmlOutputBufferWrite(buf, cur-base, (const char*)base);
990 xmlOutputBufferWrite(buf, 6, "&quot;");
991 cur++;
992 base = cur;
993 }
994 else
995 cur++;
996 }
997 if (base != cur)
998 xmlOutputBufferWrite(buf, cur-base, (const char*)base);
999 xmlOutputBufferWrite(buf, 1, "\"");
1000 }
1001 else
1002 {
1003 xmlOutputBufferWrite(buf, 1, "\'");
1004 xmlOutputBufferWriteString(buf, (const char*)string);
1005 xmlOutputBufferWrite(buf, 1, "\'");
1006 }
1007 }
1008 else
1009 {
1010 xmlOutputBufferWrite(buf, 1, "\"");
1011 xmlOutputBufferWriteString(buf, (const char*)string);
1012 xmlOutputBufferWrite(buf, 1, "\"");
1013 }
1014 }
1015
1016 static int XMLCALL transform_to_stream_write(void *context, const char *buffer, int len)
1017 {
1018 DWORD written;
1019 HRESULT hr = IStream_Write((IStream*)context, buffer, len, &written);
1020 return hr == S_OK ? written : -1;
1021 }
1022
1023 /* Output for method "text" */
1024 static void transform_write_text(xmlDocPtr result, xsltStylesheetPtr style, xmlOutputBufferPtr output)
1025 {
1026 xmlNodePtr cur = result->children;
1027 while (cur)
1028 {
1029 if (cur->type == XML_TEXT_NODE)
1030 xmlOutputBufferWriteString(output, (const char*)cur->content);
1031
1032 /* skip to next node */
1033 if (cur->children)
1034 {
1035 if ((cur->children->type != XML_ENTITY_DECL) &&
1036 (cur->children->type != XML_ENTITY_REF_NODE) &&
1037 (cur->children->type != XML_ENTITY_NODE))
1038 {
1039 cur = cur->children;
1040 continue;
1041 }
1042 }
1043
1044 if (cur->next) {
1045 cur = cur->next;
1046 continue;
1047 }
1048
1049 do
1050 {
1051 cur = cur->parent;
1052 if (cur == NULL)
1053 break;
1054 if (cur == (xmlNodePtr) style->doc) {
1055 cur = NULL;
1056 break;
1057 }
1058 if (cur->next) {
1059 cur = cur->next;
1060 break;
1061 }
1062 } while (cur);
1063 }
1064 }
1065
1066 #undef XSLT_GET_IMPORT_PTR
1067 #define XSLT_GET_IMPORT_PTR(res, style, name) { \
1068 xsltStylesheetPtr st = style; \
1069 res = NULL; \
1070 while (st != NULL) { \
1071 if (st->name != NULL) { res = st->name; break; } \
1072 st = pxsltNextImport(st); \
1073 }}
1074
1075 #undef XSLT_GET_IMPORT_INT
1076 #define XSLT_GET_IMPORT_INT(res, style, name) { \
1077 xsltStylesheetPtr st = style; \
1078 res = -1; \
1079 while (st != NULL) { \
1080 if (st->name != -1) { res = st->name; break; } \
1081 st = pxsltNextImport(st); \
1082 }}
1083
1084 static void transform_write_xmldecl(xmlDocPtr result, xsltStylesheetPtr style, BOOL omit_encoding, xmlOutputBufferPtr output)
1085 {
1086 int omit_xmldecl, standalone;
1087
1088 XSLT_GET_IMPORT_INT(omit_xmldecl, style, omitXmlDeclaration);
1089 if (omit_xmldecl == 1) return;
1090
1091 XSLT_GET_IMPORT_INT(standalone, style, standalone);
1092
1093 xmlOutputBufferWriteString(output, "<?xml version=");
1094 if (result->version)
1095 {
1096 xmlOutputBufferWriteString(output, "\"");
1097 xmlOutputBufferWriteString(output, (const char *)result->version);
1098 xmlOutputBufferWriteString(output, "\"");
1099 }
1100 else
1101 xmlOutputBufferWriteString(output, "\"1.0\"");
1102
1103 if (!omit_encoding)
1104 {
1105 const xmlChar *encoding;
1106
1107 /* default encoding is UTF-16 */
1108 XSLT_GET_IMPORT_PTR(encoding, style, encoding);
1109 xmlOutputBufferWriteString(output, " encoding=");
1110 xmlOutputBufferWriteString(output, "\"");
1111 xmlOutputBufferWriteString(output, encoding ? (const char *)encoding : "UTF-16");
1112 xmlOutputBufferWriteString(output, "\"");
1113 }
1114
1115 /* standalone attribute */
1116 if (standalone != -1)
1117 xmlOutputBufferWriteString(output, standalone == 0 ? " standalone=\"no\"" : " standalone=\"yes\"");
1118
1119 xmlOutputBufferWriteString(output, "?>");
1120 }
1121
1122 static void htmldtd_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc)
1123 {
1124 xmlDtdPtr cur = doc->intSubset;
1125
1126 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
1127 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1128 if (cur->ExternalID)
1129 {
1130 xmlOutputBufferWriteString(buf, " PUBLIC ");
1131 xml_write_quotedstring(buf, cur->ExternalID);
1132 if (cur->SystemID)
1133 {
1134 xmlOutputBufferWriteString(buf, " ");
1135 xml_write_quotedstring(buf, cur->SystemID);
1136 }
1137 }
1138 else if (cur->SystemID)
1139 {
1140 xmlOutputBufferWriteString(buf, " SYSTEM ");
1141 xml_write_quotedstring(buf, cur->SystemID);
1142 }
1143 xmlOutputBufferWriteString(buf, ">\n");
1144 }
1145
1146 /* Duplicates htmlDocContentDumpFormatOutput() the way we need it - doesn't add trailing newline. */
1147 static void htmldoc_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc, const char *encoding, int format)
1148 {
1149 xmlElementType type;
1150
1151 /* force HTML output */
1152 type = doc->type;
1153 doc->type = XML_HTML_DOCUMENT_NODE;
1154 if (doc->intSubset)
1155 htmldtd_dumpcontent(buf, doc);
1156 if (doc->children) {
1157 xmlNodePtr cur = doc->children;
1158 while (cur) {
1159 htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
1160 cur = cur->next;
1161 }
1162 }
1163 doc->type = type;
1164 }
1165
1166 static inline BOOL transform_is_empty_resultdoc(xmlDocPtr result)
1167 {
1168 return !result->children || ((result->children->type == XML_DTD_NODE) && !result->children->next);
1169 }
1170
1171 static inline BOOL transform_is_valid_method(xsltStylesheetPtr style)
1172 {
1173 return !style->methodURI || !(style->method && xmlStrEqual(style->method, (const xmlChar *)"xhtml"));
1174 }
1175
1176 /* Helper to write transformation result to specified output buffer. */
1177 static HRESULT node_transform_write(xsltStylesheetPtr style, xmlDocPtr result, BOOL omit_encoding, const char *encoding, xmlOutputBufferPtr output)
1178 {
1179 const xmlChar *method;
1180 int indent;
1181
1182 if (!transform_is_valid_method(style))
1183 {
1184 ERR("unknown output method\n");
1185 return E_FAIL;
1186 }
1187
1188 XSLT_GET_IMPORT_PTR(method, style, method)
1189 XSLT_GET_IMPORT_INT(indent, style, indent);
1190
1191 if (!method && (result->type == XML_HTML_DOCUMENT_NODE))
1192 method = (const xmlChar *) "html";
1193
1194 if (method && xmlStrEqual(method, (const xmlChar *)"html"))
1195 {
1196 htmlSetMetaEncoding(result, (const xmlChar *)encoding);
1197 if (indent == -1)
1198 indent = 1;
1199 htmldoc_dumpcontent(output, result, (const char*)encoding, indent);
1200 }
1201 else if (method && xmlStrEqual(method, (const xmlChar *)"xhtml"))
1202 {
1203 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1204 htmlDocContentDumpOutput(output, result, encoding);
1205 }
1206 else if (method && xmlStrEqual(method, (const xmlChar *)"text"))
1207 transform_write_text(result, style, output);
1208 else
1209 {
1210 transform_write_xmldecl(result, style, omit_encoding, output);
1211
1212 if (result->children)
1213 {
1214 xmlNodePtr child = result->children;
1215
1216 while (child)
1217 {
1218 xmlNodeDumpOutput(output, result, child, 0, indent == 1, encoding);
1219 if (indent && ((child->type == XML_DTD_NODE) || ((child->type == XML_COMMENT_NODE) && child->next)))
1220 xmlOutputBufferWriteString(output, "\r\n");
1221 child = child->next;
1222 }
1223 }
1224 }
1225
1226 xmlOutputBufferFlush(output);
1227 return S_OK;
1228 }
1229
1230 /* For BSTR output is always UTF-16, without 'encoding' attribute */
1231 static HRESULT node_transform_write_to_bstr(xsltStylesheetPtr style, xmlDocPtr result, BSTR *str)
1232 {
1233 HRESULT hr = S_OK;
1234
1235 if (transform_is_empty_resultdoc(result))
1236 *str = SysAllocStringLen(NULL, 0);
1237 else
1238 {
1239 xmlOutputBufferPtr output = xmlAllocOutputBuffer(xmlFindCharEncodingHandler("UTF-16"));
1240 const xmlChar *content;
1241 size_t len;
1242
1243 *str = NULL;
1244 if (!output)
1245 return E_OUTOFMEMORY;
1246
1247 hr = node_transform_write(style, result, TRUE, "UTF-16", output);
1248 #ifdef LIBXML2_NEW_BUFFER
1249 content = xmlBufContent(output->conv);
1250 len = xmlBufUse(output->conv);
1251 #else
1252 content = xmlBufferContent(output->conv);
1253 len = xmlBufferLength(output->conv);
1254 #endif
1255 /* UTF-16 encoder places UTF-16 bom, we don't need it for BSTR */
1256 content += sizeof(WCHAR);
1257 *str = SysAllocStringLen((WCHAR*)content, len/sizeof(WCHAR) - 1);
1258 xmlOutputBufferClose(output);
1259 }
1260
1261 return *str ? hr : E_OUTOFMEMORY;
1262 }
1263
1264 static HRESULT node_transform_write_to_stream(xsltStylesheetPtr style, xmlDocPtr result, IStream *stream)
1265 {
1266 static const xmlChar *utf16 = (const xmlChar*)"UTF-16";
1267 xmlOutputBufferPtr output;
1268 const xmlChar *encoding;
1269 HRESULT hr;
1270
1271 if (transform_is_empty_resultdoc(result))
1272 {
1273 WARN("empty result document\n");
1274 return S_OK;
1275 }
1276
1277 if (style->methodURI && (!style->method || !xmlStrEqual(style->method, (const xmlChar *) "xhtml")))
1278 {
1279 ERR("unknown output method\n");
1280 return E_FAIL;
1281 }
1282
1283 /* default encoding is UTF-16 */
1284 XSLT_GET_IMPORT_PTR(encoding, style, encoding);
1285 if (!encoding)
1286 encoding = utf16;
1287
1288 output = xmlOutputBufferCreateIO(transform_to_stream_write, NULL, stream, xmlFindCharEncodingHandler((const char*)encoding));
1289 if (!output)
1290 return E_OUTOFMEMORY;
1291
1292 hr = node_transform_write(style, result, FALSE, (const char*)encoding, output);
1293 xmlOutputBufferClose(output);
1294 return hr;
1295 }
1296
1297 #endif
1298
1299 HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p,
1300 IStream *stream, const struct xslprocessor_params *params)
1301 {
1302 #ifdef SONAME_LIBXSLT
1303 xsltStylesheetPtr xsltSS;
1304 HRESULT hr = S_OK;
1305 xmlnode *sheet;
1306
1307 if (!libxslt_handle) return E_NOTIMPL;
1308 if (!stylesheet || !p) return E_INVALIDARG;
1309
1310 *p = NULL;
1311
1312 sheet = get_node_obj(stylesheet);
1313 if(!sheet) return E_FAIL;
1314
1315 xsltSS = pxsltParseStylesheetDoc(sheet->node->doc);
1316 if(xsltSS)
1317 {
1318 const char **xslparams = NULL;
1319 xmlDocPtr result;
1320 unsigned int i;
1321
1322 /* convert our parameter list to libxml2 format */
1323 if (params && params->count)
1324 {
1325 struct xslprocessor_par *par;
1326
1327 i = 0;
1328 xslparams = heap_alloc((params->count*2 + 1)*sizeof(char*));
1329 LIST_FOR_EACH_ENTRY(par, &params->list, struct xslprocessor_par, entry)
1330 {
1331 xslparams[i++] = (char*)xmlchar_from_wchar(par->name);
1332 xslparams[i++] = (char*)xmlchar_from_wchar(par->value);
1333 }
1334 xslparams[i] = NULL;
1335 }
1336
1337 if (xslparams)
1338 {
1339 xsltTransformContextPtr ctxt = pxsltNewTransformContext(xsltSS, This->node->doc);
1340
1341 /* push parameters to user context */
1342 pxsltQuoteUserParams(ctxt, xslparams);
1343 result = pxsltApplyStylesheetUser(xsltSS, This->node->doc, NULL, NULL, NULL, ctxt);
1344 pxsltFreeTransformContext(ctxt);
1345
1346 for (i = 0; i < params->count*2; i++)
1347 heap_free((char*)xslparams[i]);
1348 heap_free(xslparams);
1349 }
1350 else
1351 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1352
1353 if (result)
1354 {
1355 if (stream)
1356 hr = node_transform_write_to_stream(xsltSS, result, stream);
1357 else
1358 hr = node_transform_write_to_bstr(xsltSS, result, p);
1359 xmlFreeDoc(result);
1360 }
1361 /* libxslt "helpfully" frees the XML document the stylesheet was
1362 generated from, too */
1363 xsltSS->doc = NULL;
1364 pxsltFreeStylesheet(xsltSS);
1365 }
1366
1367 if(!*p) *p = SysAllocStringLen(NULL, 0);
1368
1369 return hr;
1370 #else
1371 ERR_(winediag)("libxslt headers were not found at compile time. Expect problems.\n");
1372
1373 return E_NOTIMPL;
1374 #endif
1375 }
1376
1377 HRESULT node_transform_node(const xmlnode *node, IXMLDOMNode *stylesheet, BSTR *p)
1378 {
1379 return node_transform_node_params(node, stylesheet, p, NULL, NULL);
1380 }
1381
1382 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
1383 {
1384 xmlChar* str;
1385 HRESULT hr;
1386
1387 if (!query || !nodes) return E_INVALIDARG;
1388
1389 str = xmlchar_from_wchar(query);
1390 hr = create_selection(This->node, str, nodes);
1391 heap_free(str);
1392
1393 return hr;
1394 }
1395
1396 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
1397 {
1398 IXMLDOMNodeList *list;
1399 HRESULT hr;
1400
1401 hr = node_select_nodes(This, query, &list);
1402 if (hr == S_OK)
1403 {
1404 hr = IXMLDOMNodeList_nextNode(list, node);
1405 IXMLDOMNodeList_Release(list);
1406 }
1407 return hr;
1408 }
1409
1410 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1411 {
1412 xmlNsPtr ns = This->node->ns;
1413
1414 if(!namespaceURI)
1415 return E_INVALIDARG;
1416
1417 *namespaceURI = NULL;
1418
1419 if (ns && ns->href)
1420 *namespaceURI = bstr_from_xmlChar(ns->href);
1421
1422 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1423
1424 return *namespaceURI ? S_OK : S_FALSE;
1425 }
1426
1427 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1428 {
1429 xmlNsPtr ns = This->node->ns;
1430
1431 if (!prefix) return E_INVALIDARG;
1432
1433 *prefix = NULL;
1434
1435 if (ns && ns->prefix)
1436 *prefix = bstr_from_xmlChar(ns->prefix);
1437
1438 TRACE("prefix: %s\n", debugstr_w(*prefix));
1439
1440 return *prefix ? S_OK : S_FALSE;
1441 }
1442
1443 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1444 {
1445 if (!name) return E_INVALIDARG;
1446
1447 *name = bstr_from_xmlChar(This->node->name);
1448 if (!*name) return E_OUTOFMEMORY;
1449
1450 TRACE("returning %s\n", debugstr_w(*name));
1451
1452 return S_OK;
1453 }
1454
1455 void destroy_xmlnode(xmlnode *This)
1456 {
1457 if(This->node)
1458 {
1459 xmlnode_release(This->node);
1460 xmldoc_release(This->node->doc);
1461 }
1462 }
1463
1464 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1465 {
1466 if(node)
1467 {
1468 xmlnode_add_ref(node);
1469 xmldoc_add_ref(node->doc);
1470 }
1471
1472 This->node = node;
1473 This->iface = node_iface;
1474 This->parent = NULL;
1475
1476 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1477 }
1478
1479 typedef struct {
1480 xmlnode node;
1481 IXMLDOMNode IXMLDOMNode_iface;
1482 LONG ref;
1483 } unknode;
1484
1485 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1486 {
1487 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1488 }
1489
1490 static HRESULT WINAPI unknode_QueryInterface(
1491 IXMLDOMNode *iface,
1492 REFIID riid,
1493 void** ppvObject )
1494 {
1495 unknode *This = unknode_from_IXMLDOMNode( iface );
1496
1497 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1498
1499 if (IsEqualGUID(riid, &IID_IUnknown)) {
1500 *ppvObject = iface;
1501 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1502 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1503 *ppvObject = &This->IXMLDOMNode_iface;
1504 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1505 return *ppvObject ? S_OK : E_NOINTERFACE;
1506 }else {
1507 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1508 *ppvObject = NULL;
1509 return E_NOINTERFACE;
1510 }
1511
1512 IUnknown_AddRef((IUnknown*)*ppvObject);
1513 return S_OK;
1514 }
1515
1516 static ULONG WINAPI unknode_AddRef(
1517 IXMLDOMNode *iface )
1518 {
1519 unknode *This = unknode_from_IXMLDOMNode( iface );
1520
1521 return InterlockedIncrement(&This->ref);
1522 }
1523
1524 static ULONG WINAPI unknode_Release(
1525 IXMLDOMNode *iface )
1526 {
1527 unknode *This = unknode_from_IXMLDOMNode( iface );
1528 LONG ref;
1529
1530 ref = InterlockedDecrement( &This->ref );
1531 if(!ref) {
1532 destroy_xmlnode(&This->node);
1533 heap_free(This);
1534 }
1535
1536 return ref;
1537 }
1538
1539 static HRESULT WINAPI unknode_GetTypeInfoCount(
1540 IXMLDOMNode *iface,
1541 UINT* pctinfo )
1542 {
1543 unknode *This = unknode_from_IXMLDOMNode( iface );
1544
1545 TRACE("(%p)->(%p)\n", This, pctinfo);
1546
1547 *pctinfo = 1;
1548
1549 return S_OK;
1550 }
1551
1552 static HRESULT WINAPI unknode_GetTypeInfo(
1553 IXMLDOMNode *iface,
1554 UINT iTInfo,
1555 LCID lcid,
1556 ITypeInfo** ppTInfo )
1557 {
1558 unknode *This = unknode_from_IXMLDOMNode( iface );
1559 HRESULT hr;
1560
1561 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1562
1563 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1564
1565 return hr;
1566 }
1567
1568 static HRESULT WINAPI unknode_GetIDsOfNames(
1569 IXMLDOMNode *iface,
1570 REFIID riid,
1571 LPOLESTR* rgszNames,
1572 UINT cNames,
1573 LCID lcid,
1574 DISPID* rgDispId )
1575 {
1576 unknode *This = unknode_from_IXMLDOMNode( iface );
1577
1578 ITypeInfo *typeinfo;
1579 HRESULT hr;
1580
1581 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1582 lcid, rgDispId);
1583
1584 if(!rgszNames || cNames == 0 || !rgDispId)
1585 return E_INVALIDARG;
1586
1587 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1588 if(SUCCEEDED(hr))
1589 {
1590 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1591 ITypeInfo_Release(typeinfo);
1592 }
1593
1594 return hr;
1595 }
1596
1597 static HRESULT WINAPI unknode_Invoke(
1598 IXMLDOMNode *iface,
1599 DISPID dispIdMember,
1600 REFIID riid,
1601 LCID lcid,
1602 WORD wFlags,
1603 DISPPARAMS* pDispParams,
1604 VARIANT* pVarResult,
1605 EXCEPINFO* pExcepInfo,
1606 UINT* puArgErr )
1607 {
1608 unknode *This = unknode_from_IXMLDOMNode( iface );
1609 ITypeInfo *typeinfo;
1610 HRESULT hr;
1611
1612 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1613 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1614
1615 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1616 if(SUCCEEDED(hr))
1617 {
1618 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1619 pVarResult, pExcepInfo, puArgErr);
1620 ITypeInfo_Release(typeinfo);
1621 }
1622
1623 return hr;
1624 }
1625
1626 static HRESULT WINAPI unknode_get_nodeName(
1627 IXMLDOMNode *iface,
1628 BSTR* p )
1629 {
1630 unknode *This = unknode_from_IXMLDOMNode( iface );
1631
1632 FIXME("(%p)->(%p)\n", This, p);
1633
1634 return node_get_nodeName(&This->node, p);
1635 }
1636
1637 static HRESULT WINAPI unknode_get_nodeValue(
1638 IXMLDOMNode *iface,
1639 VARIANT* value)
1640 {
1641 unknode *This = unknode_from_IXMLDOMNode( iface );
1642
1643 FIXME("(%p)->(%p)\n", This, value);
1644
1645 if(!value)
1646 return E_INVALIDARG;
1647
1648 V_VT(value) = VT_NULL;
1649 return S_FALSE;
1650 }
1651
1652 static HRESULT WINAPI unknode_put_nodeValue(
1653 IXMLDOMNode *iface,
1654 VARIANT value)
1655 {
1656 unknode *This = unknode_from_IXMLDOMNode( iface );
1657 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1658 return E_FAIL;
1659 }
1660
1661 static HRESULT WINAPI unknode_get_nodeType(
1662 IXMLDOMNode *iface,
1663 DOMNodeType* domNodeType )
1664 {
1665 unknode *This = unknode_from_IXMLDOMNode( iface );
1666
1667 FIXME("(%p)->(%p)\n", This, domNodeType);
1668
1669 switch (This->node.node->type)
1670 {
1671 case XML_ELEMENT_NODE:
1672 case XML_ATTRIBUTE_NODE:
1673 case XML_TEXT_NODE:
1674 case XML_CDATA_SECTION_NODE:
1675 case XML_ENTITY_REF_NODE:
1676 case XML_ENTITY_NODE:
1677 case XML_PI_NODE:
1678 case XML_COMMENT_NODE:
1679 case XML_DOCUMENT_NODE:
1680 case XML_DOCUMENT_TYPE_NODE:
1681 case XML_DOCUMENT_FRAG_NODE:
1682 case XML_NOTATION_NODE:
1683 /* we only care about this set of types, libxml2 type values are
1684 exactly what we need */
1685 *domNodeType = (DOMNodeType)This->node.node->type;
1686 break;
1687 default:
1688 *domNodeType = NODE_INVALID;
1689 break;
1690 }
1691
1692 return S_OK;
1693 }
1694
1695 static HRESULT WINAPI unknode_get_parentNode(
1696 IXMLDOMNode *iface,
1697 IXMLDOMNode** parent )
1698 {
1699 unknode *This = unknode_from_IXMLDOMNode( iface );
1700 FIXME("(%p)->(%p)\n", This, parent);
1701 if (!parent) return E_INVALIDARG;
1702 *parent = NULL;
1703 return S_FALSE;
1704 }
1705
1706 static HRESULT WINAPI unknode_get_childNodes(
1707 IXMLDOMNode *iface,
1708 IXMLDOMNodeList** outList)
1709 {
1710 unknode *This = unknode_from_IXMLDOMNode( iface );
1711
1712 TRACE("(%p)->(%p)\n", This, outList);
1713
1714 return node_get_child_nodes(&This->node, outList);
1715 }
1716
1717 static HRESULT WINAPI unknode_get_firstChild(
1718 IXMLDOMNode *iface,
1719 IXMLDOMNode** domNode)
1720 {
1721 unknode *This = unknode_from_IXMLDOMNode( iface );
1722
1723 TRACE("(%p)->(%p)\n", This, domNode);
1724
1725 return node_get_first_child(&This->node, domNode);
1726 }
1727
1728 static HRESULT WINAPI unknode_get_lastChild(
1729 IXMLDOMNode *iface,
1730 IXMLDOMNode** domNode)
1731 {
1732 unknode *This = unknode_from_IXMLDOMNode( iface );
1733
1734 TRACE("(%p)->(%p)\n", This, domNode);
1735
1736 return node_get_last_child(&This->node, domNode);
1737 }
1738
1739 static HRESULT WINAPI unknode_get_previousSibling(
1740 IXMLDOMNode *iface,
1741 IXMLDOMNode** domNode)
1742 {
1743 unknode *This = unknode_from_IXMLDOMNode( iface );
1744
1745 TRACE("(%p)->(%p)\n", This, domNode);
1746
1747 return node_get_previous_sibling(&This->node, domNode);
1748 }
1749
1750 static HRESULT WINAPI unknode_get_nextSibling(
1751 IXMLDOMNode *iface,
1752 IXMLDOMNode** domNode)
1753 {
1754 unknode *This = unknode_from_IXMLDOMNode( iface );
1755
1756 TRACE("(%p)->(%p)\n", This, domNode);
1757
1758 return node_get_next_sibling(&This->node, domNode);
1759 }
1760
1761 static HRESULT WINAPI unknode_get_attributes(
1762 IXMLDOMNode *iface,
1763 IXMLDOMNamedNodeMap** attributeMap)
1764 {
1765 unknode *This = unknode_from_IXMLDOMNode( iface );
1766
1767 FIXME("(%p)->(%p)\n", This, attributeMap);
1768
1769 return return_null_ptr((void**)attributeMap);
1770 }
1771
1772 static HRESULT WINAPI unknode_insertBefore(
1773 IXMLDOMNode *iface,
1774 IXMLDOMNode* newNode, VARIANT refChild,
1775 IXMLDOMNode** outOldNode)
1776 {
1777 unknode *This = unknode_from_IXMLDOMNode( iface );
1778
1779 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1780
1781 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1782 }
1783
1784 static HRESULT WINAPI unknode_replaceChild(
1785 IXMLDOMNode *iface,
1786 IXMLDOMNode* newNode,
1787 IXMLDOMNode* oldNode,
1788 IXMLDOMNode** outOldNode)
1789 {
1790 unknode *This = unknode_from_IXMLDOMNode( iface );
1791
1792 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1793
1794 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1795 }
1796
1797 static HRESULT WINAPI unknode_removeChild(
1798 IXMLDOMNode *iface,
1799 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1800 {
1801 unknode *This = unknode_from_IXMLDOMNode( iface );
1802 return node_remove_child(&This->node, domNode, oldNode);
1803 }
1804
1805 static HRESULT WINAPI unknode_appendChild(
1806 IXMLDOMNode *iface,
1807 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1808 {
1809 unknode *This = unknode_from_IXMLDOMNode( iface );
1810 return node_append_child(&This->node, newNode, outNewNode);
1811 }
1812
1813 static HRESULT WINAPI unknode_hasChildNodes(
1814 IXMLDOMNode *iface,
1815 VARIANT_BOOL* pbool)
1816 {
1817 unknode *This = unknode_from_IXMLDOMNode( iface );
1818 return node_has_childnodes(&This->node, pbool);
1819 }
1820
1821 static HRESULT WINAPI unknode_get_ownerDocument(
1822 IXMLDOMNode *iface,
1823 IXMLDOMDocument** domDocument)
1824 {
1825 unknode *This = unknode_from_IXMLDOMNode( iface );
1826 return node_get_owner_doc(&This->node, domDocument);
1827 }
1828
1829 static HRESULT WINAPI unknode_cloneNode(
1830 IXMLDOMNode *iface,
1831 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1832 {
1833 unknode *This = unknode_from_IXMLDOMNode( iface );
1834 return node_clone(&This->node, pbool, outNode );
1835 }
1836
1837 static HRESULT WINAPI unknode_get_nodeTypeString(
1838 IXMLDOMNode *iface,
1839 BSTR* p)
1840 {
1841 unknode *This = unknode_from_IXMLDOMNode( iface );
1842
1843 FIXME("(%p)->(%p)\n", This, p);
1844
1845 return node_get_nodeName(&This->node, p);
1846 }
1847
1848 static HRESULT WINAPI unknode_get_text(
1849 IXMLDOMNode *iface,
1850 BSTR* p)
1851 {
1852 unknode *This = unknode_from_IXMLDOMNode( iface );
1853 return node_get_text(&This->node, p);
1854 }
1855
1856 static HRESULT WINAPI unknode_put_text(
1857 IXMLDOMNode *iface,
1858 BSTR p)
1859 {
1860 unknode *This = unknode_from_IXMLDOMNode( iface );
1861 return node_put_text(&This->node, p);
1862 }
1863
1864 static HRESULT WINAPI unknode_get_specified(
1865 IXMLDOMNode *iface,
1866 VARIANT_BOOL* isSpecified)
1867 {
1868 unknode *This = unknode_from_IXMLDOMNode( iface );
1869 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1870 *isSpecified = VARIANT_TRUE;
1871 return S_OK;
1872 }
1873
1874 static HRESULT WINAPI unknode_get_definition(
1875 IXMLDOMNode *iface,
1876 IXMLDOMNode** definitionNode)
1877 {
1878 unknode *This = unknode_from_IXMLDOMNode( iface );
1879 FIXME("(%p)->(%p)\n", This, definitionNode);
1880 return E_NOTIMPL;
1881 }
1882
1883 static HRESULT WINAPI unknode_get_nodeTypedValue(
1884 IXMLDOMNode *iface,
1885 VARIANT* var1)
1886 {
1887 unknode *This = unknode_from_IXMLDOMNode( iface );
1888 FIXME("(%p)->(%p)\n", This, var1);
1889 return return_null_var(var1);
1890 }
1891
1892 static HRESULT WINAPI unknode_put_nodeTypedValue(
1893 IXMLDOMNode *iface,
1894 VARIANT typedValue)
1895 {
1896 unknode *This = unknode_from_IXMLDOMNode( iface );
1897 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1898 return E_NOTIMPL;
1899 }
1900
1901 static HRESULT WINAPI unknode_get_dataType(
1902 IXMLDOMNode *iface,
1903 VARIANT* var1)
1904 {
1905 unknode *This = unknode_from_IXMLDOMNode( iface );
1906 TRACE("(%p)->(%p)\n", This, var1);
1907 return return_null_var(var1);
1908 }
1909
1910 static HRESULT WINAPI unknode_put_dataType(
1911 IXMLDOMNode *iface,
1912 BSTR p)
1913 {
1914 unknode *This = unknode_from_IXMLDOMNode( iface );
1915
1916 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1917
1918 if(!p)
1919 return E_INVALIDARG;
1920
1921 return E_FAIL;
1922 }
1923
1924 static HRESULT WINAPI unknode_get_xml(
1925 IXMLDOMNode *iface,
1926 BSTR* p)
1927 {
1928 unknode *This = unknode_from_IXMLDOMNode( iface );
1929
1930 FIXME("(%p)->(%p)\n", This, p);
1931
1932 return node_get_xml(&This->node, FALSE, p);
1933 }
1934
1935 static HRESULT WINAPI unknode_transformNode(
1936 IXMLDOMNode *iface,
1937 IXMLDOMNode* domNode, BSTR* p)
1938 {
1939 unknode *This = unknode_from_IXMLDOMNode( iface );
1940 return node_transform_node(&This->node, domNode, p);
1941 }
1942
1943 static HRESULT WINAPI unknode_selectNodes(
1944 IXMLDOMNode *iface,
1945 BSTR p, IXMLDOMNodeList** outList)
1946 {
1947 unknode *This = unknode_from_IXMLDOMNode( iface );
1948 return node_select_nodes(&This->node, p, outList);
1949 }
1950
1951 static HRESULT WINAPI unknode_selectSingleNode(
1952 IXMLDOMNode *iface,
1953 BSTR p, IXMLDOMNode** outNode)
1954 {
1955 unknode *This = unknode_from_IXMLDOMNode( iface );
1956 return node_select_singlenode(&This->node, p, outNode);
1957 }
1958
1959 static HRESULT WINAPI unknode_get_parsed(
1960 IXMLDOMNode *iface,
1961 VARIANT_BOOL* isParsed)
1962 {
1963 unknode *This = unknode_from_IXMLDOMNode( iface );
1964 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1965 *isParsed = VARIANT_TRUE;
1966 return S_OK;
1967 }
1968
1969 static HRESULT WINAPI unknode_get_namespaceURI(
1970 IXMLDOMNode *iface,
1971 BSTR* p)
1972 {
1973 unknode *This = unknode_from_IXMLDOMNode( iface );
1974 TRACE("(%p)->(%p)\n", This, p);
1975 return node_get_namespaceURI(&This->node, p);
1976 }
1977
1978 static HRESULT WINAPI unknode_get_prefix(
1979 IXMLDOMNode *iface,
1980 BSTR* p)
1981 {
1982 unknode *This = unknode_from_IXMLDOMNode( iface );
1983 return node_get_prefix(&This->node, p);
1984 }
1985
1986 static HRESULT WINAPI unknode_get_baseName(
1987 IXMLDOMNode *iface,
1988 BSTR* p)
1989 {
1990 unknode *This = unknode_from_IXMLDOMNode( iface );
1991 return node_get_base_name(&This->node, p);
1992 }
1993
1994 static HRESULT WINAPI unknode_transformNodeToObject(
1995 IXMLDOMNode *iface,
1996 IXMLDOMNode* domNode, VARIANT var1)
1997 {
1998 unknode *This = unknode_from_IXMLDOMNode( iface );
1999 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
2000 return E_NOTIMPL;
2001 }
2002
2003 static const struct IXMLDOMNodeVtbl unknode_vtbl =
2004 {
2005 unknode_QueryInterface,
2006 unknode_AddRef,
2007 unknode_Release,
2008 unknode_GetTypeInfoCount,
2009 unknode_GetTypeInfo,
2010 unknode_GetIDsOfNames,
2011 unknode_Invoke,
2012 unknode_get_nodeName,
2013 unknode_get_nodeValue,
2014 unknode_put_nodeValue,
2015 unknode_get_nodeType,
2016 unknode_get_parentNode,
2017 unknode_get_childNodes,
2018 unknode_get_firstChild,
2019 unknode_get_lastChild,
2020 unknode_get_previousSibling,
2021 unknode_get_nextSibling,
2022 unknode_get_attributes,
2023 unknode_insertBefore,
2024 unknode_replaceChild,
2025 unknode_removeChild,
2026 unknode_appendChild,
2027 unknode_hasChildNodes,
2028 unknode_get_ownerDocument,
2029 unknode_cloneNode,
2030 unknode_get_nodeTypeString,
2031 unknode_get_text,
2032 unknode_put_text,
2033 unknode_get_specified,
2034 unknode_get_definition,
2035 unknode_get_nodeTypedValue,
2036 unknode_put_nodeTypedValue,
2037 unknode_get_dataType,
2038 unknode_put_dataType,
2039 unknode_get_xml,
2040 unknode_transformNode,
2041 unknode_selectNodes,
2042 unknode_selectSingleNode,
2043 unknode_get_parsed,
2044 unknode_get_namespaceURI,
2045 unknode_get_prefix,
2046 unknode_get_baseName,
2047 unknode_transformNodeToObject
2048 };
2049
2050 IXMLDOMNode *create_node( xmlNodePtr node )
2051 {
2052 IUnknown *pUnk;
2053 IXMLDOMNode *ret;
2054 HRESULT hr;
2055
2056 if ( !node )
2057 return NULL;
2058
2059 TRACE("type %d\n", node->type);
2060 switch(node->type)
2061 {
2062 case XML_ELEMENT_NODE:
2063 pUnk = create_element( node );
2064 break;
2065 case XML_ATTRIBUTE_NODE:
2066 pUnk = create_attribute( node );
2067 break;
2068 case XML_TEXT_NODE:
2069 pUnk = create_text( node );
2070 break;
2071 case XML_CDATA_SECTION_NODE:
2072 pUnk = create_cdata( node );
2073 break;
2074 case XML_ENTITY_REF_NODE:
2075 pUnk = create_doc_entity_ref( node );
2076 break;
2077 case XML_PI_NODE:
2078 pUnk = create_pi( node );
2079 break;
2080 case XML_COMMENT_NODE:
2081 pUnk = create_comment( node );
2082 break;
2083 case XML_DOCUMENT_NODE:
2084 pUnk = create_domdoc( node );
2085 break;
2086 case XML_DOCUMENT_FRAG_NODE:
2087 pUnk = create_doc_fragment( node );
2088 break;
2089 case XML_DTD_NODE:
2090 case XML_DOCUMENT_TYPE_NODE:
2091 pUnk = create_doc_type( node );
2092 break;
2093 case XML_ENTITY_NODE:
2094 case XML_NOTATION_NODE: {
2095 unknode *new_node;
2096
2097 FIXME("only creating basic node for type %d\n", node->type);
2098
2099 new_node = heap_alloc(sizeof(unknode));
2100 if(!new_node)
2101 return NULL;
2102
2103 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
2104 new_node->ref = 1;
2105 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
2106 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
2107 break;
2108 }
2109 default:
2110 ERR("Called for unsupported node type %d\n", node->type);
2111 return NULL;
2112 }
2113
2114 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
2115 IUnknown_Release(pUnk);
2116 if(FAILED(hr)) return NULL;
2117 return ret;
2118 }
2119 #endif