1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <comphelper/DisableInteractionHelper.hxx>
22 #include <comphelper/documentinfo.hxx>
23 
24 #include <cppuhelper/implementationentry.hxx>
25 #include <cppuhelper/exc_hlp.hxx>
26 #include <cppuhelper/factory.hxx>
27 #include <cppuhelper/supportsservice.hxx>
28 #include <tools/diagnose_ex.h>
29 
30 #include <com/sun/star/frame/XModel.hpp>
31 #include <com/sun/star/lang/EventObject.hpp>
32 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
33 #include <com/sun/star/document/XScriptInvocationContext.hpp>
34 #include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
35 #include <com/sun/star/uri/XUriReference.hpp>
36 #include <com/sun/star/uri/UriReferenceFactory.hpp>
37 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
38 
39 #include <com/sun/star/deployment/XPackage.hpp>
40 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
41 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
42 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
43 
44 #include <util/MiscUtils.hxx>
45 #include <sal/log.hxx>
46 
47 #include "ActiveMSPList.hxx"
48 #include "MasterScriptProvider.hxx"
49 #include "URIHelper.hxx"
50 
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::script;
54 using namespace ::com::sun::star::document;
55 using namespace ::sf_misc;
56 
57 namespace func_provider
58 {
59 
60 static bool endsWith( const OUString& target, const OUString& item )
61 {
62     sal_Int32 index = target.indexOf( item );
63     return index != -1  &&
64            index == ( target.getLength() - item.getLength() );
65 }
66 
67 /* should be available in some central location. */
68 
69 // XScriptProvider implementation
70 
71 
72 MasterScriptProvider::MasterScriptProvider( const Reference< XComponentContext > & xContext ):
73         m_xContext( xContext ), m_bIsValid( false ), m_bInitialised( false ),
74         m_bIsPkgMSP( false )
75 {
76     ENSURE_OR_THROW( m_xContext.is(), "MasterScriptProvider::MasterScriptProvider: No context available\n" );
77     m_xMgr = m_xContext->getServiceManager();
78     ENSURE_OR_THROW( m_xMgr.is(), "MasterScriptProvider::MasterScriptProvider: No service manager available\n" );
79     m_bIsValid = true;
80 }
81 
82 
83 MasterScriptProvider::~MasterScriptProvider()
84 {
85 }
86 
87 
88 void SAL_CALL MasterScriptProvider::initialize( const Sequence < Any >& args )
89 {
90     if ( m_bInitialised )
91         return;
92 
93     m_bIsValid = false;
94 
95     sal_Int32 len = args.getLength();
96     if ( len > 1  )
97     {
98         throw RuntimeException(
99             "MasterScriptProvider::initialize: invalid number of arguments" );
100     }
101 
102     Sequence< Any > invokeArgs( len );
103 
104     if ( len != 0 )
105     {
106         // check if first parameter is a string
107         // if it is, this implies that this is a MSP created
108         // with a user or share ctx ( used for browse functionality )
109 
110         if ( args[ 0 ] >>= m_sCtxString )
111         {
112             invokeArgs[ 0  ] = args[ 0 ];
113             if ( m_sCtxString.startsWith( "vnd.sun.star.tdoc" ) )
114             {
115                 m_xModel =  MiscUtils::tDocUrlToModel( m_sCtxString );
116             }
117         }
118         else if ( args[ 0 ] >>= m_xInvocationContext )
119         {
120             m_xModel.set( m_xInvocationContext->getScriptContainer(), UNO_QUERY_THROW );
121         }
122         else
123         {
124             args[ 0 ] >>= m_xModel;
125         }
126 
127         if ( m_xModel.is() )
128         {
129             // from the arguments, we were able to deduce a model. That alone doesn't
130             // suffice, we also need an XEmbeddedScripts which actually indicates support
131             // for embedding scripts
132             Reference< XEmbeddedScripts > xScripts( m_xModel, UNO_QUERY );
133             if ( !xScripts.is() )
134             {
135                 throw lang::IllegalArgumentException(
136                     "The given document does not support embedding scripts into it, and cannot be associated with such a document.",
137                     *this,
138                     1
139                 );
140             }
141 
142             try
143             {
144                 m_sCtxString =  MiscUtils::xModelToTdocUrl( m_xModel, m_xContext );
145             }
146             catch ( const Exception& )
147             {
148                 Any aError( ::cppu::getCaughtException() );
149 
150                 OUStringBuffer buf;
151                 buf.append( "MasterScriptProvider::initialize: caught " );
152                 buf.append( aError.getValueTypeName() );
153                 buf.append( ":" );
154 
155                 Exception aException;
156                 aError >>= aException;
157                 buf.append     ( aException.Message );
158                 throw lang::WrappedTargetException( buf.makeStringAndClear(), *this, aError );
159             }
160 
161             if ( m_xInvocationContext.is() && m_xInvocationContext != m_xModel )
162                 invokeArgs[ 0 ] <<= m_xInvocationContext;
163             else
164                 invokeArgs[ 0 ] <<= m_sCtxString;
165         }
166 
167         OUString pkgSpec = "uno_packages";
168         sal_Int32 indexOfPkgSpec = m_sCtxString.lastIndexOf( pkgSpec );
169 
170         // if contex string ends with "uno_packages"
171         if ( indexOfPkgSpec > -1 && m_sCtxString.match( pkgSpec, indexOfPkgSpec ) )
172         {
173             m_bIsPkgMSP = true;
174         }
175         else
176         {
177             m_bIsPkgMSP = false;
178         }
179     }
180     else // no args
181     {
182         // use either scripting context or maybe zero args?
183         invokeArgs = Sequence< Any >( 0 ); // no arguments
184     }
185     m_sAargs = invokeArgs;
186     // don't create pkg mgr MSP for documents, not supported
187     if ( !m_bIsPkgMSP && !m_xModel.is() )
188     {
189         createPkgProvider();
190     }
191 
192     m_bInitialised = true;
193     m_bIsValid = true;
194 }
195 
196 
197 void MasterScriptProvider::createPkgProvider()
198 {
199     try
200     {
201         Any location;
202         location <<= m_sCtxString + ":uno_packages";
203 
204         Reference< provider::XScriptProviderFactory > xFac =
205             provider::theMasterScriptProviderFactory::get( m_xContext );
206 
207         m_xMSPPkg.set(
208             xFac->createScriptProvider( location ), UNO_QUERY_THROW );
209 
210     }
211     catch ( const Exception& e )
212     {
213         SAL_WARN("scripting.provider", "Exception creating MasterScriptProvider for uno_packages in context "
214                 << m_sCtxString << ": " << e );
215     }
216 }
217 
218 
219 Reference< provider::XScript >
220 MasterScriptProvider::getScript( const OUString& scriptURI )
221 {
222     if ( !m_bIsValid )
223     {
224         throw provider::ScriptFrameworkErrorException(
225             "MasterScriptProvider not initialised", Reference< XInterface >(),
226             scriptURI, "",
227             provider::ScriptFrameworkErrorType::UNKNOWN );
228     }
229 
230     // need to get the language from the string
231 
232     Reference< uri::XUriReferenceFactory > xFac ( uri::UriReferenceFactory::create( m_xContext )  );
233 
234     Reference<  uri::XUriReference > uriRef(
235         xFac->parse( scriptURI ), UNO_QUERY );
236 
237     Reference < uri::XVndSunStarScriptUrl > sfUri( uriRef, UNO_QUERY );
238 
239     if ( !uriRef.is() || !sfUri.is() )
240     {
241         throw provider::ScriptFrameworkErrorException(
242             "Incorrect format for Script URI: " + scriptURI,
243             Reference< XInterface >(),
244             scriptURI, "",
245             provider::ScriptFrameworkErrorType::UNKNOWN );
246     }
247 
248     OUString langKey("language");
249     OUString locKey("location");
250 
251     if ( !sfUri->hasParameter( langKey ) ||
252          !sfUri->hasParameter( locKey ) ||
253          ( sfUri->getName().isEmpty()  ) )
254     {
255         throw provider::ScriptFrameworkErrorException(
256             "Incorrect format for Script URI: " + scriptURI,
257             Reference< XInterface >(),
258             scriptURI, "",
259             provider::ScriptFrameworkErrorType::UNKNOWN );
260     }
261 
262     OUString language = sfUri->getParameter( langKey );
263     OUString location = sfUri->getParameter( locKey );
264 
265     // if script us located in uno pkg
266     sal_Int32 index = -1;
267     OUString pkgTag(":uno_packages");
268     // for languages other than basic,  scripts located in uno packages
269     // are merged into the user/share location context.
270     // For other languages the location attribute in script url has the form
271     // location = [user|share]:uno_packages or location :uno_packages/xxxx.uno.pkg
272     // we need to extract the value of location part from the
273     // location attribute of the script, if the script is located in an
274     // uno package then that is the location part up to and including
275     // ":uno_packages", if the script is not in an uno package then the
276     // normal value is used e.g. user or share.
277     // The value extracted will be used to determine if the script is
278     // located in the same location context as this MSP.
279     // For Basic, the language script provider can handle the execution of a
280     // script in any location context
281     if ( ( index = location.indexOf( pkgTag ) ) > -1 )
282     {
283         location = location.copy( 0, index + pkgTag.getLength() );
284     }
285 
286     Reference< provider::XScript > xScript;
287 
288     // If the script location is in the same location context as this
289     // MSP then delete to the language provider controlled by this MSP
290     // ** Special case is BASIC, all calls to getScript will be handled
291     // by the language script provider in the current location context
292     // even if its different
293     if  (   (   location == "document"
294             &&  m_xModel.is()
295             )
296             ||  ( endsWith( m_sCtxString, location ) )
297             ||  ( language == "Basic" )
298          )
299     {
300         Reference< provider::XScriptProvider > xScriptProvider;
301         OUStringBuffer buf( 80 );
302         buf.append( "com.sun.star.script.provider.ScriptProviderFor");
303         buf.append( language );
304         OUString serviceName = buf.makeStringAndClear();
305         if ( !providerCache() )
306         {
307             throw provider::ScriptFrameworkErrorException(
308                 "No LanguageProviders detected",
309                 Reference< XInterface >(),
310                 sfUri->getName(), language,
311                 provider::ScriptFrameworkErrorType::NOTSUPPORTED );
312         }
313 
314         try
315         {
316             xScriptProvider.set(
317                 providerCache()->getProvider( serviceName ),
318                 UNO_QUERY_THROW );
319         }
320         catch( const Exception& e )
321         {
322             throw provider::ScriptFrameworkErrorException(
323                 e.Message, Reference< XInterface >(),
324                 sfUri->getName(), language,
325                 provider::ScriptFrameworkErrorType::NOTSUPPORTED );
326         }
327 
328         xScript=xScriptProvider->getScript( scriptURI );
329     }
330     else
331     {
332         Reference< provider::XScriptProviderFactory > xFac_ =
333             provider::theMasterScriptProviderFactory::get( m_xContext );
334 
335         Reference< provider::XScriptProvider > xSP(
336             xFac_->createScriptProvider( makeAny( location ) ), UNO_QUERY_THROW );
337         xScript = xSP->getScript( scriptURI );
338     }
339 
340     return xScript;
341 }
342 
343 
344 ProviderCache*
345 MasterScriptProvider::providerCache()
346 {
347     if ( !m_pPCache )
348     {
349         ::osl::MutexGuard aGuard( m_mutex );
350         if ( !m_pPCache )
351         {
352             OUString serviceName1 = "com.sun.star.script.provider.ScriptProviderForBasic";
353             Sequence<OUString> blacklist { serviceName1 };
354 
355             if ( !m_bIsPkgMSP )
356             {
357                 m_pPCache.reset( new ProviderCache( m_xContext, m_sAargs ) );
358             }
359             else
360             {
361                 m_pPCache.reset( new ProviderCache( m_xContext, m_sAargs, blacklist ) );
362             }
363         }
364     }
365     return m_pPCache.get();
366 }
367 
368 
369 OUString SAL_CALL
370 MasterScriptProvider::getName()
371 {
372     if ( !m_bIsPkgMSP )
373     {
374         OUString sCtx = getContextString();
375         if ( sCtx.startsWith( "vnd.sun.star.tdoc" ) )
376         {
377             Reference< frame::XModel > xModel = m_xModel;
378             if ( !xModel.is() )
379             {
380                 xModel = MiscUtils::tDocUrlToModel( sCtx );
381             }
382 
383             m_sNodeName = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
384         }
385         else
386         {
387             m_sNodeName = parseLocationName( getContextString() );
388         }
389     }
390     else
391     {
392         m_sNodeName = "uno_packages";
393     }
394     return m_sNodeName;
395 }
396 
397 
398 Sequence< Reference< browse::XBrowseNode > > SAL_CALL
399 MasterScriptProvider::getChildNodes()
400 {
401     Sequence< Reference< provider::XScriptProvider > > providers = providerCache()->getAllProviders();
402 
403     sal_Int32 size = providers.getLength();
404     bool hasPkgs = m_xMSPPkg.is();
405     if ( hasPkgs  )
406     {
407         size++;
408     }
409     Sequence<  Reference< browse::XBrowseNode > > children( size );
410     sal_Int32 provIndex = 0;
411     for ( ; provIndex < providers.getLength(); provIndex++ )
412     {
413         children[ provIndex ].set( providers[ provIndex ], UNO_QUERY );
414     }
415 
416     if ( hasPkgs  )
417     {
418         children[ provIndex ].set( m_xMSPPkg, UNO_QUERY );
419 
420     }
421 
422     return children;
423 }
424 
425 
426 sal_Bool SAL_CALL
427 MasterScriptProvider::hasChildNodes()
428 {
429     return true;
430 }
431 
432 
433 sal_Int16 SAL_CALL
434 MasterScriptProvider::getType()
435 {
436     return browse::BrowseNodeTypes::CONTAINER;
437 }
438 
439 
440 OUString
441 MasterScriptProvider::parseLocationName( const OUString& location )
442 {
443     // strip out the last leaf of location name
444     // e.g. file://dir1/dir2/Blah.sxw - > Blah.sxw
445     OUString temp = location;
446     INetURLObject aURLObj( temp );
447     if ( !aURLObj.HasError() )
448         temp = aURLObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
449     return temp;
450 }
451 
452 namespace
453 {
454 template <typename Proc> bool FindProviderAndApply(ProviderCache& rCache, Proc p)
455 {
456     auto pass = [&rCache, &p]() -> bool
457     {
458         bool bResult = false;
459         for (auto& rProv : rCache.getAllProviders())
460         {
461             Reference<container::XNameContainer> xCont(rProv, UNO_QUERY);
462             if (!xCont.is())
463             {
464                 continue;
465             }
466             try
467             {
468                 bResult = p(xCont);
469                 break;
470             }
471             catch (Exception& e)
472             {
473                 SAL_INFO("scripting.provider", "ignoring " << e);
474             }
475         }
476         return bResult;
477     };
478     bool bSuccess = false;
479     // 1. Try to perform the operation without trying to enable JVM (if disabled)
480     // This allows us to avoid useless user interaction in case when other provider
481     // (not JVM) actually handles the operation.
482     {
483         css::uno::ContextLayer layer(
484             new comphelper::NoEnableJavaInteractionContext(css::uno::getCurrentContext()));
485         bSuccess = pass();
486     }
487     // 2. Now retry asking to enable JVM in case we didn't succeed first time
488     if (!bSuccess)
489     {
490         bSuccess = pass();
491     }
492     return bSuccess;
493 }
494 } // namespace
495 
496 // Register Package
497 void SAL_CALL
498 MasterScriptProvider::insertByName( const OUString& aName, const Any& aElement )
499 {
500     if ( !m_bIsPkgMSP )
501     {
502         if ( !m_xMSPPkg.is() )
503         {
504             throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
505         }
506 
507         Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
508         xCont->insertByName( aName, aElement );
509     }
510     else
511     {
512         Reference< deployment::XPackage > xPkg( aElement, UNO_QUERY );
513         if ( !xPkg.is() )
514         {
515             throw lang::IllegalArgumentException( "Couldn't convert to XPackage",
516                                                       Reference < XInterface > (), 2 );
517         }
518         if ( aName.isEmpty() )
519         {
520             throw lang::IllegalArgumentException( "Name not set!!",
521                                                       Reference < XInterface > (), 1 );
522         }
523         // TODO for library package parse the language, for the moment will try
524         // to get each provider to process the new Package, the first one the succeeds
525         // will terminate processing
526         const bool bSuccess = FindProviderAndApply(
527             *providerCache(), [&aName, &aElement](Reference<container::XNameContainer>& xCont) {
528                 xCont->insertByName(aName, aElement);
529                 return true;
530             });
531         if (!bSuccess)
532         {
533             // No script providers could process the package
534             throw lang::IllegalArgumentException( "Failed to register package for " + aName,
535                 Reference < XInterface > (), 2 );
536         }
537    }
538 }
539 
540 
541 // Revoke Package
542 void SAL_CALL
543 MasterScriptProvider::removeByName( const OUString& Name )
544 {
545     if ( !m_bIsPkgMSP )
546     {
547         if ( !m_xMSPPkg.is() )
548         {
549             throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
550         }
551 
552         Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
553         xCont->removeByName( Name );
554     }
555     else
556     {
557         if ( Name.isEmpty() )
558         {
559             throw lang::IllegalArgumentException( "Name not set!!",
560                                                       Reference < XInterface > (), 1 );
561         }
562         // TODO for Script library package url parse the language,
563         // for the moment will just try to get each provider to process remove/revoke
564         // request, the first one the succeeds will terminate processing
565         const bool bSuccess = FindProviderAndApply(
566             *providerCache(), [&Name](Reference<container::XNameContainer>& xCont) {
567                 xCont->removeByName(Name);
568                 return true;
569             });
570         if (!bSuccess)
571         {
572             // No script providers could process the package
573             throw lang::IllegalArgumentException( "Failed to revoke package for " + Name,
574                                                   Reference < XInterface > (), 1 );
575         }
576 
577     }
578 }
579 
580 
581 void SAL_CALL
582 MasterScriptProvider::replaceByName( const OUString& /*aName*/, const Any& /*aElement*/ )
583 {
584     // TODO needs implementing
585      throw RuntimeException( "replaceByName not implemented!!!!" );
586 }
587 
588 Any SAL_CALL
589 MasterScriptProvider::getByName( const OUString& /*aName*/ )
590 {
591     // TODO needs to be implemented
592     throw RuntimeException( "getByName not implemented!!!!" );
593 }
594 
595 sal_Bool SAL_CALL
596 MasterScriptProvider::hasByName( const OUString& aName )
597 {
598     bool result = false;
599     if ( !m_bIsPkgMSP )
600     {
601         if ( m_xMSPPkg.is() )
602         {
603             Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
604             result = xCont->hasByName( aName );
605         }
606         // If this is a document provider then we shouldn't
607         // have a PackageProvider
608         else if (!m_xModel.is())
609         {
610             throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
611         }
612 
613     }
614     else
615     {
616         if ( aName.isEmpty() )
617         {
618             throw lang::IllegalArgumentException( "Name not set!!",
619                                                       Reference < XInterface > (), 1 );
620         }
621         // TODO for Script library package url parse the language,
622         // for the moment will just try to get each provider to see if the
623         // package exists in any provider, first one that succeed will
624         // terminate the loop
625         result = FindProviderAndApply(
626             *providerCache(), [&aName](Reference<container::XNameContainer>& xCont) {
627                 return xCont->hasByName(aName);
628             });
629     }
630     return result;
631 }
632 
633 
634 Sequence< OUString > SAL_CALL
635 MasterScriptProvider::getElementNames(  )
636 {
637     // TODO needs implementing
638     throw RuntimeException( "getElementNames not implemented!!!!" );
639 }
640 
641 Type SAL_CALL
642 MasterScriptProvider::getElementType(  )
643 {
644     // TODO needs implementing
645     Type t;
646     return t;
647 }
648 
649 sal_Bool SAL_CALL MasterScriptProvider::hasElements(  )
650 {
651     // TODO needs implementing
652     throw RuntimeException( "hasElements not implemented!!!!" );
653 }
654 
655 
656 OUString SAL_CALL MasterScriptProvider::getImplementationName( )
657 {
658     return OUString( "com.sun.star.script.provider.MasterScriptProvider"  );
659 }
660 
661 sal_Bool SAL_CALL MasterScriptProvider::supportsService( const OUString& serviceName )
662 {
663     return cppu::supportsService(this, serviceName);
664 }
665 
666 
667 Sequence< OUString > SAL_CALL MasterScriptProvider::getSupportedServiceNames( )
668 {
669     OUString names[3];
670 
671     names[0] = "com.sun.star.script.provider.MasterScriptProvider";
672     names[1] = "com.sun.star.script.browse.BrowseNode";
673     names[2] = "com.sun.star.script.provider.ScriptProvider";
674 
675     return Sequence< OUString >( names, 3 );
676 }
677 
678 } // namespace func_provider
679 
680 
681 namespace scripting_runtimemgr
682 {
683 
684 static Reference< XInterface > sp_create(
685     const Reference< XComponentContext > & xCompC )
686 {
687     return static_cast<cppu::OWeakObject *>(new ::func_provider::MasterScriptProvider( xCompC ));
688 }
689 
690 
691 static Sequence< OUString > sp_getSupportedServiceNames( )
692 {
693     OUString names[3];
694 
695     names[0] = "com.sun.star.script.provider.MasterScriptProvider";
696     names[1] = "com.sun.star.script.browse.BrowseNode";
697     names[2] = "com.sun.star.script.provider.ScriptProvider";
698 
699     return Sequence< OUString >( names, 3 );
700 }
701 
702 
703 static OUString sp_getImplementationName( )
704 {
705     return OUString( "com.sun.star.script.provider.MasterScriptProvider"  );
706 }
707 
708 // ***** registration or ScriptingFrameworkURIHelper
709 static Reference< XInterface > urihelper_create(
710     const Reference< XComponentContext > & xCompC )
711 {
712     return static_cast<cppu::OWeakObject *>(
713         new ::func_provider::ScriptingFrameworkURIHelper( xCompC ));
714 }
715 
716 static Sequence< OUString > urihelper_getSupportedServiceNames( )
717 {
718     OUString serviceNameList[] = {
719         OUString(
720             "com.sun.star.script.provider.ScriptURIHelper" ) };
721 
722     Sequence< OUString > serviceNames = Sequence <
723         OUString > ( serviceNameList, 1 );
724 
725     return serviceNames;
726 }
727 
728 static OUString urihelper_getImplementationName( )
729 {
730     return OUString(
731         "com.sun.star.script.provider.ScriptURIHelper");
732 }
733 
734 static const struct cppu::ImplementationEntry s_entries [] =
735     {
736         {
737             sp_create, sp_getImplementationName,
738             sp_getSupportedServiceNames, cppu::createSingleComponentFactory,
739             nullptr, 0
740         },
741         {
742             urihelper_create,
743             urihelper_getImplementationName,
744             urihelper_getSupportedServiceNames,
745             cppu::createSingleComponentFactory,
746             nullptr, 0
747         },
748         {
749             func_provider::mspf_create, func_provider::mspf_getImplementationName,
750             func_provider::mspf_getSupportedServiceNames, cppu::createSingleComponentFactory,
751             nullptr, 0
752         },
753         {
754             browsenodefactory::bnf_create, browsenodefactory::bnf_getImplementationName,
755             browsenodefactory::bnf_getSupportedServiceNames, cppu::createSingleComponentFactory,
756             nullptr, 0
757         },
758         { nullptr, nullptr, nullptr, nullptr, nullptr, 0 }
759     };
760 }
761 
762 
763 //#### EXPORTED ##############################################################
764 
765 
766 extern "C"
767 {
768     /**
769      * This function is called to get service factories for an implementation.
770      *
771      * @param pImplName       name of implementation
772      * @param pServiceManager a service manager, need for component creation
773      * @param pRegistryKey    the registry key for this component, need for persistent
774      *                        data
775      * @return a component factory
776      */
777     SAL_DLLPUBLIC_EXPORT void * scriptframe_component_getFactory(
778         const sal_Char * pImplName,
779         void * pServiceManager,
780         void * pRegistryKey )
781     {
782         return ::cppu::component_getFactoryHelper( pImplName, pServiceManager,
783             pRegistryKey, ::scripting_runtimemgr::s_entries );
784     }
785 }
786 
787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
788