2 * XSLTemplate/XSLProcessor support
4 * Copyright 2011 Nikolay Sivov for CodeWeavers
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.
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.
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
24 #include <libxml/parser.h>
25 #include <libxml/xmlerror.h>
33 #include "msxml_private.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
45 IXSLTemplate IXSLTemplate_iface
;
53 PROCESSOR_OUTPUT_NOT_SET
,
54 PROCESSOR_OUTPUT_STREAM
, /* IStream or ISequentialStream */
55 PROCESSOR_OUTPUT_PERSISTSTREAM
, /* IPersistStream or IPersistStreamInit */
56 PROCESSOR_OUTPUT_RESPONSE
, /* IResponse */
62 IXSLProcessor IXSLProcessor_iface
;
65 xsltemplate
*stylesheet
;
71 ISequentialStream
*stream
;
72 IPersistStream
*persiststream
;
75 enum output_type output_type
;
78 struct xslprocessor_params params
;
81 static HRESULT
XSLProcessor_create(xsltemplate
*, IXSLProcessor
**);
83 static inline xsltemplate
*impl_from_IXSLTemplate( IXSLTemplate
*iface
)
85 return CONTAINING_RECORD(iface
, xsltemplate
, IXSLTemplate_iface
);
88 static inline xslprocessor
*impl_from_IXSLProcessor( IXSLProcessor
*iface
)
90 return CONTAINING_RECORD(iface
, xslprocessor
, IXSLProcessor_iface
);
93 static void xslprocessor_par_free(struct xslprocessor_params
*params
, struct xslprocessor_par
*par
)
96 list_remove(&par
->entry
);
97 SysFreeString(par
->name
);
98 SysFreeString(par
->value
);
102 static void xsltemplate_set_node( xsltemplate
*This
, IXMLDOMNode
*node
)
104 if (This
->node
) IXMLDOMNode_Release(This
->node
);
106 if (node
) IXMLDOMNode_AddRef(node
);
109 static HRESULT WINAPI
xsltemplate_QueryInterface(
114 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
115 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
117 if ( IsEqualGUID( riid
, &IID_IXSLTemplate
) ||
118 IsEqualGUID( riid
, &IID_IDispatch
) ||
119 IsEqualGUID( riid
, &IID_IUnknown
) )
123 else if (dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
125 return *ppvObject
? S_OK
: E_NOINTERFACE
;
129 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
131 return E_NOINTERFACE
;
134 IUnknown_AddRef((IUnknown
*)*ppvObject
);
138 static ULONG WINAPI
xsltemplate_AddRef( IXSLTemplate
*iface
)
140 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
141 ULONG ref
= InterlockedIncrement( &This
->ref
);
142 TRACE("%p, refcount %lu.\n", iface
, ref
);
146 static ULONG WINAPI
xsltemplate_Release( IXSLTemplate
*iface
)
148 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
149 ULONG ref
= InterlockedDecrement( &This
->ref
);
151 TRACE("%p, refcount %lu.\n", iface
, ref
);
154 if (This
->node
) IXMLDOMNode_Release( This
->node
);
161 static HRESULT WINAPI
xsltemplate_GetTypeInfoCount( IXSLTemplate
*iface
, UINT
* pctinfo
)
163 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
164 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
167 static HRESULT WINAPI
xsltemplate_GetTypeInfo(
169 UINT iTInfo
, LCID lcid
,
170 ITypeInfo
** ppTInfo
)
172 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
173 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
174 iTInfo
, lcid
, ppTInfo
);
177 static HRESULT WINAPI
xsltemplate_GetIDsOfNames(
179 REFIID riid
, LPOLESTR
* rgszNames
,
180 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
182 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
183 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
184 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
187 static HRESULT WINAPI
xsltemplate_Invoke(
189 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
190 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
191 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
193 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
194 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
195 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
198 static HRESULT WINAPI
xsltemplate_putref_stylesheet( IXSLTemplate
*iface
,
201 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
203 TRACE("(%p)->(%p)\n", This
, node
);
207 xsltemplate_set_node(This
, NULL
);
211 /* FIXME: test for document type */
212 xsltemplate_set_node(This
, node
);
217 static HRESULT WINAPI
xsltemplate_get_stylesheet( IXSLTemplate
*iface
,
220 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
222 FIXME("(%p)->(%p): stub\n", This
, node
);
226 static HRESULT WINAPI
xsltemplate_createProcessor( IXSLTemplate
*iface
,
227 IXSLProcessor
**processor
)
229 xsltemplate
*This
= impl_from_IXSLTemplate( iface
);
231 TRACE("(%p)->(%p)\n", This
, processor
);
233 if (!processor
) return E_INVALIDARG
;
235 return XSLProcessor_create(This
, processor
);
238 static const struct IXSLTemplateVtbl XSLTemplateVtbl
=
240 xsltemplate_QueryInterface
,
243 xsltemplate_GetTypeInfoCount
,
244 xsltemplate_GetTypeInfo
,
245 xsltemplate_GetIDsOfNames
,
247 xsltemplate_putref_stylesheet
,
248 xsltemplate_get_stylesheet
,
249 xsltemplate_createProcessor
252 static const tid_t xsltemplate_iface_tids
[] = {
257 static dispex_static_data_t xsltemplate_dispex
= {
261 xsltemplate_iface_tids
264 HRESULT
XSLTemplate_create(void **ppObj
)
268 TRACE("(%p)\n", ppObj
);
270 This
= malloc(sizeof(*This
));
272 return E_OUTOFMEMORY
;
274 This
->IXSLTemplate_iface
.lpVtbl
= &XSLTemplateVtbl
;
277 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IXSLTemplate_iface
, &xsltemplate_dispex
);
279 *ppObj
= &This
->IXSLTemplate_iface
;
281 TRACE("returning iface %p\n", *ppObj
);
286 /*** IXSLProcessor ***/
287 static HRESULT WINAPI
xslprocessor_QueryInterface(
288 IXSLProcessor
*iface
,
292 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
293 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
295 if ( IsEqualGUID( riid
, &IID_IXSLProcessor
) ||
296 IsEqualGUID( riid
, &IID_IDispatch
) ||
297 IsEqualGUID( riid
, &IID_IUnknown
) )
301 else if (dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
303 return *ppvObject
? S_OK
: E_NOINTERFACE
;
307 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
309 return E_NOINTERFACE
;
312 IUnknown_AddRef((IUnknown
*)*ppvObject
);
316 static ULONG WINAPI
xslprocessor_AddRef( IXSLProcessor
*iface
)
318 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
319 ULONG ref
= InterlockedIncrement( &This
->ref
);
320 TRACE("%p, refcount %lu.\n", iface
, ref
);
324 static ULONG WINAPI
xslprocessor_Release( IXSLProcessor
*iface
)
326 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
327 ULONG ref
= InterlockedDecrement( &This
->ref
);
329 TRACE("%p, refcount %lu.\n", iface
, ref
);
332 struct xslprocessor_par
*par
, *par2
;
334 if (This
->input
) IXMLDOMNode_Release(This
->input
);
335 if (This
->output
.unk
)
336 IUnknown_Release(This
->output
.unk
);
337 SysFreeString(This
->outstr
);
339 LIST_FOR_EACH_ENTRY_SAFE(par
, par2
, &This
->params
.list
, struct xslprocessor_par
, entry
)
340 xslprocessor_par_free(&This
->params
, par
);
342 IXSLTemplate_Release(&This
->stylesheet
->IXSLTemplate_iface
);
349 static HRESULT WINAPI
xslprocessor_GetTypeInfoCount( IXSLProcessor
*iface
, UINT
* pctinfo
)
351 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
352 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
355 static HRESULT WINAPI
xslprocessor_GetTypeInfo(
356 IXSLProcessor
*iface
,
357 UINT iTInfo
, LCID lcid
,
358 ITypeInfo
** ppTInfo
)
360 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
361 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
362 iTInfo
, lcid
, ppTInfo
);
365 static HRESULT WINAPI
xslprocessor_GetIDsOfNames(
366 IXSLProcessor
*iface
,
367 REFIID riid
, LPOLESTR
* rgszNames
,
368 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
370 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
371 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
372 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
375 static HRESULT WINAPI
xslprocessor_Invoke(
376 IXSLProcessor
*iface
,
377 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
378 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
379 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
381 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
382 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
383 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
386 static HRESULT WINAPI
xslprocessor_put_input( IXSLProcessor
*iface
, VARIANT input
)
388 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
389 IXMLDOMNode
*input_node
;
392 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&input
));
394 /* try IXMLDOMNode directly first */
395 if (V_VT(&input
) == VT_UNKNOWN
)
396 hr
= IUnknown_QueryInterface(V_UNKNOWN(&input
), &IID_IXMLDOMNode
, (void**)&input_node
);
397 else if (V_VT(&input
) == VT_DISPATCH
)
398 hr
= IDispatch_QueryInterface(V_DISPATCH(&input
), &IID_IXMLDOMNode
, (void**)&input_node
);
401 IXMLDOMDocument
*doc
;
403 hr
= dom_document_create(MSXML_DEFAULT
, (void **)&doc
);
408 hr
= IXMLDOMDocument_load(doc
, input
, &b
);
410 hr
= IXMLDOMDocument_QueryInterface(doc
, &IID_IXMLDOMNode
, (void**)&input_node
);
411 IXMLDOMDocument_Release(doc
);
417 if (This
->input
) IXMLDOMNode_Release(This
->input
);
418 This
->input
= input_node
;
424 static HRESULT WINAPI
xslprocessor_get_input( IXSLProcessor
*iface
, VARIANT
*input
)
426 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
428 FIXME("(%p)->(%p): stub\n", This
, input
);
432 static HRESULT WINAPI
xslprocessor_get_ownerTemplate(
433 IXSLProcessor
*iface
,
434 IXSLTemplate
**template)
436 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
438 FIXME("(%p)->(%p): stub\n", This
, template);
442 static HRESULT WINAPI
xslprocessor_setStartMode(
443 IXSLProcessor
*iface
,
447 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
449 FIXME("(%p)->(%s %s): stub\n", This
, debugstr_w(p
), debugstr_w(uri
));
453 static HRESULT WINAPI
xslprocessor_get_startMode(
454 IXSLProcessor
*iface
,
457 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
459 FIXME("(%p)->(%p): stub\n", This
, p
);
463 static HRESULT WINAPI
xslprocessor_get_startModeURI(
464 IXSLProcessor
*iface
,
467 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
469 FIXME("(%p)->(%p): stub\n", This
, uri
);
473 static HRESULT WINAPI
xslprocessor_put_output(
474 IXSLProcessor
*iface
,
477 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
478 enum output_type output_type
= PROCESSOR_OUTPUT_NOT_SET
;
479 IUnknown
*output
= NULL
;
482 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&var
));
490 if (!V_UNKNOWN(&var
))
493 output_type
= PROCESSOR_OUTPUT_STREAM
;
494 hr
= IUnknown_QueryInterface(V_UNKNOWN(&var
), &IID_IStream
, (void **)&output
);
496 hr
= IUnknown_QueryInterface(V_UNKNOWN(&var
), &IID_ISequentialStream
, (void **)&output
);
499 output_type
= PROCESSOR_OUTPUT_RESPONSE
;
500 hr
= IUnknown_QueryInterface(V_UNKNOWN(&var
), &IID_IResponse
, (void **)&output
);
504 output_type
= PROCESSOR_OUTPUT_PERSISTSTREAM
;
505 hr
= IUnknown_QueryInterface(V_UNKNOWN(&var
), &IID_IPersistStream
, (void **)&output
);
508 hr
= IUnknown_QueryInterface(V_UNKNOWN(&var
), &IID_IPersistStreamInit
, (void **)&output
);
511 output_type
= PROCESSOR_OUTPUT_NOT_SET
;
512 WARN("failed to get output interface, hr %#lx.\n", hr
);
516 FIXME("output type %d not handled\n", V_VT(&var
));
522 if (This
->output
.unk
)
523 IUnknown_Release(This
->output
.unk
);
524 This
->output
.unk
= output
;
525 This
->output_type
= output_type
;
531 static HRESULT WINAPI
xslprocessor_get_output(
532 IXSLProcessor
*iface
,
535 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
537 TRACE("(%p)->(%p)\n", This
, output
);
539 if (!output
) return E_INVALIDARG
;
541 if (This
->output
.unk
)
543 V_VT(output
) = VT_UNKNOWN
;
544 V_UNKNOWN(output
) = This
->output
.unk
;
545 IUnknown_AddRef(This
->output
.unk
);
547 else if (This
->outstr
)
549 V_VT(output
) = VT_BSTR
;
550 V_BSTR(output
) = SysAllocString(This
->outstr
);
553 V_VT(output
) = VT_EMPTY
;
558 static HRESULT WINAPI
xslprocessor_transform(
559 IXSLProcessor
*iface
,
562 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
563 ISequentialStream
*stream
= NULL
;
566 TRACE("(%p)->(%p)\n", This
, ret
);
571 if (This
->output_type
== PROCESSOR_OUTPUT_STREAM
)
573 stream
= This
->output
.stream
;
574 ISequentialStream_AddRef(stream
);
576 else if (This
->output_type
== PROCESSOR_OUTPUT_PERSISTSTREAM
||
577 This
->output_type
== PROCESSOR_OUTPUT_RESPONSE
)
579 if (FAILED(hr
= CreateStreamOnHGlobal(NULL
, TRUE
, (IStream
**)&stream
)))
583 SysFreeString(This
->outstr
);
585 hr
= node_transform_node_params(get_node_obj(This
->input
), This
->stylesheet
->node
,
586 &This
->outstr
, stream
, &This
->params
);
589 IStream
*src
= (IStream
*)stream
;
591 switch (This
->output_type
)
593 case PROCESSOR_OUTPUT_PERSISTSTREAM
:
597 /* for IPersistStream* output seekable stream is used */
599 IStream_Seek(src
, zero
, STREAM_SEEK_SET
, NULL
);
600 hr
= IPersistStream_Load(This
->output
.persiststream
, src
);
603 case PROCESSOR_OUTPUT_RESPONSE
:
605 SAFEARRAYBOUND bound
;
612 if (FAILED(hr
= GetHGlobalFromStream(src
, &hglobal
)))
614 size
= GlobalSize(hglobal
);
617 bound
.cElements
= size
;
618 if (!(array
= SafeArrayCreate(VT_UI1
, 1, &bound
)))
621 V_VT(&bin
) = VT_ARRAY
| VT_UI1
;
622 V_ARRAY(&bin
) = array
;
624 hr
= SafeArrayAccessData(array
, &dest
);
627 void *data
= GlobalLock(hglobal
);
628 memcpy(dest
, data
, size
);
629 GlobalUnlock(hglobal
);
630 SafeArrayUnaccessData(array
);
632 IResponse_BinaryWrite(This
->output
.response
, bin
);
644 ISequentialStream_Release(stream
);
646 *ret
= hr
== S_OK
? VARIANT_TRUE
: VARIANT_FALSE
;
650 static HRESULT WINAPI
xslprocessor_reset( IXSLProcessor
*iface
)
652 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
654 FIXME("(%p): stub\n", This
);
658 static HRESULT WINAPI
xslprocessor_get_readyState(
659 IXSLProcessor
*iface
,
662 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
664 FIXME("(%p)->(%p): stub\n", This
, state
);
668 static HRESULT
xslprocessor_set_parvalue(const VARIANT
*var
, struct xslprocessor_par
*par
)
676 par
->value
= SysAllocString(V_BSTR(var
));
677 if (!par
->value
) hr
= E_OUTOFMEMORY
;
681 FIXME("value type %d not handled\n", V_VT(var
));
688 static HRESULT WINAPI
xslprocessor_addParameter(
689 IXSLProcessor
*iface
,
694 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
695 struct xslprocessor_par
*cur
, *par
= NULL
;
698 TRACE("(%p)->(%s %s %s)\n", This
, debugstr_w(p
), debugstr_variant(&var
),
702 FIXME("namespace uri is not supported\n");
704 /* search for existing parameter first */
705 LIST_FOR_EACH_ENTRY(cur
, &This
->params
.list
, struct xslprocessor_par
, entry
)
707 if (!wcscmp(cur
->name
, p
))
714 /* override with new value or add new parameter */
717 if (V_VT(&var
) == VT_NULL
|| V_VT(&var
) == VT_EMPTY
)
719 /* remove parameter */
720 xslprocessor_par_free(&This
->params
, par
);
723 SysFreeString(par
->value
);
729 par
= malloc(sizeof(struct xslprocessor_par
));
730 if (!par
) return E_OUTOFMEMORY
;
732 par
->name
= SysAllocString(p
);
736 return E_OUTOFMEMORY
;
738 list_add_tail(&This
->params
.list
, &par
->entry
);
739 This
->params
.count
++;
742 hr
= xslprocessor_set_parvalue(&var
, par
);
744 xslprocessor_par_free(&This
->params
, par
);
749 static HRESULT WINAPI
xslprocessor_addObject(
750 IXSLProcessor
*iface
,
754 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
756 FIXME("(%p)->(%p %s): stub\n", This
, obj
, debugstr_w(uri
));
760 static HRESULT WINAPI
xslprocessor_get_stylesheet(
761 IXSLProcessor
*iface
,
764 xslprocessor
*This
= impl_from_IXSLProcessor( iface
);
766 FIXME("(%p)->(%p): stub\n", This
, node
);
770 static const struct IXSLProcessorVtbl XSLProcessorVtbl
=
772 xslprocessor_QueryInterface
,
774 xslprocessor_Release
,
775 xslprocessor_GetTypeInfoCount
,
776 xslprocessor_GetTypeInfo
,
777 xslprocessor_GetIDsOfNames
,
779 xslprocessor_put_input
,
780 xslprocessor_get_input
,
781 xslprocessor_get_ownerTemplate
,
782 xslprocessor_setStartMode
,
783 xslprocessor_get_startMode
,
784 xslprocessor_get_startModeURI
,
785 xslprocessor_put_output
,
786 xslprocessor_get_output
,
787 xslprocessor_transform
,
789 xslprocessor_get_readyState
,
790 xslprocessor_addParameter
,
791 xslprocessor_addObject
,
792 xslprocessor_get_stylesheet
795 static const tid_t xslprocessor_iface_tids
[] = {
800 static dispex_static_data_t xslprocessor_dispex
= {
804 xslprocessor_iface_tids
807 HRESULT
XSLProcessor_create(xsltemplate
*template, IXSLProcessor
**ppObj
)
811 TRACE("(%p)\n", ppObj
);
813 This
= malloc(sizeof(*This
));
815 return E_OUTOFMEMORY
;
817 This
->IXSLProcessor_iface
.lpVtbl
= &XSLProcessorVtbl
;
820 This
->output
.unk
= NULL
;
821 This
->output_type
= PROCESSOR_OUTPUT_NOT_SET
;
823 list_init(&This
->params
.list
);
824 This
->params
.count
= 0;
825 This
->stylesheet
= template;
826 IXSLTemplate_AddRef(&template->IXSLTemplate_iface
);
827 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IXSLProcessor_iface
, &xslprocessor_dispex
);
829 *ppObj
= &This
->IXSLProcessor_iface
;
831 TRACE("returning iface %p\n", *ppObj
);