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