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