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