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