Branch data Line data Source code
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 : : #include <pyuno/pyuno.hxx>
21 : :
22 : : #include <osl/process.h>
23 : : #include <osl/file.hxx>
24 : : #include <osl/thread.h>
25 : :
26 : : #include <rtl/ustrbuf.hxx>
27 : : #include <rtl/strbuf.hxx>
28 : : #include <rtl/bootstrap.hxx>
29 : :
30 : : #include <cppuhelper/implementationentry.hxx>
31 : : #include <cppuhelper/factory.hxx>
32 : :
33 : : using rtl::OUString;
34 : : using rtl::OUStringBuffer;
35 : : using rtl::OString;
36 : :
37 : : using pyuno::PyRef;
38 : : using pyuno::Runtime;
39 : : using pyuno::PyThreadAttach;
40 : :
41 : : using com::sun::star::registry::XRegistryKey;
42 : : using com::sun::star::uno::Reference;
43 : : using com::sun::star::uno::XInterface;
44 : : using com::sun::star::uno::Sequence;
45 : : using com::sun::star::uno::XComponentContext;
46 : : using com::sun::star::uno::RuntimeException;
47 : :
48 : : namespace pyuno_loader
49 : : {
50 : :
51 : 175 : static void raiseRuntimeExceptionWhenNeeded() throw ( RuntimeException )
52 : : {
53 [ - + ]: 175 : if( PyErr_Occurred() )
54 : : {
55 : 0 : PyRef excType, excValue, excTraceback;
56 [ # # ]: 0 : PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
57 [ # # ]: 0 : Runtime runtime;
58 [ # # ]: 0 : com::sun::star::uno::Any a = runtime.extractUnoException( excType, excValue, excTraceback );
59 : 0 : OUStringBuffer buf;
60 [ # # ]: 0 : buf.appendAscii( "python-loader:" );
61 [ # # ]: 0 : if( a.hasValue() )
62 [ # # ]: 0 : buf.append( ((com::sun::star::uno::Exception *)a.getValue())->Message );
63 [ # # ][ # # ]: 0 : throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () );
64 : : }
65 : 175 : }
66 : :
67 : 175 : static PyRef getLoaderModule() throw( RuntimeException )
68 : : {
69 : : PyRef module(
70 : : PyImport_ImportModule( "pythonloader" ),
71 [ + - ]: 175 : SAL_NO_ACQUIRE );
72 [ + - ]: 175 : raiseRuntimeExceptionWhenNeeded();
73 [ - + ]: 175 : if( !module.is() )
74 : : {
75 : : throw RuntimeException(
76 : : OUString( RTL_CONSTASCII_USTRINGPARAM( "pythonloader: Couldn't load pythonloader module" ) ),
77 [ # # ][ # # ]: 0 : Reference< XInterface > () );
78 : : }
79 [ + - ][ + - ]: 175 : return PyRef( PyModule_GetDict( module.get() ));
80 : : }
81 : :
82 : 175 : static PyRef getObjectFromLoaderModule( const char * func )
83 : : throw ( RuntimeException )
84 : : {
85 [ + - ][ + - ]: 175 : PyRef object( PyDict_GetItemString(getLoaderModule().get(), (char*)func ) );
86 [ - + ]: 175 : if( !object.is() )
87 : : {
88 : 0 : OUStringBuffer buf;
89 [ # # ]: 0 : buf.appendAscii( "pythonloader: couldn't find core element pythonloader." );
90 [ # # ]: 0 : buf.appendAscii( func );
91 [ # # ][ # # ]: 0 : throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >());
92 : : }
93 : 175 : return object;
94 : : }
95 : :
96 : 112 : OUString getImplementationName()
97 : : {
98 : 112 : return OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.pyuno.Loader" ) );
99 : : }
100 : :
101 : 112 : Sequence< OUString > getSupportedServiceNames()
102 : : {
103 [ + - ]: 112 : OUString serviceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.loader.Python" ) );
104 [ + - ]: 112 : return Sequence< OUString > ( &serviceName, 1 );
105 : : }
106 : :
107 : 0 : static void setPythonHome ( const OUString & pythonHome )
108 : : {
109 : 0 : OUString systemPythonHome;
110 [ # # ]: 0 : osl_getSystemPathFromFileURL( pythonHome.pData, &(systemPythonHome.pData) );
111 [ # # ][ # # ]: 0 : OString o = rtl::OUStringToOString( systemPythonHome, osl_getThreadTextEncoding() );
112 : : #if PY_MAJOR_VERSION >= 3
113 : : // static because Py_SetPythonHome just copies the "wide" pointer
114 : : // PATH_MAX is defined in Python.h
115 : : static wchar_t wide[PATH_MAX + 1];
116 : : size_t len = mbstowcs(wide, o.pData->buffer, PATH_MAX + 1);
117 : : if(len == (size_t)-1)
118 : : {
119 : : PyErr_SetString(PyExc_SystemError, "invalid multibyte sequence in python home path");
120 : : return;
121 : : }
122 : : if(len == PATH_MAX + 1)
123 : : {
124 : : PyErr_SetString(PyExc_SystemError, "python home path is too long");
125 : : return;
126 : : }
127 : : Py_SetPythonHome(wide);
128 : : #else
129 : 0 : rtl_string_acquire(o.pData); // increase reference count
130 [ # # ]: 0 : Py_SetPythonHome(o.pData->buffer);
131 : : #endif
132 : 0 : }
133 : :
134 : 112 : static void prependPythonPath( const OUString & pythonPathBootstrap )
135 : : {
136 : 112 : rtl::OUStringBuffer bufPYTHONPATH( 256 );
137 : 112 : sal_Int32 nIndex = 0;
138 : 0 : while( 1 )
139 : : {
140 : 112 : sal_Int32 nNew = pythonPathBootstrap.indexOf( ' ', nIndex );
141 : 112 : OUString fileUrl;
142 [ + - ]: 112 : if( nNew == -1 )
143 : : {
144 : 112 : fileUrl = pythonPathBootstrap.copy(nIndex);
145 : : }
146 : : else
147 : : {
148 : 0 : fileUrl = pythonPathBootstrap.copy(nIndex, nNew - nIndex);
149 : : }
150 : 112 : OUString systemPath;
151 [ + - ]: 112 : osl_getSystemPathFromFileURL( fileUrl.pData, &(systemPath.pData) );
152 [ + - ]: 112 : bufPYTHONPATH.append( systemPath );
153 [ + - ]: 112 : bufPYTHONPATH.append( static_cast<sal_Unicode>(SAL_PATHSEPARATOR) );
154 [ + - ]: 112 : if( nNew == -1 )
155 : : break;
156 [ + - ]: 112 : nIndex = nNew + 1;
157 [ - + ]: 224 : }
158 : 112 : const char * oldEnv = getenv( "PYTHONPATH");
159 [ - + ]: 112 : if( oldEnv )
160 [ # # ][ # # ]: 0 : bufPYTHONPATH.append( rtl::OUString(oldEnv, strlen(oldEnv), osl_getThreadTextEncoding()) );
[ # # ]
161 : :
162 [ + - ]: 112 : rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("PYTHONPATH"));
163 [ + - ]: 112 : rtl::OUString envValue(bufPYTHONPATH.makeStringAndClear());
164 [ + - ]: 112 : osl_setEnvironment(envVar.pData, envValue.pData);
165 : 112 : }
166 : :
167 : 175 : Reference< XInterface > CreateInstance( const Reference< XComponentContext > & ctx )
168 : : {
169 : 175 : Reference< XInterface > ret;
170 : :
171 [ + + ][ + - ]: 175 : if( ! Py_IsInitialized() )
172 : : {
173 : 112 : OUString pythonPath;
174 : 112 : OUString pythonHome;
175 [ + - ]: 112 : OUString path( RTL_CONSTASCII_USTRINGPARAM( "$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("pythonloader.uno" )));
176 : 112 : rtl::Bootstrap::expandMacros(path); //TODO: detect failure
177 : 112 : rtl::Bootstrap bootstrap(path);
178 : :
179 : : // look for pythonhome
180 [ + - ]: 112 : bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONHOME") ), pythonHome );
181 [ + - ]: 112 : bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONPATH" ) ) , pythonPath );
182 : :
183 : : // pythonhome+pythonpath must be set before Py_Initialize(), otherwise there appear warning on the console
184 : : // sadly, there is no api for setting the pythonpath, we have to use the environment variable
185 [ - + ]: 112 : if( !pythonHome.isEmpty() )
186 [ # # ]: 0 : setPythonHome( pythonHome );
187 : :
188 [ + - ]: 112 : if( !pythonPath.isEmpty() )
189 [ + - ]: 112 : prependPythonPath( pythonPath );
190 : :
191 : : #if WNT
192 : : //extend PATH under windows to include the branddir/program so ssl libs will be found
193 : : //for use by terminal mailmerge dependency _ssl.pyd
194 : : rtl::OUString sEnvName(RTL_CONSTASCII_USTRINGPARAM("PATH"));
195 : : rtl::OUString sPath;
196 : : osl_getEnvironment(sEnvName.pData, &sPath.pData);
197 : : rtl::OUString sBrandLocation(RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program"));
198 : : rtl::Bootstrap::expandMacros(sBrandLocation);
199 : : osl::FileBase::getSystemPathFromFileURL(sBrandLocation, sBrandLocation);
200 : : sPath = rtl::OUStringBuffer(sPath).
201 : : append(static_cast<sal_Unicode>(SAL_PATHSEPARATOR)).
202 : : append(sBrandLocation).makeStringAndClear();
203 : : osl_setEnvironment(sEnvName.pData, sPath.pData);
204 : : #endif
205 : :
206 : : #if PY_MAJOR_VERSION >= 3
207 : : PyImport_AppendInittab( (char*)"pyuno", PyInit_pyuno );
208 : : #else
209 [ + - ]: 112 : PyImport_AppendInittab( (char*)"pyuno", initpyuno );
210 : : #endif
211 : : // initialize python
212 [ + - ]: 112 : Py_Initialize();
213 [ + - ]: 112 : PyEval_InitThreads();
214 : :
215 [ + - ]: 112 : PyThreadState *tstate = PyThreadState_Get();
216 [ + - ]: 112 : PyEval_ReleaseThread( tstate );
217 : : }
218 : :
219 [ + - ][ + - ]: 175 : PyThreadAttach attach( PyInterpreterState_Head() );
220 : : {
221 [ + - ][ + + ]: 175 : if( ! Runtime::isInitialized() )
222 : : {
223 [ + - ]: 112 : Runtime::initialize( ctx );
224 : : }
225 [ + - ]: 175 : Runtime runtime;
226 : :
227 : : PyRef pyCtx = runtime.any2PyObject(
228 [ + - ][ + - ]: 175 : com::sun::star::uno::makeAny( ctx ) );
229 : :
230 [ + - ]: 175 : PyRef clazz = getObjectFromLoaderModule( "Loader" );
231 [ + - ]: 175 : PyRef args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE );
232 [ + - ]: 175 : PyTuple_SetItem( args.get(), 0 , pyCtx.getAcquired() );
233 [ + - ]: 175 : PyRef pyInstance( PyObject_CallObject( clazz.get() , args.get() ), SAL_NO_ACQUIRE );
234 [ + - ][ + - ]: 175 : runtime.pyObject2Any( pyInstance ) >>= ret;
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
235 : : }
236 [ + - ]: 175 : return ret;
237 : : }
238 : :
239 : : }
240 : :
241 : :
242 : : static struct cppu::ImplementationEntry g_entries[] =
243 : : {
244 : : {
245 : : pyuno_loader::CreateInstance, pyuno_loader::getImplementationName,
246 : : pyuno_loader::getSupportedServiceNames, cppu::createSingleComponentFactory,
247 : : 0 , 0
248 : : },
249 : : { 0, 0, 0, 0, 0, 0 }
250 : : };
251 : :
252 : : extern "C"
253 : : {
254 : :
255 : 112 : SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(
256 : : const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
257 : : {
258 : 112 : return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
259 : : }
260 : :
261 : : }
262 : :
263 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|