summaryrefslogtreecommitdiff
path: root/oox/source/core/filterbase.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/core/filterbase.cxx')
-rw-r--r--oox/source/core/filterbase.cxx566
1 files changed, 566 insertions, 0 deletions
diff --git a/oox/source/core/filterbase.cxx b/oox/source/core/filterbase.cxx
new file mode 100644
index 000000000000..fb9e43c732de
--- /dev/null
+++ b/oox/source/core/filterbase.cxx
@@ -0,0 +1,566 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/core/filterbase.hxx"
+#include <set>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <osl/mutex.hxx>
+#include <rtl/instance.hxx>
+#include <rtl/uri.hxx>
+#include <comphelper/docpasswordhelper.hxx>
+#include <comphelper/mediadescriptor.hxx>
+#include "tokens.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/helper/binaryoutputstream.hxx"
+#include "oox/helper/graphichelper.hxx"
+#include "oox/helper/modelobjecthelper.hxx"
+#include "oox/ole/oleobjecthelper.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::lang::IllegalArgumentException;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::lang::XComponent;
+using ::com::sun::star::beans::PropertyValue;
+using ::com::sun::star::frame::XFrame;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::io::XInputStream;
+using ::com::sun::star::io::XOutputStream;
+using ::com::sun::star::io::XStream;
+using ::com::sun::star::task::XStatusIndicator;
+using ::com::sun::star::task::XInteractionHandler;
+using ::com::sun::star::graphic::XGraphic;
+using ::comphelper::MediaDescriptor;
+using ::comphelper::SequenceAsHashMap;
+using ::oox::ole::OleObjectHelper;
+
+namespace oox {
+namespace core {
+
+// ============================================================================
+
+namespace {
+
+/** This guard prevents recursive loading/saving of the same document. */
+class DocumentOpenedGuard : public ::osl::Mutex
+{
+public:
+ explicit DocumentOpenedGuard( const OUString& rUrl );
+ ~DocumentOpenedGuard();
+
+ inline bool isValid() const { return mbValid; }
+
+private:
+ DocumentOpenedGuard( const DocumentOpenedGuard& );
+ DocumentOpenedGuard& operator=( const DocumentOpenedGuard& );
+
+ typedef ::std::set< OUString > UrlSet;
+ struct UrlPool : public ::rtl::Static< UrlSet, UrlPool > {};
+
+ UrlSet& mrUrls;
+ OUString maUrl;
+ bool mbValid;
+};
+
+DocumentOpenedGuard::DocumentOpenedGuard( const OUString& rUrl ) :
+ mrUrls( UrlPool::get() )
+{
+ ::osl::MutexGuard aGuard( *this );
+ mbValid = (rUrl.getLength() == 0) || (mrUrls.count( rUrl ) == 0);
+ if( mbValid && (rUrl.getLength() > 0) )
+ {
+ mrUrls.insert( rUrl );
+ maUrl = rUrl;
+ }
+}
+
+DocumentOpenedGuard::~DocumentOpenedGuard()
+{
+ ::osl::MutexGuard aGuard( *this );
+ if( maUrl.getLength() > 0 )
+ mrUrls.erase( maUrl );
+}
+
+} // namespace
+
+// ============================================================================
+
+/** Specifies whether this filter is an import or export filter. */
+enum FilterDirection
+{
+ FILTERDIRECTION_UNKNOWN,
+ FILTERDIRECTION_IMPORT,
+ FILTERDIRECTION_EXPORT
+};
+
+// ----------------------------------------------------------------------------
+
+struct FilterBaseImpl
+{
+ typedef ::boost::shared_ptr< GraphicHelper > GraphicHelperRef;
+ typedef ::boost::shared_ptr< ModelObjectHelper > ModelObjHelperRef;
+ typedef ::boost::shared_ptr< OleObjectHelper > OleObjHelperRef;
+
+ FilterDirection meDirection;
+ SequenceAsHashMap maArguments;
+ MediaDescriptor maMediaDesc;
+ OUString maFileUrl;
+ StorageRef mxStorage;
+
+ GraphicHelperRef mxGraphicHelper; /// Graphic and graphic object handling.
+ ModelObjHelperRef mxModelObjHelper; /// Tables to create new named drawing objects.
+ OleObjHelperRef mxOleObjHelper; /// OLE object handling.
+
+ Reference< XMultiServiceFactory > mxGlobalFactory;
+ Reference< XModel > mxModel;
+ Reference< XMultiServiceFactory > mxModelFactory;
+ Reference< XFrame > mxTargetFrame;
+ Reference< XInputStream > mxInStream;
+ Reference< XStream > mxOutStream;
+ Reference< XStatusIndicator > mxStatusIndicator;
+ Reference< XInteractionHandler > mxInteractionHandler;
+
+ explicit FilterBaseImpl( const Reference< XMultiServiceFactory >& rxGlobalFactory );
+
+ void setDocumentModel( const Reference< XComponent >& rxComponent );
+ bool hasDocumentModel() const;
+
+ void initializeFilter();
+ void finalizeFilter();
+};
+
+// ----------------------------------------------------------------------------
+
+FilterBaseImpl::FilterBaseImpl( const Reference< XMultiServiceFactory >& rxGlobalFactory ) :
+ meDirection( FILTERDIRECTION_UNKNOWN ),
+ mxGlobalFactory( rxGlobalFactory )
+{
+ OSL_ENSURE( mxGlobalFactory.is(), "FilterBaseImpl::FilterBaseImpl - missing service factory" );
+}
+
+void FilterBaseImpl::setDocumentModel( const Reference< XComponent >& rxComponent )
+{
+ mxModel.set( rxComponent, UNO_QUERY );
+ mxModelFactory.set( rxComponent, UNO_QUERY );
+}
+
+bool FilterBaseImpl::hasDocumentModel() const
+{
+ return mxGlobalFactory.is() && mxModel.is() && mxModelFactory.is();
+}
+
+void FilterBaseImpl::initializeFilter()
+{
+ try
+ {
+ // lock the model controllers
+ mxModel->lockControllers();
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void FilterBaseImpl::finalizeFilter()
+{
+ try
+ {
+ // write the descriptor back to the document model (adds the passwords)
+ mxModel->attachResource( maFileUrl, maMediaDesc.getAsConstPropertyValueList() );
+ // unlock the model controllers
+ mxModel->unlockControllers();
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+
+FilterBase::FilterBase( const Reference< XMultiServiceFactory >& rxGlobalFactory ) :
+ mxImpl( new FilterBaseImpl( rxGlobalFactory ) )
+{
+}
+
+FilterBase::~FilterBase()
+{
+}
+
+bool FilterBase::isImportFilter() const
+{
+ return mxImpl->meDirection == FILTERDIRECTION_IMPORT;
+}
+
+bool FilterBase::isExportFilter() const
+{
+ return mxImpl->meDirection == FILTERDIRECTION_EXPORT;
+}
+
+// ----------------------------------------------------------------------------
+
+Any FilterBase::getArgument( const OUString& rArgName ) const
+{
+ SequenceAsHashMap::const_iterator aIt = mxImpl->maArguments.find( rArgName );
+ return (aIt == mxImpl->maArguments.end()) ? Any() : aIt->second;
+}
+
+const Reference< XMultiServiceFactory >& FilterBase::getGlobalFactory() const
+{
+ return mxImpl->mxGlobalFactory;
+}
+
+const Reference< XModel >& FilterBase::getModel() const
+{
+ return mxImpl->mxModel;
+}
+
+const Reference< XMultiServiceFactory >& FilterBase::getModelFactory() const
+{
+ return mxImpl->mxModelFactory;
+}
+
+const Reference< XFrame >& FilterBase::getTargetFrame() const
+{
+ return mxImpl->mxTargetFrame;
+}
+
+const Reference< XStatusIndicator >& FilterBase::getStatusIndicator() const
+{
+ return mxImpl->mxStatusIndicator;
+}
+
+const Reference< XInteractionHandler >& FilterBase::getInteractionHandler() const
+{
+ return mxImpl->mxInteractionHandler;
+}
+
+MediaDescriptor& FilterBase::getMediaDescriptor() const
+{
+ return mxImpl->maMediaDesc;
+}
+
+const OUString& FilterBase::getFileUrl() const
+{
+ return mxImpl->maFileUrl;
+}
+
+namespace {
+
+inline bool lclIsDosDrive( const OUString& rUrl, sal_Int32 nPos = 0 )
+{
+ return
+ (rUrl.getLength() >= nPos + 3) &&
+ ((('A' <= rUrl[ nPos ]) && (rUrl[ nPos ] <= 'Z')) || (('a' <= rUrl[ nPos ]) && (rUrl[ nPos ] <= 'z'))) &&
+ (rUrl[ nPos + 1 ] == ':') &&
+ (rUrl[ nPos + 2 ] == '/');
+}
+
+} // namespace
+
+OUString FilterBase::getAbsoluteUrl( const OUString& rUrl ) const
+{
+ // handle some special cases before calling ::rtl::Uri::convertRelToAbs()
+
+ const OUString aFileSchema = CREATE_OUSTRING( "file:" );
+ const OUString aFilePrefix = CREATE_OUSTRING( "file:///" );
+ const sal_Int32 nFilePrefixLen = aFilePrefix.getLength();
+ const OUString aUncPrefix = CREATE_OUSTRING( "//" );
+
+ /* (1) convert all backslashes to slashes, and check that passed URL is
+ not empty. */
+ OUString aUrl = rUrl.replace( '\\', '/' );
+ if( aUrl.getLength() == 0 )
+ return aUrl;
+
+ /* (2) add 'file:///' to absolute Windows paths, e.g. convert
+ 'C:/path/file' to 'file:///c:/path/file'. */
+ if( lclIsDosDrive( aUrl ) )
+ return aFilePrefix + aUrl;
+
+ /* (3) add 'file:' to UNC paths, e.g. convert '//server/path/file' to
+ 'file://server/path/file'. */
+ if( aUrl.match( aUncPrefix ) )
+ return aFileSchema + aUrl;
+
+ /* (4) remove additional slashes from UNC paths, e.g. convert
+ 'file://///server/path/file' to 'file://server/path/file'. */
+ if( (aUrl.getLength() >= nFilePrefixLen + 2) &&
+ aUrl.match( aFilePrefix ) &&
+ aUrl.match( aUncPrefix, nFilePrefixLen ) )
+ {
+ return aFileSchema + aUrl.copy( nFilePrefixLen );
+ }
+
+ /* (5) handle URLs relative to current drive, e.g. the URL '/path1/file1'
+ relative to the base URL 'file:///C:/path2/file2' does not result in
+ the expected 'file:///C:/path1/file1', but in 'file:///path1/file1'. */
+ if( (aUrl.getLength() >= 1) && (aUrl[ 0 ] == '/') &&
+ mxImpl->maFileUrl.match( aFilePrefix ) &&
+ lclIsDosDrive( mxImpl->maFileUrl, nFilePrefixLen ) )
+ {
+ return mxImpl->maFileUrl.copy( 0, nFilePrefixLen + 3 ) + aUrl.copy( 1 );
+ }
+
+ try
+ {
+ return ::rtl::Uri::convertRelToAbs( mxImpl->maFileUrl, aUrl );
+ }
+ catch( ::rtl::MalformedUriException& )
+ {
+ }
+ return aUrl;
+}
+
+StorageRef FilterBase::getStorage() const
+{
+ return mxImpl->mxStorage;
+}
+
+StorageRef FilterBase::openSubStorage( const OUString& rStorageName, bool bCreateMissing ) const
+{
+ return mxImpl->mxStorage->openSubStorage( rStorageName, bCreateMissing );
+}
+
+Reference< XInputStream > FilterBase::openInputStream( const OUString& rStreamName ) const
+{
+ return mxImpl->mxStorage->openInputStream( rStreamName );
+}
+
+Reference< XOutputStream > FilterBase::openOutputStream( const OUString& rStreamName ) const
+{
+ return mxImpl->mxStorage->openOutputStream( rStreamName );
+}
+
+void FilterBase::commitStorage() const
+{
+ mxImpl->mxStorage->commit();
+}
+
+// helpers --------------------------------------------------------------------
+
+GraphicHelper& FilterBase::getGraphicHelper() const
+{
+ if( !mxImpl->mxGraphicHelper )
+ mxImpl->mxGraphicHelper.reset( implCreateGraphicHelper() );
+ return *mxImpl->mxGraphicHelper;
+}
+
+ModelObjectHelper& FilterBase::getModelObjectHelper() const
+{
+ if( !mxImpl->mxModelObjHelper )
+ mxImpl->mxModelObjHelper.reset( new ModelObjectHelper( mxImpl->mxModelFactory ) );
+ return *mxImpl->mxModelObjHelper;
+}
+
+OleObjectHelper& FilterBase::getOleObjectHelper() const
+{
+ if( !mxImpl->mxOleObjHelper )
+ mxImpl->mxOleObjHelper.reset( new OleObjectHelper( mxImpl->mxModelFactory ) );
+ return *mxImpl->mxOleObjHelper;
+}
+
+OUString FilterBase::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) const
+{
+ ::std::vector< OUString > aDefaultPasswords;
+ aDefaultPasswords.push_back( CREATE_OUSTRING( "VelvetSweatshop" ) );
+ return ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
+ rVerifier, mxImpl->maMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords );
+}
+
+bool FilterBase::importBinaryData( StreamDataSequence& orDataSeq, const OUString& rStreamName )
+{
+ OSL_ENSURE( rStreamName.getLength() > 0, "FilterBase::importBinaryData - empty stream name" );
+ if( rStreamName.getLength() == 0 )
+ return false;
+
+ // try to open the stream (this may fail - do not assert)
+ BinaryXInputStream aInStrm( openInputStream( rStreamName ), true );
+ if( aInStrm.isEof() )
+ return false;
+
+ // copy the entire stream to the passed sequence
+ SequenceOutputStream aOutStrm( orDataSeq );
+ aInStrm.copyToStream( aOutStrm );
+ return true;
+}
+
+// com.sun.star.lang.XServiceInfo interface -----------------------------------
+
+OUString SAL_CALL FilterBase::getImplementationName() throw( RuntimeException )
+{
+ return implGetImplementationName();
+}
+
+sal_Bool SAL_CALL FilterBase::supportsService( const OUString& rServiceName ) throw( RuntimeException )
+{
+ return
+ (rServiceName == CREATE_OUSTRING( "com.sun.star.document.ImportFilter" )) ||
+ (rServiceName == CREATE_OUSTRING( "com.sun.star.document.ExportFilter" ));
+}
+
+Sequence< OUString > SAL_CALL FilterBase::getSupportedServiceNames() throw( RuntimeException )
+{
+ Sequence< OUString > aServiceNames( 2 );
+ aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.document.ImportFilter" );
+ aServiceNames[ 1 ] = CREATE_OUSTRING( "com.sun.star.document.ExportFilter" );
+ return aServiceNames;
+}
+
+// com.sun.star.lang.XInitialization interface --------------------------------
+
+void SAL_CALL FilterBase::initialize( const Sequence< Any >& rArgs ) throw( Exception, RuntimeException )
+{
+ if( rArgs.getLength() >= 2 ) try
+ {
+ mxImpl->maArguments << rArgs[ 1 ];
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// com.sun.star.document.XImporter interface ----------------------------------
+
+void SAL_CALL FilterBase::setTargetDocument( const Reference< XComponent >& rxDocument ) throw( IllegalArgumentException, RuntimeException )
+{
+ mxImpl->setDocumentModel( rxDocument );
+ if( !mxImpl->hasDocumentModel() )
+ throw IllegalArgumentException();
+ mxImpl->meDirection = FILTERDIRECTION_IMPORT;
+}
+
+// com.sun.star.document.XExporter interface ----------------------------------
+
+void SAL_CALL FilterBase::setSourceDocument( const Reference< XComponent >& rxDocument ) throw( IllegalArgumentException, RuntimeException )
+{
+ mxImpl->setDocumentModel( rxDocument );
+ if( !mxImpl->hasDocumentModel() )
+ throw IllegalArgumentException();
+ mxImpl->meDirection = FILTERDIRECTION_EXPORT;
+}
+
+// com.sun.star.document.XFilter interface ------------------------------------
+
+sal_Bool SAL_CALL FilterBase::filter( const Sequence< PropertyValue >& rMediaDescSeq ) throw( RuntimeException )
+{
+ sal_Bool bRet = sal_False;
+ if( mxImpl->hasDocumentModel() && (mxImpl->meDirection != FILTERDIRECTION_UNKNOWN) )
+ {
+ setMediaDescriptor( rMediaDescSeq );
+ DocumentOpenedGuard aOpenedGuard( mxImpl->maFileUrl );
+ if( aOpenedGuard.isValid() || !mxImpl->maFileUrl.getLength() )
+ {
+ mxImpl->initializeFilter();
+ switch( mxImpl->meDirection )
+ {
+ case FILTERDIRECTION_UNKNOWN:
+ break;
+ case FILTERDIRECTION_IMPORT:
+ if( mxImpl->mxInStream.is() )
+ {
+ mxImpl->mxStorage = implCreateStorage( mxImpl->mxInStream );
+ bRet = mxImpl->mxStorage.get() && importDocument();
+ }
+ break;
+ case FILTERDIRECTION_EXPORT:
+ if( mxImpl->mxOutStream.is() )
+ {
+ mxImpl->mxStorage = implCreateStorage( mxImpl->mxOutStream );
+ bRet = mxImpl->mxStorage.get() && exportDocument();
+ }
+ break;
+ }
+ mxImpl->finalizeFilter();
+ }
+ }
+ return bRet;
+}
+
+void SAL_CALL FilterBase::cancel() throw( RuntimeException )
+{
+}
+
+// protected ------------------------------------------------------------------
+
+Reference< XInputStream > FilterBase::implGetInputStream( MediaDescriptor& rMediaDesc ) const
+{
+ return rMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_INPUTSTREAM(), Reference< XInputStream >() );
+}
+
+Reference< XStream > FilterBase::implGetOutputStream( MediaDescriptor& rMediaDesc ) const
+{
+ return rMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_STREAMFOROUTPUT(), Reference< XStream >() );
+}
+
+// private --------------------------------------------------------------------
+
+void FilterBase::setMediaDescriptor( const Sequence< PropertyValue >& rMediaDescSeq )
+{
+ mxImpl->maMediaDesc << rMediaDescSeq;
+
+ switch( mxImpl->meDirection )
+ {
+ case FILTERDIRECTION_UNKNOWN:
+ OSL_ENSURE( false, "FilterBase::setMediaDescriptor - invalid filter direction" );
+ break;
+ case FILTERDIRECTION_IMPORT:
+ mxImpl->maMediaDesc.addInputStream();
+ mxImpl->mxInStream = implGetInputStream( mxImpl->maMediaDesc );
+ OSL_ENSURE( mxImpl->mxInStream.is(), "FilterBase::setMediaDescriptor - missing input stream" );
+ break;
+ case FILTERDIRECTION_EXPORT:
+ mxImpl->mxOutStream = implGetOutputStream( mxImpl->maMediaDesc );
+ OSL_ENSURE( mxImpl->mxOutStream.is(), "FilterBase::setMediaDescriptor - missing output stream" );
+ break;
+ }
+
+ mxImpl->maFileUrl = mxImpl->maMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_URL(), OUString() );
+ mxImpl->mxTargetFrame = mxImpl->maMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_FRAME(), Reference< XFrame >() );
+ mxImpl->mxStatusIndicator = mxImpl->maMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_STATUSINDICATOR(), Reference< XStatusIndicator >() );
+ mxImpl->mxInteractionHandler = mxImpl->maMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_INTERACTIONHANDLER(), Reference< XInteractionHandler >() );
+}
+
+GraphicHelper* FilterBase::implCreateGraphicHelper() const
+{
+ // default: return base implementation without any special behaviour
+ return new GraphicHelper( mxImpl->mxGlobalFactory, mxImpl->mxTargetFrame, mxImpl->mxStorage );
+}
+
+// ============================================================================
+
+} // namespace core
+} // namespace oox
+