1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_scripting.hxx"
26 #include "basscript.hxx"
27 #include <vos/mutex.hxx>
28 #include <vcl/svapp.hxx>
29 #include <basic/sbx.hxx>
30 #include <basic/sbstar.hxx>
31 #include <basic/sbmod.hxx>
32 #include <basic/sbmeth.hxx>
33 #include <basic/basmgr.hxx>
34 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
35 
36 #include <map>
37 
38 
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::uno;
42 using namespace ::com::sun::star::script;
43 using namespace ::com::sun::star::document;
44 
45 extern ::com::sun::star::uno::Any sbxToUnoValue( SbxVariable* pVar );
46 extern void unoToSbxValue( SbxVariable* pVar, const ::com::sun::star::uno::Any& aValue );
47 
48 
49 //.........................................................................
50 namespace basprov
51 {
52 //.........................................................................
53 
54     typedef ::std::map< sal_Int16, Any, ::std::less< sal_Int16 > > OutParamMap;
55 
56     // =============================================================================
57     // BasicScriptImpl
58     // =============================================================================
59 
60     // -----------------------------------------------------------------------------
61 
BasicScriptImpl(const::rtl::OUString & funcName,SbMethodRef xMethod)62     BasicScriptImpl::BasicScriptImpl( const ::rtl::OUString& funcName, SbMethodRef xMethod )
63         :m_xMethod( xMethod )
64         ,m_funcName( funcName )
65         ,m_documentBasicManager( NULL )
66         ,m_xDocumentScriptContext()
67     {
68     }
69 
70     // -----------------------------------------------------------------------------
71 
BasicScriptImpl(const::rtl::OUString & funcName,SbMethodRef xMethod,BasicManager & documentBasicManager,const Reference<XScriptInvocationContext> & documentScriptContext)72     BasicScriptImpl::BasicScriptImpl( const ::rtl::OUString& funcName, SbMethodRef xMethod,
73         BasicManager& documentBasicManager, const Reference< XScriptInvocationContext >& documentScriptContext )
74         :m_xMethod( xMethod )
75         ,m_funcName( funcName )
76         ,m_documentBasicManager( &documentBasicManager )
77         ,m_xDocumentScriptContext( documentScriptContext )
78     {
79         StartListening( *m_documentBasicManager );
80     }
81 
82     // -----------------------------------------------------------------------------
~BasicScriptImpl()83     BasicScriptImpl::~BasicScriptImpl()
84     {
85         if ( m_documentBasicManager )
86             EndListening( *m_documentBasicManager );
87     }
88 
89     // -----------------------------------------------------------------------------
90     // SfxListener
91     // -----------------------------------------------------------------------------
Notify(SfxBroadcaster & rBC,const SfxHint & rHint)92     void BasicScriptImpl::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
93     {
94         if ( &rBC != m_documentBasicManager )
95         {
96             OSL_ENSURE( false, "BasicScriptImpl::Notify: where does this come from?" );
97             // not interested in
98             return;
99         }
100         const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint );
101         if ( pSimpleHint && ( pSimpleHint->GetId() == SFX_HINT_DYING ) )
102         {
103             m_documentBasicManager = NULL;
104             EndListening( rBC );    // prevent multiple notifications
105         }
106     }
107 
108     // -----------------------------------------------------------------------------
109     // XScript
110     // -----------------------------------------------------------------------------
111 
invoke(const Sequence<Any> & aParams,Sequence<sal_Int16> & aOutParamIndex,Sequence<Any> & aOutParam)112     Any BasicScriptImpl::invoke( const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
113         throw ( provider::ScriptFrameworkErrorException, reflection::InvocationTargetException, uno::RuntimeException)
114     {
115         // TODO: throw CannotConvertException
116         // TODO: check length of aOutParamIndex, aOutParam
117 
118         ::vos::OGuard aGuard( Application::GetSolarMutex() );
119 
120         Any aReturn;
121 
122         if ( m_xMethod )
123         {
124             // check if compiled
125             SbModule* pModule = static_cast< SbModule* >( m_xMethod->GetParent() );
126             if ( pModule && !pModule->IsCompiled() )
127                 pModule->Compile();
128 
129             // check number of parameters
130             sal_Int32 nParamsCount = aParams.getLength();
131             SbxInfo* pInfo = m_xMethod->GetInfo();
132             if ( pInfo )
133             {
134                 sal_Int32 nSbxOptional = 0;
135                 sal_uInt16 n = 1;
136                 for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) )
137                 {
138                     if ( ( pParamInfo->nFlags & SBX_OPTIONAL ) != 0 )
139                         ++nSbxOptional;
140                     else
141                         nSbxOptional = 0;
142                 }
143                 sal_Int32 nSbxCount = n - 1;
144                 if ( nParamsCount < nSbxCount - nSbxOptional )
145                 {
146                     throw provider::ScriptFrameworkErrorException(
147                         ::rtl::OUString(
148                             RTL_CONSTASCII_USTRINGPARAM(
149                                 "wrong number of parameters!" ) ),
150                          Reference< XInterface >(),
151                          m_funcName,
152                          ::rtl::OUString(
153                              RTL_CONSTASCII_USTRINGPARAM( "Basic" ) ),
154                         provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT  );
155                 }
156             }
157 
158             // set parameters
159             SbxArrayRef xSbxParams;
160             if ( nParamsCount > 0 )
161             {
162                 xSbxParams = new SbxArray;
163                 const Any* pParams = aParams.getConstArray();
164                 for ( sal_Int32 i = 0; i < nParamsCount; ++i )
165                 {
166                     SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
167                     unoToSbxValue( static_cast< SbxVariable* >( xSbxVar ), pParams[i] );
168                     xSbxParams->Put( xSbxVar, static_cast< sal_uInt16 >( i ) + 1 );
169 
170 					// Enable passing by ref
171 					if ( xSbxVar->GetType() != SbxVARIANT )
172 						xSbxVar->SetFlag( SBX_FIXED );
173                  }
174             }
175             if ( xSbxParams.Is() )
176                 m_xMethod->SetParameters( xSbxParams );
177 
178             // call method
179             SbxVariableRef xReturn = new SbxVariable;
180             ErrCode nErr = SbxERR_OK;
181             {
182                 // if it's a document-based script, temporarily reset ThisComponent to the script invocation context
183                 Any aOldThisComponent;
184                 if ( m_documentBasicManager && m_xDocumentScriptContext.is() )
185                     aOldThisComponent = m_documentBasicManager->SetGlobalUNOConstant( "ThisComponent", makeAny( m_xDocumentScriptContext ) );
186 
187                 nErr = m_xMethod->Call( xReturn );
188 
189                 if ( m_documentBasicManager && m_xDocumentScriptContext.is() )
190                     m_documentBasicManager->SetGlobalUNOConstant( "ThisComponent", aOldThisComponent );
191             }
192             if ( nErr != SbxERR_OK )
193             {
194                 // TODO: throw InvocationTargetException ?
195             }
196 
197             // get output parameters
198             if ( xSbxParams.Is() )
199             {
200                 SbxInfo* pInfo_ = m_xMethod->GetInfo();
201                 if ( pInfo_ )
202                 {
203                     OutParamMap aOutParamMap;
204                     for ( sal_uInt16 n = 1, nCount = xSbxParams->Count(); n < nCount; ++n )
205                     {
206                         const SbxParamInfo* pParamInfo = pInfo_->GetParam( n );
207                         if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 )
208                         {
209                             SbxVariable* pVar = xSbxParams->Get( n );
210                             if ( pVar )
211                             {
212                                 SbxVariableRef xVar = pVar;
213                                 aOutParamMap.insert( OutParamMap::value_type( n - 1, sbxToUnoValue( xVar ) ) );
214                             }
215                         }
216                     }
217                     sal_Int32 nOutParamCount = aOutParamMap.size();
218                     aOutParamIndex.realloc( nOutParamCount );
219                     aOutParam.realloc( nOutParamCount );
220                     sal_Int16* pOutParamIndex = aOutParamIndex.getArray();
221                     Any* pOutParam = aOutParam.getArray();
222                     for ( OutParamMap::iterator aIt = aOutParamMap.begin(); aIt != aOutParamMap.end(); ++aIt, ++pOutParamIndex, ++pOutParam )
223                     {
224                         *pOutParamIndex = aIt->first;
225                         *pOutParam = aIt->second;
226                     }
227                 }
228             }
229 
230             // get return value
231             aReturn = sbxToUnoValue( xReturn );
232 
233             // reset parameters
234             m_xMethod->SetParameters( NULL );
235         }
236 
237         return aReturn;
238     }
239 
240     // -----------------------------------------------------------------------------
241 
242 //.........................................................................
243 }	// namespace basprov
244 //.........................................................................
245