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