xref: /reactos/dll/win32/msxml3/stylesheet.c (revision bab6b90f)
1 /*
2  *    XSLTemplate/XSLProcessor support
3  *
4  * Copyright 2011 Nikolay Sivov for CodeWeavers
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 #define COBJMACROS
22 
23 #include "config.h"
24 
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 # include <libxml/xmlerror.h>
29 #endif
30 
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "ole2.h"
35 #include "msxml6.h"
36 
37 #include "msxml_private.h"
38 
39 #include "initguid.h"
40 #include "asptlb.h"
41 
42 #include "wine/debug.h"
43 
44 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
45 
46 typedef struct
47 {
48     DispatchEx dispex;
49     IXSLTemplate IXSLTemplate_iface;
50     LONG ref;
51 
52     IXMLDOMNode *node;
53 } xsltemplate;
54 
55 enum output_type
56 {
57     PROCESSOR_OUTPUT_NOT_SET,
58     PROCESSOR_OUTPUT_STREAM,        /* IStream or ISequentialStream */
59     PROCESSOR_OUTPUT_PERSISTSTREAM, /* IPersistStream or IPersistStreamInit */
60     PROCESSOR_OUTPUT_RESPONSE,      /* IResponse */
61 };
62 
63 typedef struct
64 {
65     DispatchEx dispex;
66     IXSLProcessor IXSLProcessor_iface;
67     LONG ref;
68 
69     xsltemplate *stylesheet;
70     IXMLDOMNode *input;
71 
72     union
73     {
74         IUnknown *unk;
75         ISequentialStream *stream;
76         IPersistStream *persiststream;
77         IResponse *response;
78     } output;
79     enum output_type output_type;
80     BSTR outstr;
81 
82     struct xslprocessor_params params;
83 } xslprocessor;
84 
85 static HRESULT XSLProcessor_create(xsltemplate*, IXSLProcessor**);
86 
impl_from_IXSLTemplate(IXSLTemplate * iface)87 static inline xsltemplate *impl_from_IXSLTemplate( IXSLTemplate *iface )
88 {
89     return CONTAINING_RECORD(iface, xsltemplate, IXSLTemplate_iface);
90 }
91 
impl_from_IXSLProcessor(IXSLProcessor * iface)92 static inline xslprocessor *impl_from_IXSLProcessor( IXSLProcessor *iface )
93 {
94     return CONTAINING_RECORD(iface, xslprocessor, IXSLProcessor_iface);
95 }
96 
xslprocessor_par_free(struct xslprocessor_params * params,struct xslprocessor_par * par)97 static void xslprocessor_par_free(struct xslprocessor_params *params, struct xslprocessor_par *par)
98 {
99     params->count--;
100     list_remove(&par->entry);
101     SysFreeString(par->name);
102     SysFreeString(par->value);
103     heap_free(par);
104 }
105 
xsltemplate_set_node(xsltemplate * This,IXMLDOMNode * node)106 static void xsltemplate_set_node( xsltemplate *This, IXMLDOMNode *node )
107 {
108     if (This->node) IXMLDOMNode_Release(This->node);
109     This->node = node;
110     if (node) IXMLDOMNode_AddRef(node);
111 }
112 
xsltemplate_QueryInterface(IXSLTemplate * iface,REFIID riid,void ** ppvObject)113 static HRESULT WINAPI xsltemplate_QueryInterface(
114     IXSLTemplate *iface,
115     REFIID riid,
116     void** ppvObject )
117 {
118     xsltemplate *This = impl_from_IXSLTemplate( iface );
119     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
120 
121     if ( IsEqualGUID( riid, &IID_IXSLTemplate ) ||
122          IsEqualGUID( riid, &IID_IDispatch ) ||
123          IsEqualGUID( riid, &IID_IUnknown ) )
124     {
125         *ppvObject = iface;
126     }
127     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
128     {
129         return *ppvObject ? S_OK : E_NOINTERFACE;
130     }
131     else
132     {
133         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
134         *ppvObject = NULL;
135         return E_NOINTERFACE;
136     }
137 
138     IUnknown_AddRef((IUnknown*)*ppvObject);
139     return S_OK;
140 }
141 
xsltemplate_AddRef(IXSLTemplate * iface)142 static ULONG WINAPI xsltemplate_AddRef( IXSLTemplate *iface )
143 {
144     xsltemplate *This = impl_from_IXSLTemplate( iface );
145     ULONG ref = InterlockedIncrement( &This->ref );
146     TRACE("(%p)->(%d)\n", This, ref);
147     return ref;
148 }
149 
xsltemplate_Release(IXSLTemplate * iface)150 static ULONG WINAPI xsltemplate_Release( IXSLTemplate *iface )
151 {
152     xsltemplate *This = impl_from_IXSLTemplate( iface );
153     ULONG ref = InterlockedDecrement( &This->ref );
154 
155     TRACE("(%p)->(%d)\n", This, ref);
156     if ( ref == 0 )
157     {
158         if (This->node) IXMLDOMNode_Release( This->node );
159         heap_free( This );
160     }
161 
162     return ref;
163 }
164 
xsltemplate_GetTypeInfoCount(IXSLTemplate * iface,UINT * pctinfo)165 static HRESULT WINAPI xsltemplate_GetTypeInfoCount( IXSLTemplate *iface, UINT* pctinfo )
166 {
167     xsltemplate *This = impl_from_IXSLTemplate( iface );
168     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
169 }
170 
xsltemplate_GetTypeInfo(IXSLTemplate * iface,UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)171 static HRESULT WINAPI xsltemplate_GetTypeInfo(
172     IXSLTemplate *iface,
173     UINT iTInfo, LCID lcid,
174     ITypeInfo** ppTInfo )
175 {
176     xsltemplate *This = impl_from_IXSLTemplate( iface );
177     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
178         iTInfo, lcid, ppTInfo);
179 }
180 
xsltemplate_GetIDsOfNames(IXSLTemplate * iface,REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)181 static HRESULT WINAPI xsltemplate_GetIDsOfNames(
182     IXSLTemplate *iface,
183     REFIID riid, LPOLESTR* rgszNames,
184     UINT cNames, LCID lcid, DISPID* rgDispId )
185 {
186     xsltemplate *This = impl_from_IXSLTemplate( iface );
187     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
188         riid, rgszNames, cNames, lcid, rgDispId);
189 }
190 
xsltemplate_Invoke(IXSLTemplate * iface,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)191 static HRESULT WINAPI xsltemplate_Invoke(
192     IXSLTemplate *iface,
193     DISPID dispIdMember, REFIID riid, LCID lcid,
194     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
195     EXCEPINFO* pExcepInfo, UINT* puArgErr )
196 {
197     xsltemplate *This = impl_from_IXSLTemplate( iface );
198     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
199         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
200 }
201 
xsltemplate_putref_stylesheet(IXSLTemplate * iface,IXMLDOMNode * node)202 static HRESULT WINAPI xsltemplate_putref_stylesheet( IXSLTemplate *iface,
203     IXMLDOMNode *node)
204 {
205     xsltemplate *This = impl_from_IXSLTemplate( iface );
206 
207     TRACE("(%p)->(%p)\n", This, node);
208 
209     if (!node)
210     {
211         xsltemplate_set_node(This, NULL);
212         return S_OK;
213     }
214 
215     /* FIXME: test for document type */
216     xsltemplate_set_node(This, node);
217 
218     return S_OK;
219 }
220 
xsltemplate_get_stylesheet(IXSLTemplate * iface,IXMLDOMNode ** node)221 static HRESULT WINAPI xsltemplate_get_stylesheet( IXSLTemplate *iface,
222     IXMLDOMNode **node)
223 {
224     xsltemplate *This = impl_from_IXSLTemplate( iface );
225 
226     FIXME("(%p)->(%p): stub\n", This, node);
227     return E_NOTIMPL;
228 }
229 
xsltemplate_createProcessor(IXSLTemplate * iface,IXSLProcessor ** processor)230 static HRESULT WINAPI xsltemplate_createProcessor( IXSLTemplate *iface,
231     IXSLProcessor **processor)
232 {
233     xsltemplate *This = impl_from_IXSLTemplate( iface );
234 
235     TRACE("(%p)->(%p)\n", This, processor);
236 
237     if (!processor) return E_INVALIDARG;
238 
239     return XSLProcessor_create(This, processor);
240 }
241 
242 static const struct IXSLTemplateVtbl XSLTemplateVtbl =
243 {
244     xsltemplate_QueryInterface,
245     xsltemplate_AddRef,
246     xsltemplate_Release,
247     xsltemplate_GetTypeInfoCount,
248     xsltemplate_GetTypeInfo,
249     xsltemplate_GetIDsOfNames,
250     xsltemplate_Invoke,
251     xsltemplate_putref_stylesheet,
252     xsltemplate_get_stylesheet,
253     xsltemplate_createProcessor
254 };
255 
256 static const tid_t xsltemplate_iface_tids[] = {
257     IXSLTemplate_tid,
258     0
259 };
260 
261 static dispex_static_data_t xsltemplate_dispex = {
262     NULL,
263     IXSLTemplate_tid,
264     NULL,
265     xsltemplate_iface_tids
266 };
267 
XSLTemplate_create(void ** ppObj)268 HRESULT XSLTemplate_create(void **ppObj)
269 {
270     xsltemplate *This;
271 
272     TRACE("(%p)\n", ppObj);
273 
274     This = heap_alloc( sizeof (*This) );
275     if(!This)
276         return E_OUTOFMEMORY;
277 
278     This->IXSLTemplate_iface.lpVtbl = &XSLTemplateVtbl;
279     This->ref = 1;
280     This->node = NULL;
281     init_dispex(&This->dispex, (IUnknown*)&This->IXSLTemplate_iface, &xsltemplate_dispex);
282 
283     *ppObj = &This->IXSLTemplate_iface;
284 
285     TRACE("returning iface %p\n", *ppObj);
286 
287     return S_OK;
288 }
289 
290 /*** IXSLProcessor ***/
xslprocessor_QueryInterface(IXSLProcessor * iface,REFIID riid,void ** ppvObject)291 static HRESULT WINAPI xslprocessor_QueryInterface(
292     IXSLProcessor *iface,
293     REFIID riid,
294     void** ppvObject )
295 {
296     xslprocessor *This = impl_from_IXSLProcessor( iface );
297     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
298 
299     if ( IsEqualGUID( riid, &IID_IXSLProcessor ) ||
300          IsEqualGUID( riid, &IID_IDispatch ) ||
301          IsEqualGUID( riid, &IID_IUnknown ) )
302     {
303         *ppvObject = iface;
304     }
305     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
306     {
307         return *ppvObject ? S_OK : E_NOINTERFACE;
308     }
309     else
310     {
311         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
312         *ppvObject = NULL;
313         return E_NOINTERFACE;
314     }
315 
316     IUnknown_AddRef((IUnknown*)*ppvObject);
317     return S_OK;
318 }
319 
xslprocessor_AddRef(IXSLProcessor * iface)320 static ULONG WINAPI xslprocessor_AddRef( IXSLProcessor *iface )
321 {
322     xslprocessor *This = impl_from_IXSLProcessor( iface );
323     ULONG ref = InterlockedIncrement( &This->ref );
324     TRACE("(%p)->(%d)\n", This, ref);
325     return ref;
326 }
327 
xslprocessor_Release(IXSLProcessor * iface)328 static ULONG WINAPI xslprocessor_Release( IXSLProcessor *iface )
329 {
330     xslprocessor *This = impl_from_IXSLProcessor( iface );
331     ULONG ref = InterlockedDecrement( &This->ref );
332 
333     TRACE("(%p)->(%d)\n", This, ref);
334     if ( ref == 0 )
335     {
336         struct xslprocessor_par *par, *par2;
337 
338         if (This->input) IXMLDOMNode_Release(This->input);
339         if (This->output.unk)
340             IUnknown_Release(This->output.unk);
341         SysFreeString(This->outstr);
342 
343         LIST_FOR_EACH_ENTRY_SAFE(par, par2, &This->params.list, struct xslprocessor_par, entry)
344             xslprocessor_par_free(&This->params, par);
345 
346         IXSLTemplate_Release(&This->stylesheet->IXSLTemplate_iface);
347         heap_free( This );
348     }
349 
350     return ref;
351 }
352 
xslprocessor_GetTypeInfoCount(IXSLProcessor * iface,UINT * pctinfo)353 static HRESULT WINAPI xslprocessor_GetTypeInfoCount( IXSLProcessor *iface, UINT* pctinfo )
354 {
355     xslprocessor *This = impl_from_IXSLProcessor( iface );
356     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
357 }
358 
xslprocessor_GetTypeInfo(IXSLProcessor * iface,UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)359 static HRESULT WINAPI xslprocessor_GetTypeInfo(
360     IXSLProcessor *iface,
361     UINT iTInfo, LCID lcid,
362     ITypeInfo** ppTInfo )
363 {
364     xslprocessor *This = impl_from_IXSLProcessor( iface );
365     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
366         iTInfo, lcid, ppTInfo);
367 }
368 
xslprocessor_GetIDsOfNames(IXSLProcessor * iface,REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)369 static HRESULT WINAPI xslprocessor_GetIDsOfNames(
370     IXSLProcessor *iface,
371     REFIID riid, LPOLESTR* rgszNames,
372     UINT cNames, LCID lcid, DISPID* rgDispId )
373 {
374     xslprocessor *This = impl_from_IXSLProcessor( iface );
375     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
376         riid, rgszNames, cNames, lcid, rgDispId);
377 }
378 
xslprocessor_Invoke(IXSLProcessor * iface,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)379 static HRESULT WINAPI xslprocessor_Invoke(
380     IXSLProcessor *iface,
381     DISPID dispIdMember, REFIID riid, LCID lcid,
382     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
383     EXCEPINFO* pExcepInfo, UINT* puArgErr )
384 {
385     xslprocessor *This = impl_from_IXSLProcessor( iface );
386     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
387         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
388 }
389 
xslprocessor_put_input(IXSLProcessor * iface,VARIANT input)390 static HRESULT WINAPI xslprocessor_put_input( IXSLProcessor *iface, VARIANT input )
391 {
392     xslprocessor *This = impl_from_IXSLProcessor( iface );
393     IXMLDOMNode *input_node;
394     HRESULT hr;
395 
396     TRACE("(%p)->(%s)\n", This, debugstr_variant(&input));
397 
398     /* try IXMLDOMNode directly first */
399     if (V_VT(&input) == VT_UNKNOWN)
400         hr = IUnknown_QueryInterface(V_UNKNOWN(&input), &IID_IXMLDOMNode, (void**)&input_node);
401     else if (V_VT(&input) == VT_DISPATCH)
402         hr = IDispatch_QueryInterface(V_DISPATCH(&input), &IID_IXMLDOMNode, (void**)&input_node);
403     else
404     {
405         IXMLDOMDocument *doc;
406 
407         hr = DOMDocument_create(MSXML_DEFAULT, (void**)&doc);
408         if (hr == S_OK)
409         {
410             VARIANT_BOOL b;
411 
412             hr = IXMLDOMDocument_load(doc, input, &b);
413             if (hr == S_OK)
414                 hr = IXMLDOMDocument_QueryInterface(doc, &IID_IXMLDOMNode, (void**)&input_node);
415             IXMLDOMDocument_Release(doc);
416         }
417     }
418 
419     if (hr == S_OK)
420     {
421         if (This->input) IXMLDOMNode_Release(This->input);
422         This->input = input_node;
423     }
424 
425     return hr;
426 }
427 
xslprocessor_get_input(IXSLProcessor * iface,VARIANT * input)428 static HRESULT WINAPI xslprocessor_get_input( IXSLProcessor *iface, VARIANT *input )
429 {
430     xslprocessor *This = impl_from_IXSLProcessor( iface );
431 
432     FIXME("(%p)->(%p): stub\n", This, input);
433     return E_NOTIMPL;
434 }
435 
xslprocessor_get_ownerTemplate(IXSLProcessor * iface,IXSLTemplate ** template)436 static HRESULT WINAPI xslprocessor_get_ownerTemplate(
437     IXSLProcessor *iface,
438     IXSLTemplate **template)
439 {
440     xslprocessor *This = impl_from_IXSLProcessor( iface );
441 
442     FIXME("(%p)->(%p): stub\n", This, template);
443     return E_NOTIMPL;
444 }
445 
xslprocessor_setStartMode(IXSLProcessor * iface,BSTR p,BSTR uri)446 static HRESULT WINAPI xslprocessor_setStartMode(
447     IXSLProcessor *iface,
448     BSTR p,
449     BSTR uri)
450 {
451     xslprocessor *This = impl_from_IXSLProcessor( iface );
452 
453     FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(p), debugstr_w(uri));
454     return E_NOTIMPL;
455 }
456 
xslprocessor_get_startMode(IXSLProcessor * iface,BSTR * p)457 static HRESULT WINAPI xslprocessor_get_startMode(
458     IXSLProcessor *iface,
459     BSTR *p)
460 {
461     xslprocessor *This = impl_from_IXSLProcessor( iface );
462 
463     FIXME("(%p)->(%p): stub\n", This, p);
464     return E_NOTIMPL;
465 }
466 
xslprocessor_get_startModeURI(IXSLProcessor * iface,BSTR * uri)467 static HRESULT WINAPI xslprocessor_get_startModeURI(
468     IXSLProcessor *iface,
469     BSTR *uri)
470 {
471     xslprocessor *This = impl_from_IXSLProcessor( iface );
472 
473     FIXME("(%p)->(%p): stub\n", This, uri);
474     return E_NOTIMPL;
475 }
476 
xslprocessor_put_output(IXSLProcessor * iface,VARIANT var)477 static HRESULT WINAPI xslprocessor_put_output(
478     IXSLProcessor *iface,
479     VARIANT var)
480 {
481     xslprocessor *This = impl_from_IXSLProcessor( iface );
482     enum output_type output_type = PROCESSOR_OUTPUT_NOT_SET;
483     IUnknown *output = NULL;
484     HRESULT hr = S_OK;
485 
486     TRACE("(%p)->(%s)\n", This, debugstr_variant(&var));
487 
488     switch (V_VT(&var))
489     {
490     case VT_EMPTY:
491         break;
492     case VT_UNKNOWN:
493     case VT_DISPATCH:
494         if (!V_UNKNOWN(&var))
495             break;
496 
497         output_type = PROCESSOR_OUTPUT_STREAM;
498         hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_IStream, (void **)&output);
499         if (FAILED(hr))
500             hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_ISequentialStream, (void **)&output);
501         if (FAILED(hr))
502         {
503             output_type = PROCESSOR_OUTPUT_RESPONSE;
504             hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_IResponse, (void **)&output);
505         }
506         if (FAILED(hr))
507         {
508             output_type = PROCESSOR_OUTPUT_PERSISTSTREAM;
509             hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_IPersistStream, (void **)&output);
510         }
511         if (FAILED(hr))
512             hr = IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_IPersistStreamInit, (void **)&output);
513         if (FAILED(hr))
514         {
515             output_type = PROCESSOR_OUTPUT_NOT_SET;
516             WARN("failed to get output interface, 0x%08x\n", hr);
517         }
518         break;
519     default:
520         FIXME("output type %d not handled\n", V_VT(&var));
521         hr = E_FAIL;
522     }
523 
524     if (hr == S_OK)
525     {
526         if (This->output.unk)
527             IUnknown_Release(This->output.unk);
528         This->output.unk = output;
529         This->output_type = output_type;
530     }
531 
532     return hr;
533 }
534 
xslprocessor_get_output(IXSLProcessor * iface,VARIANT * output)535 static HRESULT WINAPI xslprocessor_get_output(
536     IXSLProcessor *iface,
537     VARIANT *output)
538 {
539     xslprocessor *This = impl_from_IXSLProcessor( iface );
540 
541     TRACE("(%p)->(%p)\n", This, output);
542 
543     if (!output) return E_INVALIDARG;
544 
545     if (This->output.unk)
546     {
547         V_VT(output) = VT_UNKNOWN;
548         V_UNKNOWN(output) = This->output.unk;
549         IUnknown_AddRef(This->output.unk);
550     }
551     else if (This->outstr)
552     {
553         V_VT(output) = VT_BSTR;
554         V_BSTR(output) = SysAllocString(This->outstr);
555     }
556     else
557         V_VT(output) = VT_EMPTY;
558 
559     return S_OK;
560 }
561 
xslprocessor_transform(IXSLProcessor * iface,VARIANT_BOOL * ret)562 static HRESULT WINAPI xslprocessor_transform(
563     IXSLProcessor *iface,
564     VARIANT_BOOL  *ret)
565 {
566 #ifdef HAVE_LIBXML2
567     xslprocessor *This = impl_from_IXSLProcessor( iface );
568     ISequentialStream *stream = NULL;
569     HRESULT hr;
570 
571     TRACE("(%p)->(%p)\n", This, ret);
572 
573     if (!ret)
574         return E_INVALIDARG;
575 
576     if (This->output_type == PROCESSOR_OUTPUT_STREAM)
577     {
578         stream = This->output.stream;
579         ISequentialStream_AddRef(stream);
580     }
581     else if (This->output_type == PROCESSOR_OUTPUT_PERSISTSTREAM ||
582             This->output_type == PROCESSOR_OUTPUT_RESPONSE)
583     {
584         if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, (IStream **)&stream)))
585             return hr;
586     }
587 
588     SysFreeString(This->outstr);
589 
590     hr = node_transform_node_params(get_node_obj(This->input), This->stylesheet->node,
591             &This->outstr, stream, &This->params);
592     if (SUCCEEDED(hr))
593     {
594         IStream *src = (IStream *)stream;
595 
596         switch (This->output_type)
597         {
598         case PROCESSOR_OUTPUT_PERSISTSTREAM:
599         {
600             LARGE_INTEGER zero;
601 
602             /* for IPersistStream* output seekable stream is used */
603             zero.QuadPart = 0;
604             IStream_Seek(src, zero, STREAM_SEEK_SET, NULL);
605             hr = IPersistStream_Load(This->output.persiststream, src);
606             break;
607         }
608         case PROCESSOR_OUTPUT_RESPONSE:
609         {
610             SAFEARRAYBOUND bound;
611             SAFEARRAY *array;
612             HGLOBAL hglobal;
613             VARIANT bin;
614             DWORD size;
615             void *dest;
616 
617             if (FAILED(hr = GetHGlobalFromStream(src, &hglobal)))
618                 break;
619             size = GlobalSize(hglobal);
620 
621             bound.lLbound = 0;
622             bound.cElements = size;
623             if (!(array = SafeArrayCreate(VT_UI1, 1, &bound)))
624                 break;
625 
626             V_VT(&bin) = VT_ARRAY | VT_UI1;
627             V_ARRAY(&bin) = array;
628 
629             hr = SafeArrayAccessData(array, &dest);
630             if (hr == S_OK)
631             {
632                 void *data = GlobalLock(hglobal);
633                 memcpy(dest, data, size);
634                 GlobalUnlock(hglobal);
635                 SafeArrayUnaccessData(array);
636 
637                 IResponse_BinaryWrite(This->output.response, bin);
638             }
639 
640             VariantClear(&bin);
641             break;
642         }
643         default:
644             ;
645         }
646     }
647 
648     if (stream)
649         ISequentialStream_Release(stream);
650 
651     *ret = hr == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
652     return hr;
653 #else
654     FIXME("libxml2 is required but wasn't present at compile time\n");
655     return E_NOTIMPL;
656 #endif
657 }
658 
xslprocessor_reset(IXSLProcessor * iface)659 static HRESULT WINAPI xslprocessor_reset( IXSLProcessor *iface )
660 {
661     xslprocessor *This = impl_from_IXSLProcessor( iface );
662 
663     FIXME("(%p): stub\n", This);
664     return E_NOTIMPL;
665 }
666 
xslprocessor_get_readyState(IXSLProcessor * iface,LONG * state)667 static HRESULT WINAPI xslprocessor_get_readyState(
668     IXSLProcessor *iface,
669     LONG *state)
670 {
671     xslprocessor *This = impl_from_IXSLProcessor( iface );
672 
673     FIXME("(%p)->(%p): stub\n", This, state);
674     return E_NOTIMPL;
675 }
676 
xslprocessor_set_parvalue(const VARIANT * var,struct xslprocessor_par * par)677 static HRESULT xslprocessor_set_parvalue(const VARIANT *var, struct xslprocessor_par *par)
678 {
679     HRESULT hr = S_OK;
680 
681     switch (V_VT(var))
682     {
683     case VT_BSTR:
684     {
685         par->value = SysAllocString(V_BSTR(var));
686         if (!par->value) hr = E_OUTOFMEMORY;
687         break;
688     }
689     default:
690         FIXME("value type %d not handled\n", V_VT(var));
691         hr = E_NOTIMPL;
692     }
693 
694     return hr;
695 }
696 
xslprocessor_addParameter(IXSLProcessor * iface,BSTR p,VARIANT var,BSTR uri)697 static HRESULT WINAPI xslprocessor_addParameter(
698     IXSLProcessor *iface,
699     BSTR p,
700     VARIANT var,
701     BSTR uri)
702 {
703     xslprocessor *This = impl_from_IXSLProcessor( iface );
704     struct xslprocessor_par *cur, *par = NULL;
705     HRESULT hr;
706 
707     TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(p), debugstr_variant(&var),
708         debugstr_w(uri));
709 
710     if (uri && *uri)
711         FIXME("namespace uri is not supported\n");
712 
713     /* search for existing parameter first */
714     LIST_FOR_EACH_ENTRY(cur, &This->params.list, struct xslprocessor_par, entry)
715     {
716         if (!strcmpW(cur->name, p))
717         {
718             par = cur;
719             break;
720         }
721     }
722 
723     /* override with new value or add new parameter */
724     if (par)
725     {
726         if (V_VT(&var) == VT_NULL || V_VT(&var) == VT_EMPTY)
727         {
728             /* remove parameter */
729             xslprocessor_par_free(&This->params, par);
730             return S_OK;
731         }
732         SysFreeString(par->value);
733         par->value = NULL;
734     }
735     else
736     {
737         /* new parameter */
738         par = heap_alloc(sizeof(struct xslprocessor_par));
739         if (!par) return E_OUTOFMEMORY;
740 
741         par->name = SysAllocString(p);
742         if (!par->name)
743         {
744             heap_free(par);
745             return E_OUTOFMEMORY;
746         }
747         list_add_tail(&This->params.list, &par->entry);
748         This->params.count++;
749     }
750 
751     hr = xslprocessor_set_parvalue(&var, par);
752     if (FAILED(hr))
753         xslprocessor_par_free(&This->params, par);
754 
755     return hr;
756 }
757 
xslprocessor_addObject(IXSLProcessor * iface,IDispatch * obj,BSTR uri)758 static HRESULT WINAPI xslprocessor_addObject(
759     IXSLProcessor *iface,
760     IDispatch *obj,
761     BSTR uri)
762 {
763     xslprocessor *This = impl_from_IXSLProcessor( iface );
764 
765     FIXME("(%p)->(%p %s): stub\n", This, obj, debugstr_w(uri));
766     return E_NOTIMPL;
767 }
768 
xslprocessor_get_stylesheet(IXSLProcessor * iface,IXMLDOMNode ** node)769 static HRESULT WINAPI xslprocessor_get_stylesheet(
770     IXSLProcessor *iface,
771     IXMLDOMNode  **node)
772 {
773     xslprocessor *This = impl_from_IXSLProcessor( iface );
774 
775     FIXME("(%p)->(%p): stub\n", This, node);
776     return E_NOTIMPL;
777 }
778 
779 static const struct IXSLProcessorVtbl XSLProcessorVtbl =
780 {
781     xslprocessor_QueryInterface,
782     xslprocessor_AddRef,
783     xslprocessor_Release,
784     xslprocessor_GetTypeInfoCount,
785     xslprocessor_GetTypeInfo,
786     xslprocessor_GetIDsOfNames,
787     xslprocessor_Invoke,
788     xslprocessor_put_input,
789     xslprocessor_get_input,
790     xslprocessor_get_ownerTemplate,
791     xslprocessor_setStartMode,
792     xslprocessor_get_startMode,
793     xslprocessor_get_startModeURI,
794     xslprocessor_put_output,
795     xslprocessor_get_output,
796     xslprocessor_transform,
797     xslprocessor_reset,
798     xslprocessor_get_readyState,
799     xslprocessor_addParameter,
800     xslprocessor_addObject,
801     xslprocessor_get_stylesheet
802 };
803 
804 static const tid_t xslprocessor_iface_tids[] = {
805     IXSLProcessor_tid,
806     0
807 };
808 
809 static dispex_static_data_t xslprocessor_dispex = {
810     NULL,
811     IXSLProcessor_tid,
812     NULL,
813     xslprocessor_iface_tids
814 };
815 
XSLProcessor_create(xsltemplate * template,IXSLProcessor ** ppObj)816 HRESULT XSLProcessor_create(xsltemplate *template, IXSLProcessor **ppObj)
817 {
818     xslprocessor *This;
819 
820     TRACE("(%p)\n", ppObj);
821 
822     This = heap_alloc( sizeof (*This) );
823     if(!This)
824         return E_OUTOFMEMORY;
825 
826     This->IXSLProcessor_iface.lpVtbl = &XSLProcessorVtbl;
827     This->ref = 1;
828     This->input = NULL;
829     This->output.unk = NULL;
830     This->output_type = PROCESSOR_OUTPUT_NOT_SET;
831     This->outstr = NULL;
832     list_init(&This->params.list);
833     This->params.count = 0;
834     This->stylesheet = template;
835     IXSLTemplate_AddRef(&template->IXSLTemplate_iface);
836     init_dispex(&This->dispex, (IUnknown*)&This->IXSLProcessor_iface, &xslprocessor_dispex);
837 
838     *ppObj = &This->IXSLProcessor_iface;
839 
840     TRACE("returning iface %p\n", *ppObj);
841 
842     return S_OK;
843 }
844