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 87 static inline xsltemplate *impl_from_IXSLTemplate( IXSLTemplate *iface ) 88 { 89 return CONTAINING_RECORD(iface, xsltemplate, IXSLTemplate_iface); 90 } 91 92 static inline xslprocessor *impl_from_IXSLProcessor( IXSLProcessor *iface ) 93 { 94 return CONTAINING_RECORD(iface, xslprocessor, IXSLProcessor_iface); 95 } 96 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 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 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 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 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 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 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 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 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 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 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 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 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 ***/ 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 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 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 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 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 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 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 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 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, debugstr_w(p), debugstr_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 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 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 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 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 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 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 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 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 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 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