bump product version to 5.0.4.1
[LibreOffice.git] / extensions / source / plugin / base / xplugin.cxx
blob9933739cddca7c82dff37a4187ff435d4b396f0b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
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.
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).
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.
27 ************************************************************************/
29 #ifdef AIX
30 #define _LINUX_SOURCE_COMPAT
31 #include <sys/timer.h>
32 #undef _LINUX_SOURCE_COMPAT
33 #endif
35 #ifdef WNT
36 #include <prewin.h>
37 #include <postwin.h>
38 #endif
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>
45 #include <cppuhelper/queryinterface.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <plugin/impl.hxx>
48 #include <sal/log.hxx>
49 #include <ucbhelper/content.hxx>
50 #include <tools/urlobj.hxx>
51 #include <vcl/svapp.hxx>
52 #include <salhelper/timer.hxx>
53 #include <osl/file.hxx>
55 #ifdef UNX
56 #include <sys/types.h>
57 #include <sys/socket.h>
58 #endif
60 #if OSL_DEBUG_LEVEL > 1
61 #include <stdio.h>
62 #endif
64 #include <boost/scoped_array.hpp>
66 using namespace com::sun::star;
67 using namespace com::sun::star::io;
68 using namespace com::sun::star::beans;
69 using namespace com::sun::star::plugin;
70 using namespace osl;
72 class PluginDisposer : public salhelper::Timer
74 private:
75 XPlugin_Impl* m_pPlugin;
77 virtual void SAL_CALL onShot() SAL_OVERRIDE;
78 public:
79 PluginDisposer( XPlugin_Impl* pPlugin ) :
80 salhelper::Timer( salhelper::TTimeValue( 2, 0 ),
81 salhelper::TTimeValue( 2, 0 ) ),
82 m_pPlugin( pPlugin )
83 { start(); }
84 virtual ~PluginDisposer() {}
87 void PluginDisposer::onShot()
89 if( m_pPlugin )
91 if( m_pPlugin->isDisposable() )
93 Application::PostUserEvent( LINK( m_pPlugin, XPlugin_Impl, secondLevelDispose ), (void*)m_pPlugin );
96 else
97 release();
100 Any XPlugin_Impl::queryInterface( const Type& type ) throw( RuntimeException, std::exception )
102 return OWeakAggObject::queryInterface( type );
105 Any XPlugin_Impl::queryAggregation( const Type& type ) throw( RuntimeException, std::exception )
107 Any aRet( cppu::queryInterface( type, static_cast< XPlugin* >(this) ) );
108 if( ! aRet.hasValue() )
109 aRet = PluginControl_Impl::queryAggregation( type );
110 return aRet;
114 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 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 m_bIsDisposed( false )
129 memset( &m_aInstance, 0, sizeof( m_aInstance ) );
130 memset( &m_aNPWindow, 0, sizeof( m_aNPWindow ) );
132 m_xModel = new PluginModel();
133 uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
134 xPS->addPropertyChangeListener( OUString(), this );
136 Guard< Mutex > aGuard( ::PluginManager::get().getPluginMutex() );
137 ::PluginManager::get().getPlugins().push_back( this );
140 void XPlugin_Impl::destroyInstance()
142 Guard< Mutex > aGuard( m_aMutex );
144 NPSavedData* pSavedData = NULL;
146 destroyStreams();
147 if( getPluginComm() )
149 getPluginComm()->NPP_Destroy( this, &pSavedData );
150 getPluginComm()->decRef();
151 m_pPluginComm = NULL;
154 freeArgs();
156 while( m_aPEventListeners.size() )
158 delete *m_aPEventListeners.begin();
159 m_aPEventListeners.pop_front();
163 XPlugin_Impl::~XPlugin_Impl()
165 destroyInstance();
168 void XPlugin_Impl::checkListeners( const char* normalizedURL )
170 if( ! normalizedURL )
171 return;
173 Guard< Mutex > aGuard( m_aMutex );
175 std::list<PluginEventListener*>::iterator iter;
176 for( iter = m_aPEventListeners.begin();
177 iter != m_aPEventListeners.end();
178 ++iter )
180 if( ! strcmp( normalizedURL, (*iter)->getURL() ) ||
181 ! strcmp( normalizedURL, (*iter)->getNormalizedURL() ) )
183 (*iter)->disposing( com::sun::star::lang::EventObject() );
184 delete *iter;
185 m_aPEventListeners.remove( *iter );
186 return;
191 IMPL_LINK( XPlugin_Impl, secondLevelDispose, XPlugin_Impl*, /*pThis*/ )
193 Guard< Mutex > aGuard( m_aMutex );
195 // may have become undisposable between PostUserEvent and here
196 // or may have disposed and receive a second UserEvent
197 std::list<XPlugin_Impl*>& rList = ::PluginManager::get().getPlugins();
198 std::list<XPlugin_Impl*>::iterator iter;
201 Guard< Mutex > aPluginGuard( ::PluginManager::get().getPluginMutex() );
202 for( iter = rList.begin(); iter != rList.end(); ++iter )
204 if( *iter == this )
205 break;
207 if( iter == rList.end() || ! isDisposable() )
208 return 0;
211 if (m_pDisposer)
213 m_pDisposer->release();
214 m_pDisposer = NULL;
217 uno::Reference< XPlugin > xProtection( this );
218 uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
219 xPS->removePropertyChangeListener( OUString(), this );
221 Guard< Mutex > aPluginGuard( ::PluginManager::get().getPluginMutex() );
222 rList.remove( this );
224 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 destroyInstance();
230 PluginControl_Impl::dispose();
231 return 0;
234 void XPlugin_Impl::dispose() throw(std::exception)
236 Guard< Mutex > aGuard( m_aMutex );
238 if (m_bIsDisposed || !getPluginComm())
239 return;
240 m_bIsDisposed = true;
242 if( isDisposable() )
243 secondLevelDispose( this );
244 else
246 m_pDisposer = new PluginDisposer( this );
247 m_pDisposer->acquire();
251 void XPlugin_Impl::initArgs( const Sequence< OUString >& argn,
252 const Sequence< OUString >& argv,
253 sal_Int16 mode )
255 m_aPluginMode = mode;
257 m_nArgs = argn.getLength();
258 m_pArgn = new const char*[m_nArgs];
259 m_pArgv = new const char*[m_nArgs];
260 const OUString* pUArgn = argn.getConstArray();
261 const OUString* pUArgv = argv.getConstArray();
262 for( int i = 0; i < m_nArgs; i++ )
264 m_pArgn[i] = strdup(
265 OUStringToOString( pUArgn[i], m_aEncoding ).getStr()
267 m_pArgv[i] = strdup(
268 OUStringToOString( pUArgv[i], m_aEncoding ).getStr()
273 void XPlugin_Impl::freeArgs()
275 if( m_nArgs > 0 )
277 for( ; m_nArgs--; )
279 free( (void*)m_pArgn[m_nArgs] );
280 free( (void*)m_pArgv[m_nArgs] );
282 delete [] m_pArgn;
283 delete [] m_pArgv;
287 void XPlugin_Impl::prependArg( const char* pName, const char* pValue )
289 const char** pNewNames = new const char*[m_nArgs+1];
290 const char** pNewValues = new const char*[m_nArgs+1];
292 pNewNames[0] = strdup( pName );
293 pNewValues[0] = strdup( pValue );
294 for( int nIndex = 0; nIndex < m_nArgs; ++nIndex )
296 pNewNames[nIndex+1] = m_pArgn[nIndex];
297 pNewValues[nIndex+1]= m_pArgv[nIndex];
299 // free old arrays
300 delete [] m_pArgn;
301 delete [] m_pArgv;
302 // set new arrays
303 m_pArgn = pNewNames;
304 m_pArgv = pNewValues;
305 // set new number of arguments
306 m_nArgs++;
307 #if OSL_DEBUG_LEVEL > 1
308 fprintf( stderr, "inserted %s=%s\n", pNewNames[0], pNewValues[0] );
309 #endif
312 void XPlugin_Impl::handleSpecialArgs()
314 // special handling for real audio which needs a lot of parameters
315 // or won't function at all
316 if( m_aDescription.Mimetype == "audio/x-pn-realaudio-plugin" && m_nArgs < 1 )
318 OUString aURL;
319 if( m_xModel.is() )
323 uno::Reference< XPropertySet > xProp( m_xModel, UNO_QUERY );
324 Any aProp = xProp->getPropertyValue("URL");
325 aProp >>= aURL;
327 catch(const UnknownPropertyException &)
332 if( !aURL.isEmpty() )
334 // set new args, old args need not be freed as there were none set
335 m_nArgs = 6;
336 m_pArgn = new const char*[m_nArgs];
337 m_pArgv = new const char*[m_nArgs];
339 // SRC
340 m_pArgn[0] = strdup( "SRC" );
341 m_pArgv[0] = strdup( OUStringToOString( aURL, m_aEncoding ).getStr() );
342 // WIDTH
343 m_pArgn[1] = strdup( "WIDTH" );
344 m_pArgv[1] = strdup( "200" );
345 // HEIGHT
346 m_pArgn[2] = strdup( "HEIGHT" );
347 m_pArgv[2] = strdup( "200" );
348 // CONTROLS
349 m_pArgn[3] = strdup( "CONTROLS" );
350 m_pArgv[3] = strdup( "PlayButton,StopButton,ImageWindow" );
351 // AUTOSTART
352 m_pArgn[4] = strdup( "AUTOSTART" );
353 m_pArgv[4] = strdup( "TRUE" );
354 // NOJAVA
355 m_pArgn[5] = strdup( "NOJAVA" );
356 m_pArgv[5] = strdup( "TRUE" );
359 // #69333# special for pdf
360 else if( m_aDescription.Mimetype == "application/pdf" )
361 m_aPluginMode = PluginMode::FULL;
363 // see if we have a TYPE tag
364 int nIndex;
365 for( nIndex = 0; nIndex < m_nArgs; ++nIndex )
366 if( m_pArgn[nIndex][0] == 'T' &&
367 m_pArgn[nIndex][1] == 'Y' &&
368 m_pArgn[nIndex][2] == 'P' &&
369 m_pArgn[nIndex][3] == 'E' &&
370 m_pArgn[nIndex][4] == 0 )
371 break;
372 if( nIndex >= m_nArgs )
374 // TYPE
375 prependArg( "TYPE", OUStringToOString( m_aDescription.Mimetype, m_aEncoding ).getStr() );
378 // see if we have a SRC tag
379 for( nIndex = 0; nIndex < m_nArgs; ++nIndex )
380 if( m_pArgn[nIndex][0] == 'S' &&
381 m_pArgn[nIndex][1] == 'R' &&
382 m_pArgn[nIndex][2] == 'C' &&
383 m_pArgn[nIndex][3] == 0 )
384 break;
385 if( nIndex >= m_nArgs )
387 // need a SRC parameter (as all browser set one on the plugin
388 OUString aURL;
389 if( m_xModel.is() )
393 uno::Reference< XPropertySet > xProp( m_xModel, UNO_QUERY );
394 Any aProp = xProp->getPropertyValue("URL");
395 aProp >>= aURL;
397 catch(const UnknownPropertyException &)
402 if( !aURL.isEmpty() )
404 // SRC
405 prependArg( "SRC", OUStringToOString( aURL, m_aEncoding ).getStr() );
410 void XPlugin_Impl::initInstance( const PluginDescription& rDescription,
411 const Sequence< OUString >& argn,
412 const Sequence< OUString >& argv,
413 sal_Int16 mode )
415 Guard< Mutex > aGuard( m_aMutex );
417 m_aDescription = rDescription;
418 initArgs( argn, argv, mode );
419 handleSpecialArgs();
422 void XPlugin_Impl::initInstance( const OUString& rURL,
423 const Sequence< OUString >& argn,
424 const Sequence< OUString >& argv,
425 sal_Int16 mode )
427 Guard< Mutex > aGuard( m_aMutex );
429 initArgs( argn, argv, mode );
430 m_aDescription = fitDescription( rURL );
432 m_xModel = new PluginModel( rURL, m_aDescription.Mimetype );
433 handleSpecialArgs();
436 void XPlugin_Impl::modelChanged()
438 Guard< Mutex > aGuard( m_aMutex );
440 m_nProvidingState = PROVIDING_MODEL_UPDATE;
442 m_aDescription = fitDescription( getCreationURL() );
443 destroyInstance();
444 if( m_aDescription.Mimetype.isEmpty() )
446 m_nProvidingState = PROVIDING_NONE;
447 return;
450 OUString aURL = getCreationURL();
451 provideNewStream( m_aDescription.Mimetype,
452 uno::Reference< XActiveDataSource >(),
453 aURL,
454 0, 0, aURL.startsWith("file:") );
455 m_nProvidingState = PROVIDING_NONE;
458 OUString XPlugin_Impl::getCreationURL()
460 Guard< Mutex > aGuard( m_aMutex );
462 OUString aRet;
463 uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
464 if( xPS.is() )
466 Any aValue = xPS->getPropertyValue("URL");
467 aValue >>= aRet;
469 return aRet;
473 sal_Bool XPlugin_Impl::setModel( const uno::Reference< com::sun::star::awt::XControlModel > & Model )
474 throw( RuntimeException, std::exception )
476 Guard< Mutex > aGuard( m_aMutex );
478 uno::Reference< com::sun::star::beans::XPropertySet > xPS( Model, UNO_QUERY );
479 if( ! xPS.is() )
480 return sal_False;
482 if( !getCreationURL().isEmpty() )
484 m_xModel = Model;
485 modelChanged();
486 xPS->addPropertyChangeListener( OUString(), this );
487 return sal_True;
489 return sal_False;
492 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 )
495 Guard< Mutex > aGuard( m_aMutex );
497 if( ! _xPeer.is() )
499 if( ! Parent.is() )
500 throw RuntimeException();
501 PluginControl_Impl::createPeer( xToolkit, Parent );
505 void XPlugin_Impl::loadPlugin()
507 Guard< Mutex > aGuard( m_aMutex );
509 std::list<PluginComm*>::iterator iter;
510 for( iter = ::PluginManager::get().getPluginComms().begin();
511 iter != ::PluginManager::get().getPluginComms().end(); ++iter )
513 if( OStringToOUString( (*iter)->getLibName(), m_aEncoding ) == m_aDescription.PluginName )
515 setPluginComm( *iter );
516 break;
519 const SystemEnvData* pEnvData = getSysChildSysData();
520 #if defined( UNX ) && !(defined(MACOSX))
521 if (pEnvData->pDisplay) // headless?
523 XSync( static_cast<Display*>(pEnvData->pDisplay), False );
525 #endif
526 if( ! getPluginComm() )
528 if( !m_aDescription.PluginName.isEmpty() )
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 PluginComm* pComm = NULL;
537 int sv[2];
538 if( !socketpair( AF_UNIX, SOCK_STREAM, 0, sv ) )
539 pComm = new UnxPluginComm( m_aDescription.Mimetype,
540 m_aDescription.PluginName,
541 (Window)pEnvData->aWindow,
542 sv[0],
543 sv[1]
546 SAL_WARN_IF( !pComm, "extensions.plugin", "no PluginComm");
547 if (!pComm)
548 return;
550 #elif defined WNT
551 PluginComm* pComm = new PluginComm_Impl( m_aDescription.Mimetype,
552 m_aDescription.PluginName,
553 (HWND)pEnvData->hWnd );
554 #endif
556 setPluginComm( pComm );
558 else
559 return;
562 getPluginComm()->
563 NPP_New( const_cast<char*>(OUStringToOString( m_aDescription.Mimetype,
564 m_aEncoding).getStr()),
565 &getNPPInstance(),
566 m_aPluginMode == PluginMode::FULL ? NP_FULL : NP_EMBED,
567 ::sal::static_int_cast< int16_t, int >( m_nArgs ),
568 (char**)(m_nArgs ? m_pArgn : NULL),
569 (char**)(m_nArgs ? m_pArgv : NULL),
570 NULL );
571 #ifdef MACOSX
572 // m_aNPWindow is set up in the MacPluginComm from the view
573 SetSysPlugDataParentView(*pEnvData);
574 #elif defined( UNX )
575 if (pEnvData->pDisplay) // headless?
577 XSync( static_cast<Display*>(pEnvData->pDisplay), False );
578 m_aNPWindow.window = reinterpret_cast<void*>(pEnvData->aWindow);
580 else
582 m_aNPWindow.window = NULL;
584 m_aNPWindow.ws_info = NULL;
585 #else
586 m_aNPWindow.window = (void*)pEnvData->hWnd;
587 #endif
588 com::sun::star::awt::Rectangle aPosSize = getPosSize();
590 for( int i = 0; i < m_nArgs; i++ )
592 OString aName( m_pArgn[i] );
593 if( aName.equalsIgnoreAsciiCase( "width" ) )
595 OString aValue( m_pArgv[i] );
596 aPosSize.Width = aValue.toInt32();
598 else if( aName.equalsIgnoreAsciiCase( "height" ) )
600 OString aValue( m_pArgv[i] );
601 aPosSize.Height = aValue.toInt32();
605 m_aNPWindow.clipRect.top = 0;
606 m_aNPWindow.clipRect.left = 0;
607 m_aNPWindow.clipRect.bottom = ::sal::static_int_cast< uint16_t, sal_Int32 >( aPosSize.Height );
608 m_aNPWindow.clipRect.right = ::sal::static_int_cast< uint16_t, sal_Int32 >( aPosSize.Width );
609 m_aNPWindow.type = NPWindowTypeWindow;
611 m_aNPWindow.x = 0;
612 m_aNPWindow.y = 0;
613 m_aNPWindow.width = aPosSize.Width ? aPosSize.Width : 600;
614 m_aNPWindow.height = aPosSize.Height ? aPosSize.Height : 600;
616 getPluginComm()->NPP_SetWindow( this );
619 void XPlugin_Impl::destroyStreams()
621 Guard< Mutex > aGuard( m_aMutex );
623 // streams remove themselves from this list when deleted
624 while( m_aOutputStreams.size() )
625 delete *m_aOutputStreams.begin();
627 // input streams are XOutputStreams, they cannot be simply deleted
628 std::list<PluginInputStream*> aLocalList( m_aInputStreams );
629 for( std::list<PluginInputStream*>::iterator it = aLocalList.begin();
630 it != aLocalList.end(); ++it )
631 (*it)->setMode( -1 );
634 PluginStream* XPlugin_Impl::getStreamFromNPStream( NPStream* stream )
636 Guard< Mutex > aGuard( m_aMutex );
638 std::list<PluginInputStream*>::iterator iter;
639 for( iter = m_aInputStreams.begin(); iter != m_aInputStreams.end(); ++iter )
640 if( &(*iter)->getStream() == stream )
641 return *iter;
643 std::list<PluginOutputStream*>::iterator iter2;
644 for( iter2 = m_aOutputStreams.begin(); iter2 != m_aOutputStreams.end(); ++iter2 )
645 if( &(*iter2)->getStream() == stream )
646 return *iter2;
648 return NULL;
651 sal_Bool XPlugin_Impl::provideNewStream(const OUString& mimetype,
652 const uno::Reference< com::sun::star::io::XActiveDataSource > & stream,
653 const OUString& url, sal_Int32 length,
654 sal_Int32 lastmodified, sal_Bool isfile) throw(std::exception)
657 Guard< Mutex > aGuard( m_aMutex );
658 bool bRet = false;
660 if( m_nProvidingState != PROVIDING_NONE )
662 m_nProvidingState = PROVIDING_NOW;
663 Any aAny;
664 aAny <<= url;
665 uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
666 if( xPS.is() )
670 xPS->setPropertyValue("URL", aAny );
671 aAny <<= mimetype;
672 xPS->setPropertyValue("TYPE", aAny );
674 catch(...)
679 m_nProvidingState = PROVIDING_NOW;
681 OString aMIME;
682 if( !mimetype.isEmpty() )
683 aMIME = OUStringToOString( mimetype, m_aEncoding );
684 else
685 aMIME = OUStringToOString( m_aDescription.Mimetype, m_aEncoding );
687 OString aURL = OUStringToOString( url, m_aEncoding );
689 // check whether there is a notifylistener for this stream
690 // this means that the strema is created from the plugin
691 // via NPN_GetURLNotify or NPN_PostURLNotify
692 std::list<PluginEventListener*>::iterator iter;
693 for( iter = m_aPEventListeners.begin();
694 iter != m_aPEventListeners.end();
695 ++iter )
697 if( (*iter)->getNormalizedURL() == aURL )
699 aURL = (*iter)->getURL();
700 break;
704 if( ! m_pPluginComm )
706 loadPlugin();
707 if( !m_aLastGetUrl.isEmpty() && m_aLastGetUrl == aURL )
709 // plugin is pulling data, don't push the same stream;
710 // this complicated method could have been avoided if
711 // all plugins respected the SRC parameter; but e.g.
712 // acrobat reader plugin does not
713 m_nProvidingState = PROVIDING_NONE;
714 return sal_True;
717 if( ! m_pPluginComm )
718 return sal_False;
720 if( url.isEmpty() )
721 // this is valid if the plugin is supposed to
722 // pull data (via e.g. NPN_GetURL)
723 return sal_True;
725 // set mimetype on model
727 uno::Reference< com::sun::star::beans::XPropertySet > xPS( m_xModel, UNO_QUERY );
728 if( xPS.is() )
732 Any aAny;
733 aAny <<= m_aDescription.Mimetype;
734 xPS->setPropertyValue("TYPE", aAny );
736 catch(...)
742 // there may be plugins that can use the file length information,
743 // but currently none are known. Since this file opening/seeking/closing
744 // is rather costly, it is not implemented. If there are plugins known to
745 // make use of the file length, simply put it in
747 PluginInputStream* pStream = new PluginInputStream( this, aURL.getStr(),
748 length, lastmodified );
749 uno::Reference< com::sun::star::io::XOutputStream > xNewStream( pStream );
751 if( iter != m_aPEventListeners.end() )
752 pStream->getStream().notifyData = (*iter)->getNotifyData();
754 uint16_t stype = 0;
756 // special handling acrobat reader
757 // presenting a seekable stream to it does not seem to work correctly
758 if( aMIME.equals( "application/pdf" ) )
759 isfile = sal_False;
761 #if OSL_DEBUG_LEVEL > 1
762 fprintf( stderr,
763 "new stream \"%s\" of MIMEType \"%s\"\n"
764 "for plugin \"%s\"\n"
765 "seekable = %s, length = %" SAL_PRIdINT32 "\n",
766 aURL.getStr(), aMIME.getStr(), getPluginComm()->getLibName().getStr(),
767 isfile ? "true" : "false", length );
769 #endif
770 if( ! m_pPluginComm->NPP_NewStream( &m_aInstance,
771 const_cast<char*>(aMIME.getStr()),
772 &pStream->getStream(), isfile,
773 &stype ) )
775 #if OSL_DEBUG_LEVEL > 1
776 const char* pType;
777 switch( stype )
779 case NP_NORMAL: pType = "NP_NORMAL";break;
780 case NP_SEEK: pType = "NP_SEEK";break;
781 case NP_ASFILE: pType = "NP_ASFILE";break;
782 case NP_ASFILEONLY: pType = "NP_ASFILEONLY";break;
783 default: pType = "unknown!!!";
785 fprintf( stderr, "Plugin wants it in Mode %s\n", pType );
786 #endif
787 if( isfile && stype == NP_ASFILEONLY )
789 OString aFileName;
790 if( url.startsWith("file:") )
792 OUString aSysName;
793 osl_getSystemPathFromFileURL( url.pData, &aSysName.pData );
794 aFileName = OUStringToOString( aSysName, m_aEncoding );
796 else
797 aFileName = OUStringToOString( url, m_aEncoding );
798 m_pPluginComm->
799 NPP_StreamAsFile( &m_aInstance,
800 &pStream->getStream(),
801 aFileName.getStr() );
803 else
805 pStream->setMode( stype );
807 if( ! stream.is() )
809 // stream has to be loaded by PluginStream itself via UCB
810 pStream->load();
812 else
814 uno::Reference< com::sun::star::io::XConnectable > xConnectable( stream, UNO_QUERY );
815 pStream->setPredecessor( xConnectable );
816 if( xConnectable.is() )
818 xConnectable->setSuccessor( static_cast< com::sun::star::io::XConnectable* >(pStream) );
819 while( xConnectable->getPredecessor().is() )
820 xConnectable = xConnectable->getPredecessor();
822 stream->setOutputStream( xNewStream );
823 pStream->setSource( stream );
824 uno::Reference< com::sun::star::io::XActiveDataControl > xController;
825 if( xConnectable.is() )
826 xController = uno::Reference< com::sun::star::io::XActiveDataControl >( xConnectable, UNO_QUERY );
827 else
828 xController = uno::Reference< com::sun::star::io::XActiveDataControl >( stream, UNO_QUERY );
830 if( xController.is() )
831 xController->start();
834 bRet = true;
837 m_nProvidingState = PROVIDING_NONE;
839 return bRet;
842 void XPlugin_Impl::disposing( const com::sun::star::lang::EventObject& /*rSource*/ ) throw(std::exception)
846 void XPlugin_Impl::propertyChange(const com::sun::star::beans::PropertyChangeEvent& rEvent)
847 throw (css::uno::RuntimeException, std::exception)
849 Guard< Mutex > aGuard( m_aMutex );
851 if( rEvent.PropertyName == "URL" )
853 OUString aStr;
854 rEvent.NewValue >>= aStr;
855 if( m_nProvidingState == PROVIDING_NONE )
857 if( aStr != m_aURL )
859 m_aURL = aStr;
860 modelChanged();
866 void XPlugin_Impl::setPluginContext( const uno::Reference< XPluginContext > & rContext )
868 m_rBrowserContext = rContext;
871 void XPlugin_Impl::setPosSize( sal_Int32 nX_, sal_Int32 nY_, sal_Int32 nWidth_, sal_Int32 nHeight_, sal_Int16 nFlags )
872 throw( RuntimeException, std::exception )
874 Guard< Mutex > aGuard( m_aMutex );
876 #if OSL_DEBUG_LEVEL > 1
877 fprintf( stderr, "XPlugin_Impl::setPosSize( %" SAL_PRIdINT32 ", %" SAL_PRIdINT32 ", %" SAL_PRIdINT32 ", %" SAL_PRIdINT32 ", %d )\n",
878 nX_, nY_, nWidth_, nHeight_, nFlags );
879 #endif
881 PluginControl_Impl::setPosSize(nX_, nY_, nWidth_, nHeight_, nFlags);
883 m_aNPWindow.x = 0;
884 m_aNPWindow.y = 0;
885 m_aNPWindow.width = nWidth_;
886 m_aNPWindow.height = nHeight_;
887 m_aNPWindow.clipRect.top = 0;
888 m_aNPWindow.clipRect.left = 0;
889 m_aNPWindow.clipRect.right = ::sal::static_int_cast< uint16_t, sal_Int32 >( nWidth_ );
890 m_aNPWindow.clipRect.bottom = ::sal::static_int_cast< uint16_t, sal_Int32 >( nHeight_ );
892 if( getPluginComm() )
893 getPluginComm()->NPP_SetWindow( this );
896 PluginDescription XPlugin_Impl::fitDescription( const OUString& rURL )
898 uno::Reference< XPluginManager > xPMgr( plugin::PluginManager::create(comphelper::getComponentContext(m_xSMgr)) );
900 Sequence< PluginDescription > aDescrs = xPMgr->getPluginDescriptions();
901 const PluginDescription* pDescrs = aDescrs.getConstArray();
903 for( int nArg = 0; nArg < m_nArgs; nArg++ )
905 if( strncmp( m_pArgn[nArg], "TYPE", 4 ) == 0 &&
906 m_pArgn[nArg][4] == 0 )
908 for( int i = 0; i < aDescrs.getLength(); i++ )
910 if( pDescrs[i].Mimetype.equalsAscii( m_pArgv[nArg] ) )
911 return pDescrs[i];
916 int nPos = rURL.lastIndexOf( (sal_Unicode)'.' );
917 if( nPos != -1 )
919 OUString const aExt = rURL.copy( nPos ).toAsciiLowerCase();
920 for( int i = 0; i < aDescrs.getLength(); i++ )
922 OUString aThisExt = pDescrs[ i ].Extension.toAsciiLowerCase();
923 if( aThisExt.indexOf( aExt ) != -1 )
925 return pDescrs[i];
929 return PluginDescription();
933 PluginStream::PluginStream( XPlugin_Impl* pPlugin,
934 const char* url, sal_uInt32 len, sal_uInt32 lastmod)
935 : m_wPlugin(static_cast< ::cppu::OWeakObject* >(pPlugin))
936 , m_pPlugin(pPlugin)
939 memset( &m_aNPStream, 0, sizeof( m_aNPStream ) );
940 m_aNPStream.url = strdup( url );
941 m_aNPStream.end = len;
942 m_aNPStream.lastmodified = lastmod;
945 PluginStream::~PluginStream()
947 uno::Reference<uno::XInterface> const xPlugin(m_wPlugin);
948 XPlugin_Impl *const pPlugin(m_pPlugin);
949 if (xPlugin.is() && pPlugin)
951 Guard< Mutex > aGuard( pPlugin->getMutex() );
953 if( m_pPlugin && m_pPlugin->getPluginComm() )
955 m_pPlugin->getPluginComm()->NPP_DestroyStream( &m_pPlugin->getNPPInstance(),
956 &m_aNPStream, NPRES_DONE );
957 m_pPlugin->checkListeners( m_aNPStream.url );
958 m_pPlugin->getPluginComm()->NPP_SetWindow( m_pPlugin );
961 ::free( (void*)m_aNPStream.url );
964 PluginInputStream::PluginInputStream( XPlugin_Impl* pPlugin,
965 const char* url,
966 sal_uInt32 len,
967 sal_uInt32 lastmod ) :
968 PluginStream( pPlugin, url, len, lastmod ),
969 m_pContent( NULL ),
970 m_nMode( NP_NORMAL ),
971 m_nWritePos( 0 )
973 assert(m_pPlugin);
974 Guard< Mutex > aGuard( m_pPlugin->getMutex() );
976 m_pPlugin->getInputStreams().push_back( this );
977 OUString aTmpFile;
978 osl::FileBase::createTempFile( 0, 0, &aTmpFile );
980 // set correct extension, some plugins need that
981 OUString aName( m_aNPStream.url, strlen( m_aNPStream.url ), m_pPlugin->getTextEncoding() );
982 OUString aExtension;
983 sal_Int32 nSepInd = aName.lastIndexOf('.');
984 if( nSepInd != -1 )
986 aExtension = aName.copy( nSepInd + 1, aName.getLength() - nSepInd - 1 );
988 if( !aExtension.isEmpty() )
990 aTmpFile += aExtension;
992 m_aFileStream.Open( aTmpFile, StreamMode::READ | StreamMode::WRITE );
993 if( ! m_aFileStream.IsOpen() )
995 // might be that the extension scrambled the whole filename
996 osl::FileBase::createTempFile( 0, 0, &aTmpFile );
997 m_aFileStream.Open( aTmpFile, StreamMode::READ | StreamMode::WRITE );
1001 PluginInputStream::~PluginInputStream()
1003 OUString aFile( m_aFileStream.GetFileName() );
1005 m_aFileStream.Close();
1007 uno::Reference<uno::XInterface> const xPlugin(m_wPlugin);
1008 XPlugin_Impl *const pPlugin(m_pPlugin);
1009 if (xPlugin.is() && pPlugin)
1011 Guard< Mutex > aGuard( pPlugin->getMutex() );
1013 pPlugin->getInputStreams().remove( this );
1015 if( m_pPlugin )
1017 OString aFileName(OUStringToOString(aFile, m_pPlugin->getTextEncoding()));
1018 if( m_pPlugin->getPluginComm() && m_nMode != -1 )
1019 // mode -1 means either an error occurred,
1020 // or the plugin is already disposing
1022 m_pPlugin->getPluginComm()->addFileToDelete( aFile );
1023 if( m_nMode == NP_ASFILE )
1025 m_pPlugin->getPluginComm()->
1026 NPP_StreamAsFile( &m_pPlugin->getNPPInstance(),
1027 &m_aNPStream,
1028 aFileName.getStr() );
1030 m_pPlugin->getPluginComm()->NPP_SetWindow( m_pPlugin );
1031 m_pPlugin->getInputStreams().remove( this );
1033 else
1034 osl::File::remove( aFile );
1036 else
1037 osl::File::remove( aFile );
1039 else
1040 osl::File::remove( aFile );
1041 if( m_pContent )
1042 delete m_pContent;
1045 PluginStreamType PluginInputStream::getStreamType()
1047 return InputStream;
1050 void PluginInputStream::load()
1052 Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1054 INetURLObject aUrl;
1055 aUrl.SetSmartProtocol( INetProtocol::File );
1056 aUrl.SetSmartURL(
1057 OUString( getStream().url,
1058 strlen( getStream().url ),
1059 RTL_TEXTENCODING_MS_1252
1060 ) );
1063 m_pContent =
1064 new ::ucbhelper::Content(
1065 aUrl.GetMainURL(INetURLObject::DECODE_TO_IURI),
1066 uno::Reference< com::sun::star::ucb::XCommandEnvironment >(),
1067 comphelper::getProcessComponentContext()
1069 m_pContent->openStream( static_cast< XOutputStream* >( this ) );
1071 catch(const com::sun::star::uno::Exception &)
1076 void PluginInputStream::setMode( sal_Int32 nMode )
1078 assert(m_pPlugin); // this is currently only called from two places...
1079 Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1081 m_nMode = nMode;
1083 // invalidation by plugin
1084 if (m_nMode == -1)
1086 m_pPlugin->getInputStreams().remove( this );
1087 m_pPlugin = NULL;
1088 m_wPlugin.clear();
1092 void PluginInputStream::writeBytes( const Sequence<sal_Int8>& Buffer ) throw(std::exception)
1094 uno::Reference<uno::XInterface> const xPlugin(m_wPlugin);
1095 XPlugin_Impl *const pPlugin(m_pPlugin);
1096 if (!xPlugin.is() || !pPlugin)
1097 return;
1099 Guard< Mutex > aGuard( pPlugin->getMutex() );
1101 m_aFileStream.Seek( STREAM_SEEK_TO_END );
1102 m_aFileStream.Write( Buffer.getConstArray(), Buffer.getLength() );
1104 if( m_nMode == NP_SEEK )
1105 // hold reference, streem gets destroyed in NPN_DestroyStream
1106 m_xSelf = this;
1108 if( m_nMode == -1 || !m_pPlugin->getPluginComm() )
1109 return;
1111 sal_Size nPos = m_aFileStream.Tell();
1112 sal_Size nBytes = 0;
1113 while( m_nMode != NP_ASFILEONLY &&
1114 m_nWritePos < nPos &&
1115 (nBytes = m_pPlugin->getPluginComm()-> NPP_WriteReady(
1116 &m_pPlugin->getNPPInstance(), &m_aNPStream )) > 0 )
1118 nBytes = (nBytes > nPos - m_nWritePos) ? nPos - m_nWritePos : nBytes;
1120 boost::scoped_array<char> pBuffer(new char[ nBytes ]);
1121 m_aFileStream.Seek( m_nWritePos );
1122 nBytes = m_aFileStream.Read( pBuffer.get(), nBytes );
1124 int32_t nBytesRead = 0;
1127 nBytesRead = m_pPlugin->getPluginComm()->NPP_Write(
1128 &m_pPlugin->getNPPInstance(), &m_aNPStream, m_nWritePos, nBytes, pBuffer.get() );
1130 catch( ... )
1132 nBytesRead = 0;
1135 if( nBytesRead < 0 )
1137 m_nMode = -1;
1138 return;
1141 m_nWritePos += nBytesRead;
1145 void PluginInputStream::closeOutput() throw(std::exception)
1147 uno::Reference<uno::XInterface> const xPlugin(m_wPlugin);
1148 XPlugin_Impl *const pPlugin(m_pPlugin);
1149 if (!xPlugin.is() || !pPlugin)
1150 return;
1152 Guard< Mutex > aGuard( pPlugin->getMutex() );
1154 flush();
1155 m_xSource = uno::Reference< com::sun::star::io::XActiveDataSource >();
1158 sal_uInt32 PluginInputStream::read( sal_uInt32 offset, sal_Int8* buffer, sal_uInt32 size )
1160 uno::Reference<uno::XInterface> const xPlugin(m_wPlugin);
1161 XPlugin_Impl *const pPlugin(m_pPlugin);
1162 if (!xPlugin.is() || !pPlugin)
1163 return 0;
1165 Guard< Mutex > aGuard( pPlugin->getMutex() );
1167 if( m_nMode != NP_SEEK )
1168 return 0;
1170 m_aFileStream.Seek( offset );
1171 return m_aFileStream.Read( buffer, size );
1174 void PluginInputStream::flush() throw(std::exception)
1178 PluginOutputStream::PluginOutputStream( XPlugin_Impl* pPlugin,
1179 const char* url,
1180 sal_uInt32 len,
1181 sal_uInt32 lastmod ) :
1182 PluginStream( pPlugin, url, len, lastmod ),
1183 m_xStream( pPlugin->getServiceManager()->createInstance("com.sun.star.io.DataOutputStream"), UNO_QUERY )
1185 Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1187 m_pPlugin->getOutputStreams().push_back( this );
1190 PluginOutputStream::~PluginOutputStream()
1192 Guard< Mutex > aGuard( m_pPlugin->getMutex() );
1194 m_pPlugin->getOutputStreams().remove( this );
1197 PluginStreamType PluginOutputStream::getStreamType()
1199 return OutputStream;
1202 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */