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