Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*************************************************************************
3 : *
4 : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : *
6 : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : *
8 : * OpenOffice.org - a multi-platform office productivity suite
9 : *
10 : * This file is part of OpenOffice.org.
11 : *
12 : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : * it under the terms of the GNU Lesser General Public License version 3
14 : * only, as published by the Free Software Foundation.
15 : *
16 : * OpenOffice.org is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU Lesser General Public License version 3 for more details
20 : * (a copy is included in the LICENSE file that accompanied this code).
21 : *
22 : * You should have received a copy of the GNU Lesser General Public License
23 : * version 3 along with OpenOffice.org. If not, see
24 : * <http://www.openoffice.org/license.html>
25 : * for a copy of the LGPLv3 License.
26 : *
27 : ************************************************************************/
28 :
29 : #ifdef AIX
30 : #define _LINUX_SOURCE_COMPAT
31 : #include <sys/timer.h>
32 : #undef _LINUX_SOURCE_COMPAT
33 : #endif
34 :
35 : #ifdef WNT
36 : #include <prewin.h>
37 : #include <postwin.h>
38 : #endif
39 :
40 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
42 : #include <com/sun/star/loader/XImplementationLoader.hpp>
43 : #include <com/sun/star/plugin/PluginManager.hpp>
44 :
45 : #include <comphelper/processfactory.hxx>
46 : #include <plugin/impl.hxx>
47 : #include <ucbhelper/content.hxx>
48 : #include <tools/urlobj.hxx>
49 : #include <vcl/svapp.hxx>
50 : #include <salhelper/timer.hxx>
51 : #include <osl/file.hxx>
52 :
53 : #ifdef UNX
54 : #include <sys/types.h>
55 : #include <sys/socket.h>
56 : #endif
57 :
58 : #if OSL_DEBUG_LEVEL > 1
59 : #include <stdio.h>
60 : #endif
61 :
62 : #include <boost/scoped_array.hpp>
63 :
64 : using namespace com::sun::star;
65 : using namespace com::sun::star::io;
66 : using namespace com::sun::star::beans;
67 : using namespace com::sun::star::plugin;
68 : using namespace osl;
69 :
70 : class PluginDisposer : public salhelper::Timer
71 : {
72 : private:
73 : XPlugin_Impl* m_pPlugin;
74 :
75 : virtual void SAL_CALL onShot() SAL_OVERRIDE;
76 : public:
77 0 : PluginDisposer( XPlugin_Impl* pPlugin ) :
78 : salhelper::Timer( salhelper::TTimeValue( 2, 0 ),
79 : salhelper::TTimeValue( 2, 0 ) ),
80 0 : m_pPlugin( pPlugin )
81 0 : { start(); }
82 0 : virtual ~PluginDisposer() {}
83 : };
84 :
85 0 : void PluginDisposer::onShot()
86 : {
87 0 : if( m_pPlugin )
88 : {
89 0 : if( m_pPlugin->isDisposable() )
90 : {
91 0 : Application::PostUserEvent( LINK( m_pPlugin, XPlugin_Impl, secondLevelDispose ), (void*)m_pPlugin );
92 : }
93 : }
94 : else
95 0 : release();
96 0 : }
97 :
98 0 : Any XPlugin_Impl::queryInterface( const Type& type ) throw( RuntimeException, std::exception )
99 : {
100 0 : return OWeakAggObject::queryInterface( type );
101 : }
102 :
103 0 : Any XPlugin_Impl::queryAggregation( const Type& type ) throw( RuntimeException, std::exception )
104 : {
105 0 : Any aRet( cppu::queryInterface( type, static_cast< XPlugin* >(this) ) );
106 0 : if( ! aRet.hasValue() )
107 0 : aRet = PluginControl_Impl::queryAggregation( type );
108 0 : return aRet;
109 : }
110 :
111 :
112 0 : XPlugin_Impl::XPlugin_Impl( const uno::Reference< com::sun::star::lang::XMultiServiceFactory > & rSMgr) :
113 : PluginControl_Impl(),
114 : m_xSMgr( rSMgr ),
115 : m_pPluginComm( NULL ),
116 : m_pSysPlugData( CreateSysPlugData() ),
117 0 : m_aEncoding( osl_getThreadTextEncoding() ),
118 : m_pArgv( NULL ),
119 : m_pArgn( NULL ),
120 : m_nArgs( 0 ),
121 : m_aPluginMode( NP_FULL ),
122 : m_nProvidingState( PROVIDING_NONE ),
123 : m_nCalledFromPlugin( 0 ),
124 : m_pDisposer( NULL ),
125 0 : m_bIsDisposed( false )
126 : {
127 0 : memset( &m_aInstance, 0, sizeof( m_aInstance ) );
128 0 : memset( &m_aNPWindow, 0, sizeof( m_aNPWindow ) );
129 :
130 0 : m_xModel = new PluginModel();
131 0 : uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
132 0 : xPS->addPropertyChangeListener( OUString(), this );
133 :
134 0 : Guard< Mutex > aGuard( ::PluginManager::get().getPluginMutex() );
135 0 : ::PluginManager::get().getPlugins().push_back( this );
136 0 : }
137 :
138 0 : void XPlugin_Impl::destroyInstance()
139 : {
140 0 : Guard< Mutex > aGuard( m_aMutex );
141 :
142 0 : NPSavedData* pSavedData = NULL;
143 :
144 0 : destroyStreams();
145 0 : if( getPluginComm() )
146 : {
147 0 : getPluginComm()->NPP_Destroy( this, &pSavedData );
148 0 : getPluginComm()->decRef();
149 0 : m_pPluginComm = NULL;
150 : }
151 :
152 0 : freeArgs();
153 :
154 0 : while( m_aPEventListeners.size() )
155 : {
156 0 : delete *m_aPEventListeners.begin();
157 0 : m_aPEventListeners.pop_front();
158 0 : }
159 0 : }
160 :
161 0 : XPlugin_Impl::~XPlugin_Impl()
162 : {
163 0 : destroyInstance();
164 0 : }
165 :
166 0 : void XPlugin_Impl::checkListeners( const char* normalizedURL )
167 : {
168 0 : if( ! normalizedURL )
169 0 : return;
170 :
171 0 : Guard< Mutex > aGuard( m_aMutex );
172 :
173 0 : std::list<PluginEventListener*>::iterator iter;
174 0 : for( iter = m_aPEventListeners.begin();
175 0 : iter != m_aPEventListeners.end();
176 : ++iter )
177 : {
178 0 : if( ! strcmp( normalizedURL, (*iter)->getURL() ) ||
179 0 : ! strcmp( normalizedURL, (*iter)->getNormalizedURL() ) )
180 : {
181 0 : (*iter)->disposing( com::sun::star::lang::EventObject() );
182 0 : delete *iter;
183 0 : m_aPEventListeners.remove( *iter );
184 0 : return;
185 : }
186 0 : }
187 : }
188 :
189 0 : IMPL_LINK( XPlugin_Impl, secondLevelDispose, XPlugin_Impl*, /*pThis*/ )
190 : {
191 0 : Guard< Mutex > aGuard( m_aMutex );
192 :
193 : // may have become undisposable between PostUserEvent and here
194 : // or may have disposed and receive a second UserEvent
195 0 : std::list<XPlugin_Impl*>& rList = ::PluginManager::get().getPlugins();
196 0 : std::list<XPlugin_Impl*>::iterator iter;
197 :
198 : {
199 0 : Guard< Mutex > aPluginGuard( ::PluginManager::get().getPluginMutex() );
200 0 : for( iter = rList.begin(); iter != rList.end(); ++iter )
201 : {
202 0 : if( *iter == this )
203 0 : break;
204 : }
205 0 : if( iter == rList.end() || ! isDisposable() )
206 0 : return 0;
207 : }
208 :
209 0 : if (m_pDisposer)
210 : {
211 0 : m_pDisposer->release();
212 0 : m_pDisposer = NULL;
213 : }
214 :
215 0 : uno::Reference< XPlugin > xProtection( this );
216 0 : uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
217 0 : xPS->removePropertyChangeListener( OUString(), this );
218 : {
219 0 : Guard< Mutex > aPluginGuard( ::PluginManager::get().getPluginMutex() );
220 0 : rList.remove( this );
221 : }
222 0 : m_aNPWindow.window = NULL;
223 : #ifndef UNX
224 : // acrobat does an unconditional XtParent on the windows widget
225 : getPluginComm()->NPP_SetWindow( this );
226 : #endif
227 0 : destroyInstance();
228 0 : PluginControl_Impl::dispose();
229 0 : return 0;
230 : }
231 :
232 0 : void XPlugin_Impl::dispose() throw(std::exception)
233 : {
234 0 : Guard< Mutex > aGuard( m_aMutex );
235 :
236 0 : if (m_bIsDisposed || !getPluginComm())
237 0 : return;
238 0 : m_bIsDisposed = true;
239 :
240 0 : if( isDisposable() )
241 0 : secondLevelDispose( this );
242 : else
243 : {
244 0 : m_pDisposer = new PluginDisposer( this );
245 0 : m_pDisposer->acquire();
246 0 : }
247 : }
248 :
249 0 : void XPlugin_Impl::initArgs( const Sequence< OUString >& argn,
250 : const Sequence< OUString >& argv,
251 : sal_Int16 mode )
252 : {
253 0 : m_aPluginMode = mode;
254 :
255 0 : m_nArgs = argn.getLength();
256 0 : m_pArgn = new const char*[m_nArgs];
257 0 : m_pArgv = new const char*[m_nArgs];
258 0 : const OUString* pUArgn = argn.getConstArray();
259 0 : const OUString* pUArgv = argv.getConstArray();
260 0 : for( int i = 0; i < m_nArgs; i++ )
261 : {
262 0 : m_pArgn[i] = strdup(
263 0 : OUStringToOString( pUArgn[i], m_aEncoding ).getStr()
264 0 : );
265 0 : m_pArgv[i] = strdup(
266 0 : OUStringToOString( pUArgv[i], m_aEncoding ).getStr()
267 0 : );
268 : }
269 0 : }
270 :
271 0 : void XPlugin_Impl::freeArgs()
272 : {
273 0 : if( m_nArgs > 0 )
274 : {
275 0 : for( ; m_nArgs--; )
276 : {
277 0 : free( (void*)m_pArgn[m_nArgs] );
278 0 : free( (void*)m_pArgv[m_nArgs] );
279 : }
280 0 : delete [] m_pArgn;
281 0 : delete [] m_pArgv;
282 : }
283 0 : }
284 :
285 0 : void XPlugin_Impl::prependArg( const char* pName, const char* pValue )
286 : {
287 0 : const char** pNewNames = new const char*[m_nArgs+1];
288 0 : const char** pNewValues = new const char*[m_nArgs+1];
289 :
290 0 : pNewNames[0] = strdup( pName );
291 0 : pNewValues[0] = strdup( pValue );
292 0 : for( int nIndex = 0; nIndex < m_nArgs; ++nIndex )
293 : {
294 0 : pNewNames[nIndex+1] = m_pArgn[nIndex];
295 0 : pNewValues[nIndex+1]= m_pArgv[nIndex];
296 : }
297 : // free old arrays
298 0 : delete [] m_pArgn;
299 0 : delete [] m_pArgv;
300 : // set new arrays
301 0 : m_pArgn = pNewNames;
302 0 : m_pArgv = pNewValues;
303 : // set new number of arguments
304 0 : m_nArgs++;
305 : #if OSL_DEBUG_LEVEL > 1
306 : fprintf( stderr, "inserted %s=%s\n", pNewNames[0], pNewValues[0] );
307 : #endif
308 0 : }
309 :
310 0 : void XPlugin_Impl::handleSpecialArgs()
311 : {
312 : // special handling for real audio which needs a lot of parameters
313 : // or won't function at all
314 0 : if( m_aDescription.Mimetype.equalsAscii( "audio/x-pn-realaudio-plugin" ) && m_nArgs < 1 )
315 : {
316 0 : OUString aURL;
317 0 : if( m_xModel.is() )
318 : {
319 : try
320 : {
321 0 : uno::Reference< XPropertySet > xProp( m_xModel, UNO_QUERY );
322 0 : Any aProp = xProp->getPropertyValue("URL");
323 0 : aProp >>= aURL;
324 : }
325 0 : catch(const UnknownPropertyException &)
326 : {
327 : }
328 : }
329 :
330 0 : if( !aURL.isEmpty() )
331 : {
332 : // set new args, old args need not be freed as there were none set
333 0 : m_nArgs = 6;
334 0 : m_pArgn = new const char*[m_nArgs];
335 0 : m_pArgv = new const char*[m_nArgs];
336 :
337 : // SRC
338 0 : m_pArgn[0] = strdup( "SRC" );
339 0 : m_pArgv[0] = strdup( OUStringToOString( aURL, m_aEncoding ).getStr() );
340 : // WIDTH
341 0 : m_pArgn[1] = strdup( "WIDTH" );
342 0 : m_pArgv[1] = strdup( "200" );
343 : // HEIGHT
344 0 : m_pArgn[2] = strdup( "HEIGHT" );
345 0 : m_pArgv[2] = strdup( "200" );
346 : // CONTROLS
347 0 : m_pArgn[3] = strdup( "CONTROLS" );
348 0 : m_pArgv[3] = strdup( "PlayButton,StopButton,ImageWindow" );
349 : // AUTOSTART
350 0 : m_pArgn[4] = strdup( "AUTOSTART" );
351 0 : m_pArgv[4] = strdup( "TRUE" );
352 : // NOJAVA
353 0 : m_pArgn[5] = strdup( "NOJAVA" );
354 0 : m_pArgv[5] = strdup( "TRUE" );
355 0 : }
356 : }
357 : // #69333# special for pdf
358 0 : else if( m_aDescription.Mimetype.equalsAscii( "application/pdf" ) )
359 0 : m_aPluginMode = PluginMode::FULL;
360 :
361 : // see if we have a TYPE tag
362 : int nIndex;
363 0 : for( nIndex = 0; nIndex < m_nArgs; ++nIndex )
364 0 : if( m_pArgn[nIndex][0] == 'T' &&
365 0 : m_pArgn[nIndex][1] == 'Y' &&
366 0 : m_pArgn[nIndex][2] == 'P' &&
367 0 : m_pArgn[nIndex][3] == 'E' &&
368 0 : m_pArgn[nIndex][4] == 0 )
369 0 : break;
370 0 : if( nIndex >= m_nArgs )
371 : {
372 : // TYPE
373 0 : prependArg( "TYPE", OUStringToOString( m_aDescription.Mimetype, m_aEncoding ).getStr() );
374 : }
375 :
376 : // see if we have a SRC tag
377 0 : for( nIndex = 0; nIndex < m_nArgs; ++nIndex )
378 0 : if( m_pArgn[nIndex][0] == 'S' &&
379 0 : m_pArgn[nIndex][1] == 'R' &&
380 0 : m_pArgn[nIndex][2] == 'C' &&
381 0 : m_pArgn[nIndex][3] == 0 )
382 0 : break;
383 0 : if( nIndex >= m_nArgs )
384 : {
385 : // need a SRC parameter (as all browser set one on the plugin
386 0 : OUString aURL;
387 0 : if( m_xModel.is() )
388 : {
389 : try
390 : {
391 0 : uno::Reference< XPropertySet > xProp( m_xModel, UNO_QUERY );
392 0 : Any aProp = xProp->getPropertyValue("URL");
393 0 : aProp >>= aURL;
394 : }
395 0 : catch(const UnknownPropertyException &)
396 : {
397 : }
398 : }
399 :
400 0 : if( !aURL.isEmpty() )
401 : {
402 : // SRC
403 0 : prependArg( "SRC", OUStringToOString( aURL, m_aEncoding ).getStr() );
404 0 : }
405 : }
406 0 : }
407 :
408 0 : void XPlugin_Impl::initInstance( const PluginDescription& rDescription,
409 : const Sequence< OUString >& argn,
410 : const Sequence< OUString >& argv,
411 : sal_Int16 mode )
412 : {
413 0 : Guard< Mutex > aGuard( m_aMutex );
414 :
415 0 : m_aDescription = rDescription;
416 0 : initArgs( argn, argv, mode );
417 0 : handleSpecialArgs();
418 0 : }
419 :
420 0 : void XPlugin_Impl::initInstance( const OUString& rURL,
421 : const Sequence< OUString >& argn,
422 : const Sequence< OUString >& argv,
423 : sal_Int16 mode )
424 : {
425 0 : Guard< Mutex > aGuard( m_aMutex );
426 :
427 0 : initArgs( argn, argv, mode );
428 0 : m_aDescription = fitDescription( rURL );
429 :
430 0 : m_xModel = new PluginModel( rURL, m_aDescription.Mimetype );
431 0 : handleSpecialArgs();
432 0 : }
433 :
434 0 : void XPlugin_Impl::modelChanged()
435 : {
436 0 : Guard< Mutex > aGuard( m_aMutex );
437 :
438 0 : m_nProvidingState = PROVIDING_MODEL_UPDATE;
439 :
440 0 : m_aDescription = fitDescription( getCreationURL() );
441 0 : destroyInstance();
442 0 : if( m_aDescription.Mimetype.isEmpty() )
443 : {
444 0 : m_nProvidingState = PROVIDING_NONE;
445 0 : return;
446 : }
447 :
448 0 : OUString aURL = getCreationURL();
449 : provideNewStream( m_aDescription.Mimetype,
450 : uno::Reference< XActiveDataSource >(),
451 : aURL,
452 0 : 0, 0, aURL.startsWith("file:") );
453 0 : m_nProvidingState = PROVIDING_NONE;
454 : }
455 :
456 0 : OUString XPlugin_Impl::getCreationURL()
457 : {
458 0 : Guard< Mutex > aGuard( m_aMutex );
459 :
460 0 : OUString aRet;
461 0 : uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
462 0 : if( xPS.is() )
463 : {
464 0 : Any aValue = xPS->getPropertyValue("URL");
465 0 : aValue >>= aRet;
466 : }
467 0 : return aRet;
468 : }
469 :
470 :
471 0 : sal_Bool XPlugin_Impl::setModel( const uno::Reference< com::sun::star::awt::XControlModel > & Model )
472 : throw( RuntimeException, std::exception )
473 : {
474 0 : Guard< Mutex > aGuard( m_aMutex );
475 :
476 0 : uno::Reference< com::sun::star::beans::XPropertySet > xPS( Model, UNO_QUERY );
477 0 : if( ! xPS.is() )
478 0 : return sal_False;
479 :
480 0 : if( !getCreationURL().isEmpty() )
481 : {
482 0 : m_xModel = Model;
483 0 : modelChanged();
484 0 : xPS->addPropertyChangeListener( OUString(), this );
485 0 : return sal_True;
486 : }
487 0 : return sal_False;
488 : }
489 :
490 0 : void XPlugin_Impl::createPeer( const uno::Reference< com::sun::star::awt::XToolkit > & xToolkit, const uno::Reference< com::sun::star::awt::XWindowPeer > & Parent )
491 : throw( RuntimeException, std::exception )
492 : {
493 0 : Guard< Mutex > aGuard( m_aMutex );
494 :
495 0 : if( ! _xPeer.is() )
496 : {
497 0 : if( ! Parent.is() )
498 0 : throw RuntimeException();
499 0 : PluginControl_Impl::createPeer( xToolkit, Parent );
500 0 : }
501 0 : }
502 :
503 0 : void XPlugin_Impl::loadPlugin()
504 : {
505 0 : Guard< Mutex > aGuard( m_aMutex );
506 :
507 0 : std::list<PluginComm*>::iterator iter;
508 0 : for( iter = ::PluginManager::get().getPluginComms().begin();
509 0 : iter != ::PluginManager::get().getPluginComms().end(); ++iter )
510 : {
511 0 : if( OStringToOUString( (*iter)->getLibName(), m_aEncoding ) == m_aDescription.PluginName )
512 : {
513 0 : setPluginComm( *iter );
514 0 : break;
515 : }
516 : }
517 0 : const SystemEnvData* pEnvData = getSysChildSysData();
518 : #if defined( UNX ) && !(defined(MACOSX))
519 0 : if (pEnvData->pDisplay) // headless?
520 : {
521 0 : XSync( (Display*)pEnvData->pDisplay, False );
522 : }
523 : #endif
524 0 : if( ! getPluginComm() )
525 : {
526 0 : if( !m_aDescription.PluginName.isEmpty() )
527 : {
528 : #if defined MACOSX
529 : PluginComm* pComm = new MacPluginComm( m_aDescription.Mimetype,
530 : m_aDescription.PluginName,
531 : pEnvData->mpNSView );
532 : #elif defined UNX
533 : // need a new PluginComm
534 0 : PluginComm* pComm = NULL;
535 : int sv[2];
536 0 : if( !socketpair( AF_UNIX, SOCK_STREAM, 0, sv ) )
537 : pComm = new UnxPluginComm( m_aDescription.Mimetype,
538 : m_aDescription.PluginName,
539 : (Window)pEnvData->aWindow,
540 : sv[0],
541 : sv[1]
542 0 : );
543 :
544 : SAL_WARN_IF( !pComm, "extensions.plugin", "no PluginComm");
545 0 : if (!pComm)
546 0 : return;
547 :
548 : #elif defined WNT
549 : PluginComm* pComm = new PluginComm_Impl( m_aDescription.Mimetype,
550 : m_aDescription.PluginName,
551 : (HWND)pEnvData->hWnd );
552 : #endif
553 :
554 0 : setPluginComm( pComm );
555 : }
556 : else
557 0 : return;
558 : }
559 :
560 0 : getPluginComm()->
561 : NPP_New( (char*)OUStringToOString( m_aDescription.Mimetype,
562 0 : m_aEncoding).getStr(),
563 0 : &getNPPInstance(),
564 0 : m_aPluginMode == PluginMode::FULL ? NP_FULL : NP_EMBED,
565 0 : ::sal::static_int_cast< int16_t, int >( m_nArgs ),
566 : (char**)(m_nArgs ? m_pArgn : NULL),
567 : (char**)(m_nArgs ? m_pArgv : NULL),
568 0 : NULL );
569 : #ifdef MACOSX
570 : // m_aNPWindow is set up in the MacPluginComm from the view
571 : SetSysPlugDataParentView(*pEnvData);
572 : #elif defined( UNX )
573 0 : if (pEnvData->pDisplay) // headless?
574 : {
575 0 : XSync( (Display*)pEnvData->pDisplay, False );
576 0 : m_aNPWindow.window = reinterpret_cast<void*>(pEnvData->aWindow);
577 : }
578 : else
579 : {
580 0 : m_aNPWindow.window = NULL;
581 : }
582 0 : m_aNPWindow.ws_info = NULL;
583 : #else
584 : m_aNPWindow.window = (void*)pEnvData->hWnd;
585 : #endif
586 0 : com::sun::star::awt::Rectangle aPosSize = getPosSize();
587 :
588 0 : for( int i = 0; i < m_nArgs; i++ )
589 : {
590 0 : OString aName( m_pArgn[i] );
591 0 : if( aName.equalsIgnoreAsciiCase( "width" ) )
592 : {
593 0 : OString aValue( m_pArgv[i] );
594 0 : aPosSize.Width = aValue.toInt32();
595 : }
596 0 : else if( aName.equalsIgnoreAsciiCase( "height" ) )
597 : {
598 0 : OString aValue( m_pArgv[i] );
599 0 : aPosSize.Height = aValue.toInt32();
600 : }
601 0 : }
602 :
603 0 : m_aNPWindow.clipRect.top = 0;
604 0 : m_aNPWindow.clipRect.left = 0;
605 0 : m_aNPWindow.clipRect.bottom = ::sal::static_int_cast< uint16_t, sal_Int32 >( aPosSize.Height );
606 0 : m_aNPWindow.clipRect.right = ::sal::static_int_cast< uint16_t, sal_Int32 >( aPosSize.Width );
607 0 : m_aNPWindow.type = NPWindowTypeWindow;
608 :
609 0 : m_aNPWindow.x = 0;
610 0 : m_aNPWindow.y = 0;
611 0 : m_aNPWindow.width = aPosSize.Width ? aPosSize.Width : 600;
612 0 : m_aNPWindow.height = aPosSize.Height ? aPosSize.Height : 600;
613 :
614 0 : getPluginComm()->NPP_SetWindow( this );
615 : }
616 :
617 0 : void XPlugin_Impl::destroyStreams()
618 : {
619 0 : Guard< Mutex > aGuard( m_aMutex );
620 :
621 : // streams remove themselves from this list when deleted
622 0 : while( m_aOutputStreams.size() )
623 0 : delete *m_aOutputStreams.begin();
624 :
625 : // input streams are XOutputStreams, they cannot be simply deleted
626 0 : std::list<PluginInputStream*> aLocalList( m_aInputStreams );
627 0 : for( std::list<PluginInputStream*>::iterator it = aLocalList.begin();
628 0 : it != aLocalList.end(); ++it )
629 0 : (*it)->setMode( -1 );
630 0 : }
631 :
632 0 : PluginStream* XPlugin_Impl::getStreamFromNPStream( NPStream* stream )
633 : {
634 0 : Guard< Mutex > aGuard( m_aMutex );
635 :
636 0 : std::list<PluginInputStream*>::iterator iter;
637 0 : for( iter = m_aInputStreams.begin(); iter != m_aInputStreams.end(); ++iter )
638 0 : if( &(*iter)->getStream() == stream )
639 0 : return *iter;
640 :
641 0 : std::list<PluginOutputStream*>::iterator iter2;
642 0 : for( iter2 = m_aOutputStreams.begin(); iter2 != m_aOutputStreams.end(); ++iter2 )
643 0 : if( &(*iter2)->getStream() == stream )
644 0 : return *iter2;
645 :
646 0 : return NULL;
647 : }
648 :
649 0 : sal_Bool XPlugin_Impl::provideNewStream(const OUString& mimetype,
650 : const uno::Reference< com::sun::star::io::XActiveDataSource > & stream,
651 : const OUString& url, sal_Int32 length,
652 : sal_Int32 lastmodified, sal_Bool isfile) throw(std::exception)
653 :
654 : {
655 0 : Guard< Mutex > aGuard( m_aMutex );
656 0 : bool bRet = false;
657 :
658 0 : if( m_nProvidingState != PROVIDING_NONE )
659 : {
660 0 : m_nProvidingState = PROVIDING_NOW;
661 0 : Any aAny;
662 0 : aAny <<= url;
663 0 : uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
664 0 : if( xPS.is() )
665 : {
666 : try
667 : {
668 0 : xPS->setPropertyValue("URL", aAny );
669 0 : aAny <<= mimetype;
670 0 : xPS->setPropertyValue("TYPE", aAny );
671 : }
672 0 : catch(...)
673 : {
674 : }
675 0 : }
676 : }
677 0 : m_nProvidingState = PROVIDING_NOW;
678 :
679 0 : OString aMIME;
680 0 : if( !mimetype.isEmpty() )
681 0 : aMIME = OUStringToOString( mimetype, m_aEncoding );
682 : else
683 0 : aMIME = OUStringToOString( m_aDescription.Mimetype, m_aEncoding );
684 :
685 0 : OString aURL = OUStringToOString( url, m_aEncoding );
686 :
687 : // check whether there is a notifylistener for this stream
688 : // this means that the strema is created from the plugin
689 : // via NPN_GetURLNotify or NPN_PostURLNotify
690 0 : std::list<PluginEventListener*>::iterator iter;
691 0 : for( iter = m_aPEventListeners.begin();
692 0 : iter != m_aPEventListeners.end();
693 : ++iter )
694 : {
695 0 : if( (*iter)->getNormalizedURL() == aURL )
696 : {
697 0 : aURL = (*iter)->getURL();
698 0 : break;
699 : }
700 : }
701 :
702 0 : if( ! m_pPluginComm )
703 : {
704 0 : loadPlugin();
705 0 : if( !m_aLastGetUrl.isEmpty() && m_aLastGetUrl == aURL )
706 : {
707 : // plugin is pulling data, don't push the same stream;
708 : // this complicated method could have been avoided if
709 : // all plugins respected the SRC parameter; but e.g.
710 : // acrobat reader plugin does not
711 0 : m_nProvidingState = PROVIDING_NONE;
712 0 : return sal_True;
713 : }
714 : }
715 0 : if( ! m_pPluginComm )
716 0 : return sal_False;
717 :
718 0 : if( url.isEmpty() )
719 : // this is valid if the plugin is supposed to
720 : // pull data (via e.g. NPN_GetURL)
721 0 : return sal_True;
722 :
723 : // set mimetype on model
724 : {
725 0 : uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
726 0 : if( xPS.is() )
727 : {
728 : try
729 : {
730 0 : Any aAny;
731 0 : aAny <<= m_aDescription.Mimetype;
732 0 : xPS->setPropertyValue("TYPE", aAny );
733 : }
734 0 : catch(...)
735 : {
736 : }
737 0 : }
738 : }
739 :
740 : // there may be plugins that can use the file length information,
741 : // but currently none are known. Since this file opening/seeking/closing
742 : // is rather costly, it is not implemented. If there are plugins known to
743 : // make use of the file length, simply put it in
744 :
745 : PluginInputStream* pStream = new PluginInputStream( this, aURL.getStr(),
746 0 : length, lastmodified );
747 0 : uno::Reference< com::sun::star::io::XOutputStream > xNewStream( pStream );
748 :
749 0 : if( iter != m_aPEventListeners.end() )
750 0 : pStream->getStream().notifyData = (*iter)->getNotifyData();
751 :
752 0 : uint16_t stype = 0;
753 :
754 : // special handling acrobat reader
755 : // presenting a seekable stream to it does not seem to work correctly
756 0 : if( aMIME.equals( "application/pdf" ) )
757 0 : isfile = sal_False;
758 :
759 : #if OSL_DEBUG_LEVEL > 1
760 : fprintf( stderr,
761 : "new stream \"%s\" of MIMEType \"%s\"\n"
762 : "for plugin \"%s\"\n"
763 : "seekable = %s, length = %" SAL_PRIdINT32 "\n",
764 : aURL.getStr(), aMIME.getStr(), getPluginComm()->getLibName().getStr(),
765 : isfile ? "true" : "false", length );
766 :
767 : #endif
768 0 : if( ! m_pPluginComm->NPP_NewStream( &m_aInstance,
769 0 : (char*)aMIME.getStr(),
770 0 : &pStream->getStream(), isfile,
771 0 : &stype ) )
772 : {
773 : #if OSL_DEBUG_LEVEL > 1
774 : const char* pType;
775 : switch( stype )
776 : {
777 : case NP_NORMAL: pType = "NP_NORMAL";break;
778 : case NP_SEEK: pType = "NP_SEEK";break;
779 : case NP_ASFILE: pType = "NP_ASFILE";break;
780 : case NP_ASFILEONLY: pType = "NP_ASFILEONLY";break;
781 : default: pType = "unknown!!!";
782 : }
783 : fprintf( stderr, "Plugin wants it in Mode %s\n", pType );
784 : #endif
785 0 : if( isfile && stype == NP_ASFILEONLY )
786 : {
787 0 : OString aFileName;
788 0 : if( url.startsWith("file:") )
789 : {
790 0 : OUString aSysName;
791 0 : osl_getSystemPathFromFileURL( url.pData, &aSysName.pData );
792 0 : aFileName = OUStringToOString( aSysName, m_aEncoding );
793 : }
794 : else
795 0 : aFileName = OUStringToOString( url, m_aEncoding );
796 : m_pPluginComm->
797 : NPP_StreamAsFile( &m_aInstance,
798 0 : &pStream->getStream(),
799 0 : aFileName.getStr() );
800 : }
801 : else
802 : {
803 0 : pStream->setMode( stype );
804 :
805 0 : if( ! stream.is() )
806 : {
807 : // stream has to be loaded by PluginStream itself via UCB
808 0 : pStream->load();
809 : }
810 : else
811 : {
812 0 : uno::Reference< com::sun::star::io::XConnectable > xConnectable( stream, UNO_QUERY );
813 0 : pStream->setPredecessor( xConnectable );
814 0 : if( xConnectable.is() )
815 : {
816 0 : xConnectable->setSuccessor( static_cast< com::sun::star::io::XConnectable* >(pStream) );
817 0 : while( xConnectable->getPredecessor().is() )
818 0 : xConnectable = xConnectable->getPredecessor();
819 : }
820 0 : stream->setOutputStream( xNewStream );
821 0 : pStream->setSource( stream );
822 0 : uno::Reference< com::sun::star::io::XActiveDataControl > xController;
823 0 : if( xConnectable.is() )
824 0 : xController = uno::Reference< com::sun::star::io::XActiveDataControl >( xConnectable, UNO_QUERY );
825 : else
826 0 : xController = uno::Reference< com::sun::star::io::XActiveDataControl >( stream, UNO_QUERY );
827 :
828 0 : if( xController.is() )
829 0 : xController->start();
830 : }
831 : }
832 0 : bRet = true;
833 : }
834 :
835 0 : m_nProvidingState = PROVIDING_NONE;
836 :
837 0 : return bRet;
838 : }
839 :
840 0 : void XPlugin_Impl::disposing( const com::sun::star::lang::EventObject& /*rSource*/ ) throw(std::exception)
841 : {
842 0 : }
843 :
844 0 : void XPlugin_Impl::propertyChange(const com::sun::star::beans::PropertyChangeEvent& rEvent)
845 : throw (css::uno::RuntimeException, std::exception)
846 : {
847 0 : Guard< Mutex > aGuard( m_aMutex );
848 :
849 0 : if( rEvent.PropertyName.equalsAscii( "URL" ) )
850 : {
851 0 : OUString aStr;
852 0 : rEvent.NewValue >>= aStr;
853 0 : if( m_nProvidingState == PROVIDING_NONE )
854 : {
855 0 : if( aStr != m_aURL )
856 : {
857 0 : m_aURL = aStr;
858 0 : modelChanged();
859 : }
860 0 : }
861 0 : }
862 0 : }
863 :
864 0 : void XPlugin_Impl::setPluginContext( const uno::Reference< XPluginContext > & rContext )
865 : {
866 0 : m_rBrowserContext = rContext;
867 0 : }
868 :
869 0 : void XPlugin_Impl::setPosSize( sal_Int32 nX_, sal_Int32 nY_, sal_Int32 nWidth_, sal_Int32 nHeight_, sal_Int16 nFlags )
870 : throw( RuntimeException, std::exception )
871 : {
872 0 : Guard< Mutex > aGuard( m_aMutex );
873 :
874 : #if OSL_DEBUG_LEVEL > 1
875 : fprintf( stderr, "XPlugin_Impl::setPosSize( %" SAL_PRIdINT32 ", %" SAL_PRIdINT32 ", %" SAL_PRIdINT32 ", %" SAL_PRIdINT32 ", %d )\n",
876 : nX_, nY_, nWidth_, nHeight_, nFlags );
877 : #endif
878 :
879 0 : PluginControl_Impl::setPosSize(nX_, nY_, nWidth_, nHeight_, nFlags);
880 :
881 0 : m_aNPWindow.x = 0;
882 0 : m_aNPWindow.y = 0;
883 0 : m_aNPWindow.width = nWidth_;
884 0 : m_aNPWindow.height = nHeight_;
885 0 : m_aNPWindow.clipRect.top = 0;
886 0 : m_aNPWindow.clipRect.left = 0;
887 0 : m_aNPWindow.clipRect.right = ::sal::static_int_cast< uint16_t, sal_Int32 >( nWidth_ );
888 0 : m_aNPWindow.clipRect.bottom = ::sal::static_int_cast< uint16_t, sal_Int32 >( nHeight_ );
889 :
890 0 : if( getPluginComm() )
891 0 : getPluginComm()->NPP_SetWindow( this );
892 0 : }
893 :
894 0 : PluginDescription XPlugin_Impl::fitDescription( const OUString& rURL )
895 : {
896 0 : uno::Reference< XPluginManager > xPMgr( plugin::PluginManager::create(comphelper::getComponentContext(m_xSMgr)) );
897 :
898 0 : Sequence< PluginDescription > aDescrs = xPMgr->getPluginDescriptions();
899 0 : const PluginDescription* pDescrs = aDescrs.getConstArray();
900 :
901 0 : for( int nArg = 0; nArg < m_nArgs; nArg++ )
902 : {
903 0 : if( strncmp( m_pArgn[nArg], "TYPE", 4 ) == 0 &&
904 0 : m_pArgn[nArg][4] == 0 )
905 : {
906 0 : for( int i = 0; i < aDescrs.getLength(); i++ )
907 : {
908 0 : if( pDescrs[i].Mimetype.equalsAscii( m_pArgv[nArg] ) )
909 0 : return pDescrs[i];
910 : }
911 : }
912 : }
913 :
914 0 : int nPos = rURL.lastIndexOf( (sal_Unicode)'.' );
915 0 : if( nPos != -1 )
916 : {
917 0 : OUString const aExt = rURL.copy( nPos ).toAsciiLowerCase();
918 0 : for( int i = 0; i < aDescrs.getLength(); i++ )
919 : {
920 0 : OUString aThisExt = pDescrs[ i ].Extension.toAsciiLowerCase();
921 0 : if( aThisExt.indexOf( aExt ) != -1 )
922 : {
923 0 : return pDescrs[i];
924 : }
925 0 : }
926 : }
927 0 : return PluginDescription();
928 : }
929 :
930 :
931 0 : PluginStream::PluginStream( XPlugin_Impl* pPlugin,
932 : const char* url, sal_uInt32 len, sal_uInt32 lastmod ) :
933 0 : m_pPlugin( pPlugin )
934 : {
935 0 : memset( &m_aNPStream, 0, sizeof( m_aNPStream ) );
936 0 : m_aNPStream.url = strdup( url );
937 0 : m_aNPStream.end = len;
938 0 : m_aNPStream.lastmodified = lastmod;
939 0 : }
940 :
941 0 : PluginStream::~PluginStream()
942 : {
943 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
944 :
945 0 : if( m_pPlugin && m_pPlugin->getPluginComm() )
946 : {
947 0 : m_pPlugin->getPluginComm()->NPP_DestroyStream( &m_pPlugin->getNPPInstance(),
948 0 : &m_aNPStream, NPRES_DONE );
949 0 : m_pPlugin->checkListeners( m_aNPStream.url );
950 0 : m_pPlugin->getPluginComm()->NPP_SetWindow( m_pPlugin );
951 : }
952 0 : ::free( (void*)m_aNPStream.url );
953 0 : }
954 :
955 0 : PluginInputStream::PluginInputStream( XPlugin_Impl* pPlugin,
956 : const char* url,
957 : sal_uInt32 len,
958 : sal_uInt32 lastmod ) :
959 : PluginStream( pPlugin, url, len, lastmod ),
960 : m_pContent( NULL ),
961 : m_nMode( NP_NORMAL ),
962 0 : m_nWritePos( 0 )
963 : {
964 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
965 :
966 0 : m_pPlugin->getInputStreams().push_back( this );
967 0 : OUString aTmpFile;
968 0 : osl::FileBase::createTempFile( 0, 0, &aTmpFile );
969 :
970 : // set correct extension, some plugins need that
971 0 : OUString aName( m_aNPStream.url, strlen( m_aNPStream.url ), m_pPlugin->getTextEncoding() );
972 0 : OUString aExtension;
973 0 : sal_Int32 nSepInd = aName.lastIndexOf('.');
974 0 : if( nSepInd != -1 )
975 : {
976 0 : aExtension = aName.copy( nSepInd + 1, aName.getLength() - nSepInd - 1 );
977 : }
978 0 : if( !aExtension.isEmpty() )
979 : {
980 0 : aTmpFile += aExtension;
981 : }
982 0 : m_aFileStream.Open( aTmpFile, STREAM_READ | STREAM_WRITE );
983 0 : if( ! m_aFileStream.IsOpen() )
984 : {
985 : // might be that the extension scrambled the whole filename
986 0 : osl::FileBase::createTempFile( 0, 0, &aTmpFile );
987 0 : m_aFileStream.Open( aTmpFile, STREAM_READ | STREAM_WRITE );
988 0 : }
989 0 : }
990 :
991 0 : PluginInputStream::~PluginInputStream()
992 : {
993 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
994 :
995 0 : m_pPlugin->getInputStreams().remove( this );
996 :
997 0 : OUString aFile( m_aFileStream.GetFileName() );
998 :
999 0 : m_aFileStream.Close();
1000 0 : if( m_pPlugin )
1001 : {
1002 0 : OString aFileName(OUStringToOString(aFile, m_pPlugin->getTextEncoding()));
1003 0 : if( m_pPlugin->getPluginComm() && m_nMode != -1 )
1004 : // mode -1 means either an error occurred,
1005 : // or the plugin is already disposing
1006 : {
1007 0 : m_pPlugin->getPluginComm()->addFileToDelete( aFile );
1008 0 : if( m_nMode == NP_ASFILE )
1009 : {
1010 0 : m_pPlugin->getPluginComm()->
1011 0 : NPP_StreamAsFile( &m_pPlugin->getNPPInstance(),
1012 : &m_aNPStream,
1013 0 : aFileName.getStr() );
1014 : }
1015 0 : m_pPlugin->getPluginComm()->NPP_SetWindow( m_pPlugin );
1016 0 : m_pPlugin->getInputStreams().remove( this );
1017 : }
1018 : else
1019 0 : osl::File::remove( aFile );
1020 : }
1021 : else
1022 0 : osl::File::remove( aFile );
1023 0 : if( m_pContent )
1024 0 : delete m_pContent;
1025 0 : }
1026 :
1027 0 : PluginStreamType PluginInputStream::getStreamType()
1028 : {
1029 0 : return InputStream;
1030 : }
1031 :
1032 0 : void PluginInputStream::load()
1033 : {
1034 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1035 :
1036 0 : INetURLObject aUrl;
1037 0 : aUrl.SetSmartProtocol( INET_PROT_FILE );
1038 : aUrl.SetSmartURL(
1039 0 : OUString( getStream().url,
1040 0 : strlen( getStream().url ),
1041 : RTL_TEXTENCODING_MS_1252
1042 0 : ) );
1043 : try
1044 : {
1045 : m_pContent =
1046 : new ::ucbhelper::Content(
1047 : aUrl.GetMainURL(INetURLObject::DECODE_TO_IURI),
1048 : uno::Reference< com::sun::star::ucb::XCommandEnvironment >(),
1049 : comphelper::getProcessComponentContext()
1050 0 : );
1051 0 : m_pContent->openStream( static_cast< XOutputStream* >( this ) );
1052 : }
1053 0 : catch(const com::sun::star::uno::Exception &)
1054 : {
1055 0 : }
1056 0 : }
1057 :
1058 0 : void PluginInputStream::setMode( sal_Int32 nMode )
1059 : {
1060 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1061 :
1062 0 : m_nMode = nMode;
1063 :
1064 : // invalidation by plugin
1065 0 : if( m_nMode == -1 && m_pPlugin )
1066 : {
1067 0 : m_pPlugin->getInputStreams().remove( this );
1068 0 : m_pPlugin = NULL;
1069 0 : }
1070 0 : }
1071 :
1072 0 : void PluginInputStream::writeBytes( const Sequence<sal_Int8>& Buffer ) throw(std::exception)
1073 : {
1074 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1075 :
1076 0 : m_aFileStream.Seek( STREAM_SEEK_TO_END );
1077 0 : m_aFileStream.Write( Buffer.getConstArray(), Buffer.getLength() );
1078 :
1079 0 : if( m_nMode == NP_SEEK )
1080 : // hold reference, streem gets destroyed in NPN_DestroyStream
1081 0 : m_xSelf = this;
1082 :
1083 0 : if( m_nMode == -1 || !m_pPlugin->getPluginComm() )
1084 0 : return;
1085 :
1086 0 : sal_Size nPos = m_aFileStream.Tell();
1087 0 : sal_Size nBytes = 0;
1088 0 : while( m_nMode != NP_ASFILEONLY &&
1089 0 : m_nWritePos < nPos &&
1090 0 : (nBytes = m_pPlugin->getPluginComm()-> NPP_WriteReady(
1091 0 : &m_pPlugin->getNPPInstance(), &m_aNPStream )) > 0 )
1092 : {
1093 0 : nBytes = (nBytes > nPos - m_nWritePos) ? nPos - m_nWritePos : nBytes;
1094 :
1095 0 : boost::scoped_array<char> pBuffer(new char[ nBytes ]);
1096 0 : m_aFileStream.Seek( m_nWritePos );
1097 0 : nBytes = m_aFileStream.Read( pBuffer.get(), nBytes );
1098 :
1099 0 : int32_t nBytesRead = 0;
1100 : try
1101 : {
1102 0 : nBytesRead = m_pPlugin->getPluginComm()->NPP_Write(
1103 0 : &m_pPlugin->getNPPInstance(), &m_aNPStream, m_nWritePos, nBytes, pBuffer.get() );
1104 : }
1105 0 : catch( ... )
1106 : {
1107 0 : nBytesRead = 0;
1108 : }
1109 :
1110 0 : if( nBytesRead < 0 )
1111 : {
1112 0 : m_nMode = -1;
1113 0 : return;
1114 : }
1115 :
1116 0 : m_nWritePos += nBytesRead;
1117 0 : }
1118 : }
1119 :
1120 0 : void PluginInputStream::closeOutput() throw(std::exception)
1121 : {
1122 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1123 :
1124 0 : flush();
1125 0 : m_xSource = uno::Reference< com::sun::star::io::XActiveDataSource >();
1126 0 : }
1127 :
1128 0 : sal_uInt32 PluginInputStream::read( sal_uInt32 offset, sal_Int8* buffer, sal_uInt32 size )
1129 : {
1130 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1131 :
1132 0 : if( m_nMode != NP_SEEK )
1133 0 : return 0;
1134 :
1135 0 : m_aFileStream.Seek( offset );
1136 0 : return m_aFileStream.Read( buffer, size );
1137 : }
1138 :
1139 0 : void PluginInputStream::flush(void) throw(std::exception)
1140 : {
1141 0 : }
1142 :
1143 0 : PluginOutputStream::PluginOutputStream( XPlugin_Impl* pPlugin,
1144 : const char* url,
1145 : sal_uInt32 len,
1146 : sal_uInt32 lastmod ) :
1147 : PluginStream( pPlugin, url, len, lastmod ),
1148 0 : m_xStream( pPlugin->getServiceManager()->createInstance("com.sun.star.io.DataOutputStream"), UNO_QUERY )
1149 : {
1150 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1151 :
1152 0 : m_pPlugin->getOutputStreams().push_back( this );
1153 0 : }
1154 :
1155 0 : PluginOutputStream::~PluginOutputStream()
1156 : {
1157 0 : Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1158 :
1159 0 : m_pPlugin->getOutputStreams().remove( this );
1160 0 : }
1161 :
1162 0 : PluginStreamType PluginOutputStream::getStreamType()
1163 : {
1164 0 : return OutputStream;
1165 6 : }
1166 :
1167 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|