msxml3: Add IObjectWithSite support to IXMLHttpRequest.
[wine] / dlls / msxml3 / stylesheet.c
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 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "msxml6.h"
31
32 #include "msxml_private.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
37
38 #ifdef HAVE_LIBXML2
39
40 typedef struct _xsltemplate
41 {
42     IXSLTemplate IXSLTemplate_iface;
43     LONG ref;
44
45     IXMLDOMNode *node;
46 } xsltemplate;
47
48 typedef struct _xslprocessor
49 {
50     IXSLProcessor IXSLProcessor_iface;
51     LONG ref;
52
53     xsltemplate *stylesheet;
54     IXMLDOMNode *input;
55     IStream     *output;
56 } xslprocessor;
57
58 static HRESULT XSLProcessor_create(xsltemplate*, IXSLProcessor**);
59
60 static inline xsltemplate *impl_from_IXSLTemplate( IXSLTemplate *iface )
61 {
62     return CONTAINING_RECORD(iface, xsltemplate, IXSLTemplate_iface);
63 }
64
65 static inline xslprocessor *impl_from_IXSLProcessor( IXSLProcessor *iface )
66 {
67     return CONTAINING_RECORD(iface, xslprocessor, IXSLProcessor_iface);
68 }
69
70 static void xsltemplate_set_node( xsltemplate *This, IXMLDOMNode *node )
71 {
72     if (This->node) IXMLDOMNode_Release(This->node);
73     This->node = node;
74     if (node) IXMLDOMNode_AddRef(node);
75 }
76
77 static HRESULT WINAPI xsltemplate_QueryInterface(
78     IXSLTemplate *iface,
79     REFIID riid,
80     void** ppvObject )
81 {
82     xsltemplate *This = impl_from_IXSLTemplate( iface );
83     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
84
85     if ( IsEqualGUID( riid, &IID_IXSLTemplate ) ||
86          IsEqualGUID( riid, &IID_IDispatch ) ||
87          IsEqualGUID( riid, &IID_IUnknown ) )
88     {
89         *ppvObject = iface;
90     }
91     else
92     {
93         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
94         return E_NOINTERFACE;
95     }
96
97     IUnknown_AddRef((IUnknown*)*ppvObject);
98     return S_OK;
99 }
100
101 static ULONG WINAPI xsltemplate_AddRef( IXSLTemplate *iface )
102 {
103     xsltemplate *This = impl_from_IXSLTemplate( iface );
104     return InterlockedIncrement( &This->ref );
105 }
106
107 static ULONG WINAPI xsltemplate_Release( IXSLTemplate *iface )
108 {
109     xsltemplate *This = impl_from_IXSLTemplate( iface );
110     ULONG ref;
111
112     ref = InterlockedDecrement( &This->ref );
113     if ( ref == 0 )
114     {
115         if (This->node) IXMLDOMNode_Release( This->node );
116         heap_free( This );
117     }
118
119     return ref;
120 }
121
122 static HRESULT WINAPI xsltemplate_GetTypeInfoCount( IXSLTemplate *iface, UINT* pctinfo )
123 {
124     xsltemplate *This = impl_from_IXSLTemplate( iface );
125
126     TRACE("(%p)->(%p)\n", This, pctinfo);
127
128     *pctinfo = 1;
129     return S_OK;
130 }
131
132 static HRESULT WINAPI xsltemplate_GetTypeInfo(
133     IXSLTemplate *iface,
134     UINT iTInfo, LCID lcid,
135     ITypeInfo** ppTInfo )
136 {
137     xsltemplate *This = impl_from_IXSLTemplate( iface );
138
139     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
140
141     return get_typeinfo(IXSLTemplate_tid, ppTInfo);
142 }
143
144 static HRESULT WINAPI xsltemplate_GetIDsOfNames(
145     IXSLTemplate *iface,
146     REFIID riid, LPOLESTR* rgszNames,
147     UINT cNames, LCID lcid, DISPID* rgDispId )
148 {
149     xsltemplate *This = impl_from_IXSLTemplate( iface );
150     ITypeInfo *typeinfo;
151     HRESULT hr;
152
153     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
154           lcid, rgDispId);
155
156     if(!rgszNames || cNames == 0 || !rgDispId)
157         return E_INVALIDARG;
158
159     hr = get_typeinfo(IXSLTemplate_tid, &typeinfo);
160     if(SUCCEEDED(hr))
161     {
162         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
163         ITypeInfo_Release(typeinfo);
164     }
165
166     return hr;
167 }
168
169 static HRESULT WINAPI xsltemplate_Invoke(
170     IXSLTemplate *iface,
171     DISPID dispIdMember, REFIID riid, LCID lcid,
172     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
173     EXCEPINFO* pExcepInfo, UINT* puArgErr )
174 {
175     xsltemplate *This = impl_from_IXSLTemplate( iface );
176     ITypeInfo *typeinfo;
177     HRESULT hr;
178
179     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
180           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
181
182     hr = get_typeinfo(IXSLTemplate_tid, &typeinfo);
183     if(SUCCEEDED(hr))
184     {
185        hr = ITypeInfo_Invoke(typeinfo, &This->IXSLTemplate_iface, dispIdMember,
186                 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
187         ITypeInfo_Release(typeinfo);
188     }
189
190     return hr;
191 }
192
193 static HRESULT WINAPI xsltemplate_putref_stylesheet( IXSLTemplate *iface,
194     IXMLDOMNode *node)
195 {
196     xsltemplate *This = impl_from_IXSLTemplate( iface );
197
198     TRACE("(%p)->(%p)\n", This, node);
199
200     if (!node)
201     {
202         xsltemplate_set_node(This, NULL);
203         return S_OK;
204     }
205
206     /* FIXME: test for document type */
207     xsltemplate_set_node(This, node);
208
209     return S_OK;
210 }
211
212 static HRESULT WINAPI xsltemplate_get_stylesheet( IXSLTemplate *iface,
213     IXMLDOMNode **node)
214 {
215     xsltemplate *This = impl_from_IXSLTemplate( iface );
216
217     FIXME("(%p)->(%p): stub\n", This, node);
218     return E_NOTIMPL;
219 }
220
221 static HRESULT WINAPI xsltemplate_createProcessor( IXSLTemplate *iface,
222     IXSLProcessor **processor)
223 {
224     xsltemplate *This = impl_from_IXSLTemplate( iface );
225
226     TRACE("(%p)->(%p)\n", This, processor);
227
228     if (!processor) return E_INVALIDARG;
229
230     return XSLProcessor_create(This, processor);
231 }
232
233 static const struct IXSLTemplateVtbl xsltemplate_vtbl =
234 {
235     xsltemplate_QueryInterface,
236     xsltemplate_AddRef,
237     xsltemplate_Release,
238     xsltemplate_GetTypeInfoCount,
239     xsltemplate_GetTypeInfo,
240     xsltemplate_GetIDsOfNames,
241     xsltemplate_Invoke,
242
243     xsltemplate_putref_stylesheet,
244     xsltemplate_get_stylesheet,
245     xsltemplate_createProcessor
246 };
247
248 HRESULT XSLTemplate_create(IUnknown *pUnkOuter, void **ppObj)
249 {
250     xsltemplate *This;
251
252     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
253
254     if(pUnkOuter) FIXME("support aggregation, outer\n");
255
256     This = heap_alloc( sizeof (*This) );
257     if(!This)
258         return E_OUTOFMEMORY;
259
260     This->IXSLTemplate_iface.lpVtbl = &xsltemplate_vtbl;
261     This->ref = 1;
262     This->node = NULL;
263
264     *ppObj = &This->IXSLTemplate_iface;
265
266     TRACE("returning iface %p\n", *ppObj);
267
268     return S_OK;
269 }
270
271 /*** IXSLProcessor ***/
272 static HRESULT WINAPI xslprocessor_QueryInterface(
273     IXSLProcessor *iface,
274     REFIID riid,
275     void** ppvObject )
276 {
277     xslprocessor *This = impl_from_IXSLProcessor( iface );
278     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
279
280     if ( IsEqualGUID( riid, &IID_IXSLProcessor ) ||
281          IsEqualGUID( riid, &IID_IDispatch ) ||
282          IsEqualGUID( riid, &IID_IUnknown ) )
283     {
284         *ppvObject = iface;
285     }
286     else
287     {
288         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
289         return E_NOINTERFACE;
290     }
291
292     IUnknown_AddRef((IUnknown*)*ppvObject);
293     return S_OK;
294 }
295
296 static ULONG WINAPI xslprocessor_AddRef( IXSLProcessor *iface )
297 {
298     xslprocessor *This = impl_from_IXSLProcessor( iface );
299     return InterlockedIncrement( &This->ref );
300 }
301
302 static ULONG WINAPI xslprocessor_Release( IXSLProcessor *iface )
303 {
304     xslprocessor *This = impl_from_IXSLProcessor( iface );
305     ULONG ref;
306
307     ref = InterlockedDecrement( &This->ref );
308     if ( ref == 0 )
309     {
310         if (This->input) IXMLDOMNode_Release(This->input);
311         if (This->output) IStream_Release(This->output);
312         IXSLTemplate_Release(&This->stylesheet->IXSLTemplate_iface);
313         heap_free( This );
314     }
315
316     return ref;
317 }
318
319 static HRESULT WINAPI xslprocessor_GetTypeInfoCount( IXSLProcessor *iface, UINT* pctinfo )
320 {
321     xslprocessor *This = impl_from_IXSLProcessor( iface );
322
323     TRACE("(%p)->(%p)\n", This, pctinfo);
324
325     *pctinfo = 1;
326     return S_OK;
327 }
328
329 static HRESULT WINAPI xslprocessor_GetTypeInfo(
330     IXSLProcessor *iface,
331     UINT iTInfo, LCID lcid,
332     ITypeInfo** ppTInfo )
333 {
334     xslprocessor *This = impl_from_IXSLProcessor( iface );
335
336     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
337
338     return get_typeinfo(IXSLProcessor_tid, ppTInfo);
339 }
340
341 static HRESULT WINAPI xslprocessor_GetIDsOfNames(
342     IXSLProcessor *iface,
343     REFIID riid, LPOLESTR* rgszNames,
344     UINT cNames, LCID lcid, DISPID* rgDispId )
345 {
346     xslprocessor *This = impl_from_IXSLProcessor( iface );
347     ITypeInfo *typeinfo;
348     HRESULT hr;
349
350     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
351           lcid, rgDispId);
352
353     if(!rgszNames || cNames == 0 || !rgDispId)
354         return E_INVALIDARG;
355
356     hr = get_typeinfo(IXSLProcessor_tid, &typeinfo);
357     if(SUCCEEDED(hr))
358     {
359         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
360         ITypeInfo_Release(typeinfo);
361     }
362
363     return hr;
364 }
365
366 static HRESULT WINAPI xslprocessor_Invoke(
367     IXSLProcessor *iface,
368     DISPID dispIdMember, REFIID riid, LCID lcid,
369     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
370     EXCEPINFO* pExcepInfo, UINT* puArgErr )
371 {
372     xslprocessor *This = impl_from_IXSLProcessor( iface );
373     ITypeInfo *typeinfo;
374     HRESULT hr;
375
376     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
377           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
378
379     hr = get_typeinfo(IXSLProcessor_tid, &typeinfo);
380     if(SUCCEEDED(hr))
381     {
382        hr = ITypeInfo_Invoke(typeinfo, &This->IXSLProcessor_iface, dispIdMember,
383                 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
384         ITypeInfo_Release(typeinfo);
385     }
386
387     return hr;
388 }
389
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(&CLSID_DOMDocument, NULL, (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
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
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
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, wine_dbgstr_w(p), wine_dbgstr_w(uri));
454     return E_NOTIMPL;
455 }
456
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
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
477 static HRESULT WINAPI xslprocessor_put_output(
478     IXSLProcessor *iface,
479     VARIANT output)
480 {
481     xslprocessor *This = impl_from_IXSLProcessor( iface );
482     IStream *stream;
483     HRESULT hr;
484
485     FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&output));
486
487     switch (V_VT(&output))
488     {
489       case VT_EMPTY:
490         stream = NULL;
491         hr = S_OK;
492         break;
493       case VT_UNKNOWN:
494         hr = IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_IStream, (void**)&stream);
495         break;
496       default:
497         hr = E_FAIL;
498     }
499
500     if (hr == S_OK)
501     {
502         if (This->output) IStream_Release(This->output);
503         This->output = stream;
504     }
505
506     return hr;
507 }
508
509 static HRESULT WINAPI xslprocessor_get_output(
510     IXSLProcessor *iface,
511     VARIANT *output)
512 {
513     xslprocessor *This = impl_from_IXSLProcessor( iface );
514
515     FIXME("(%p)->(%p): stub\n", This, output);
516     return E_NOTIMPL;
517 }
518
519 static HRESULT WINAPI xslprocessor_transform(
520     IXSLProcessor *iface,
521     VARIANT_BOOL  *ret)
522 {
523     xslprocessor *This = impl_from_IXSLProcessor( iface );
524     HRESULT hr;
525     BSTR p;
526
527     TRACE("(%p)->(%p)\n", This, ret);
528
529     if (!ret) return E_INVALIDARG;
530
531     hr = IXMLDOMNode_transformNode(This->input, This->stylesheet->node, &p);
532     if (hr == S_OK)
533     {
534         ULONG len = 0;
535
536         /* output to stream */
537         hr = IStream_Write(This->output, p, SysStringByteLen(p), &len);
538         *ret = len == SysStringByteLen(p) ? VARIANT_TRUE : VARIANT_FALSE;
539         SysFreeString(p);
540     }
541     else
542         *ret = VARIANT_FALSE;
543
544     return hr;
545 }
546
547 static HRESULT WINAPI xslprocessor_reset( IXSLProcessor *iface )
548 {
549     xslprocessor *This = impl_from_IXSLProcessor( iface );
550
551     FIXME("(%p): stub\n", This);
552     return E_NOTIMPL;
553 }
554
555 static HRESULT WINAPI xslprocessor_get_readyState(
556     IXSLProcessor *iface,
557     LONG *state)
558 {
559     xslprocessor *This = impl_from_IXSLProcessor( iface );
560
561     FIXME("(%p)->(%p): stub\n", This, state);
562     return E_NOTIMPL;
563 }
564
565 static HRESULT WINAPI xslprocessor_addParameter(
566     IXSLProcessor *iface,
567     BSTR p,
568     VARIANT var,
569     BSTR uri)
570 {
571     xslprocessor *This = impl_from_IXSLProcessor( iface );
572
573     FIXME("(%p)->(%s %s): stub\n", This, wine_dbgstr_w(p), wine_dbgstr_w(uri));
574     return E_NOTIMPL;
575 }
576
577 static HRESULT WINAPI xslprocessor_addObject(
578     IXSLProcessor *iface,
579     IDispatch *obj,
580     BSTR uri)
581 {
582     xslprocessor *This = impl_from_IXSLProcessor( iface );
583
584     FIXME("(%p)->(%p %s): stub\n", This, obj, wine_dbgstr_w(uri));
585     return E_NOTIMPL;
586 }
587
588 static HRESULT WINAPI xslprocessor_get_stylesheet(
589     IXSLProcessor *iface,
590     IXMLDOMNode  **node)
591 {
592     xslprocessor *This = impl_from_IXSLProcessor( iface );
593
594     FIXME("(%p)->(%p): stub\n", This, node);
595     return E_NOTIMPL;
596 }
597
598 static const struct IXSLProcessorVtbl xslprocessor_vtbl =
599 {
600     xslprocessor_QueryInterface,
601     xslprocessor_AddRef,
602     xslprocessor_Release,
603     xslprocessor_GetTypeInfoCount,
604     xslprocessor_GetTypeInfo,
605     xslprocessor_GetIDsOfNames,
606     xslprocessor_Invoke,
607
608     xslprocessor_put_input,
609     xslprocessor_get_input,
610     xslprocessor_get_ownerTemplate,
611     xslprocessor_setStartMode,
612     xslprocessor_get_startMode,
613     xslprocessor_get_startModeURI,
614     xslprocessor_put_output,
615     xslprocessor_get_output,
616     xslprocessor_transform,
617     xslprocessor_reset,
618     xslprocessor_get_readyState,
619     xslprocessor_addParameter,
620     xslprocessor_addObject,
621     xslprocessor_get_stylesheet
622 };
623
624 HRESULT XSLProcessor_create(xsltemplate *template, IXSLProcessor **ppObj)
625 {
626     xslprocessor *This;
627
628     TRACE("(%p)\n", ppObj);
629
630     This = heap_alloc( sizeof (*This) );
631     if(!This)
632         return E_OUTOFMEMORY;
633
634     This->IXSLProcessor_iface.lpVtbl = &xslprocessor_vtbl;
635     This->ref = 1;
636     This->input = NULL;
637     This->output = NULL;
638     This->stylesheet = template;
639     IXSLTemplate_AddRef(&template->IXSLTemplate_iface);
640
641     *ppObj = &This->IXSLProcessor_iface;
642
643     TRACE("returning iface %p\n", *ppObj);
644
645     return S_OK;
646 }
647
648 #else
649
650 HRESULT XSLTemplate_create(IUnknown *pUnkOuter, void **ppObj)
651 {
652     MESSAGE("This program tried to use a XSLTemplate object, but\n"
653             "libxml2 support was not present at compile time.\n");
654     return E_NOTIMPL;
655 }
656
657 #endif