LCOV - code coverage report
Current view: top level - libreoffice/oox/source/ole - olestorage.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 120 146 82.2 %
Date: 2012-12-27 Functions: 24 28 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "oox/ole/olestorage.hxx"
      21             : 
      22             : #include <com/sun/star/beans/PropertyValue.hpp>
      23             : #include <com/sun/star/container/XNameContainer.hpp>
      24             : #include <com/sun/star/embed/XTransactedObject.hpp>
      25             : #include <com/sun/star/io/TempFile.hpp>
      26             : #include <com/sun/star/io/XInputStream.hpp>
      27             : #include <com/sun/star/io/XOutputStream.hpp>
      28             : #include <com/sun/star/io/XSeekable.hpp>
      29             : #include <com/sun/star/io/XStream.hpp>
      30             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      31             : #include <com/sun/star/uno/XComponentContext.hpp>
      32             : #include <cppuhelper/implbase2.hxx>
      33             : #include "oox/helper/binaryinputstream.hxx"
      34             : #include "oox/helper/binaryoutputstream.hxx"
      35             : #include "oox/helper/containerhelper.hxx"
      36             : #include "oox/helper/helper.hxx"
      37             : 
      38             : namespace oox {
      39             : namespace ole {
      40             : 
      41             : // ============================================================================
      42             : 
      43             : using namespace ::com::sun::star::beans;
      44             : using namespace ::com::sun::star::container;
      45             : using namespace ::com::sun::star::embed;
      46             : using namespace ::com::sun::star::io;
      47             : using namespace ::com::sun::star::lang;
      48             : using namespace ::com::sun::star::uno;
      49             : 
      50             : using ::rtl::OUString;
      51             : 
      52             : // ============================================================================
      53             : 
      54             : namespace {
      55             : 
      56             : typedef ::cppu::WeakImplHelper2< XSeekable, XOutputStream > OleOutputStreamBase;
      57             : 
      58             : /** Implementation of an OLE storage output stream that inserts itself into the
      59             :     storage when it is closed.
      60             :  */
      61             : class OleOutputStream : public OleOutputStreamBase
      62             : {
      63             : public:
      64             :     explicit            OleOutputStream(
      65             :                             const Reference< XComponentContext >& rxContext,
      66             :                             const Reference< XNameContainer >& rxStorage,
      67             :                             const OUString& rElementName );
      68             :     virtual             ~OleOutputStream();
      69             : 
      70             :     virtual void SAL_CALL seek( sal_Int64 nPos ) throw( IllegalArgumentException, IOException, RuntimeException );
      71             :     virtual sal_Int64 SAL_CALL getPosition() throw( IOException, RuntimeException );
      72             :     virtual sal_Int64 SAL_CALL getLength() throw( IOException, RuntimeException );
      73             : 
      74             :     virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& rData ) throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException );
      75             :     virtual void SAL_CALL flush() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException );
      76             :     virtual void SAL_CALL closeOutput() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException );
      77             : 
      78             : private:
      79             :     void                ensureSeekable() const throw( IOException );
      80             :     void                ensureConnected() const throw( NotConnectedException );
      81             : 
      82             : private:
      83             :     Reference< XNameContainer > mxStorage;
      84             :     Reference< XStream > mxTempFile;
      85             :     Reference< XOutputStream > mxOutStrm;
      86             :     Reference< XSeekable > mxSeekable;
      87             :     OUString            maElementName;
      88             : };
      89             : 
      90             : // ----------------------------------------------------------------------------
      91             : 
      92          55 : OleOutputStream::OleOutputStream( const Reference< XComponentContext >& rxContext,
      93             :         const Reference< XNameContainer >& rxStorage, const OUString& rElementName ) :
      94             :     mxStorage( rxStorage ),
      95          55 :     maElementName( rElementName )
      96             : {
      97             :     try
      98             :     {
      99          55 :         mxTempFile.set( TempFile::create(rxContext), UNO_QUERY_THROW );
     100          55 :         mxOutStrm = mxTempFile->getOutputStream();
     101          55 :         mxSeekable.set( mxOutStrm, UNO_QUERY );
     102             :     }
     103           0 :     catch(const Exception& )
     104             :     {
     105             :     }
     106          55 : }
     107             : 
     108         110 : OleOutputStream::~OleOutputStream()
     109             : {
     110         110 : }
     111             : 
     112           0 : void SAL_CALL OleOutputStream::seek( sal_Int64 nPos ) throw( IllegalArgumentException, IOException, RuntimeException )
     113             : {
     114           0 :     ensureSeekable();
     115           0 :     mxSeekable->seek( nPos );
     116           0 : }
     117             : 
     118           0 : sal_Int64 SAL_CALL OleOutputStream::getPosition() throw( IOException, RuntimeException )
     119             : {
     120           0 :     ensureSeekable();
     121           0 :     return mxSeekable->getPosition();
     122             : }
     123             : 
     124           0 : sal_Int64 SAL_CALL OleOutputStream::getLength() throw( IOException, RuntimeException )
     125             : {
     126           0 :     ensureSeekable();
     127           0 :     return mxSeekable->getLength();
     128             : }
     129             : 
     130          55 : void SAL_CALL OleOutputStream::writeBytes( const Sequence< sal_Int8 >& rData ) throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
     131             : {
     132          55 :     ensureConnected();
     133          55 :     mxOutStrm->writeBytes( rData );
     134          55 : }
     135             : 
     136          55 : void SAL_CALL OleOutputStream::flush() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
     137             : {
     138          55 :     ensureConnected();
     139          55 :     mxOutStrm->flush();
     140          55 : }
     141             : 
     142          55 : void SAL_CALL OleOutputStream::closeOutput() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
     143             : {
     144          55 :     ensureConnected();
     145          55 :     ensureSeekable();
     146             :     // remember the class members
     147          55 :     Reference< XOutputStream > xOutStrm = mxOutStrm;
     148          55 :     Reference< XSeekable > xSeekable = mxSeekable;
     149             :     // reset all class members
     150          55 :     mxOutStrm.clear();
     151          55 :     mxSeekable.clear();
     152             :     // close stream (and let it throw something if needed)
     153          55 :     xOutStrm->closeOutput();
     154             :     // on success, insert the stream into the OLE storage (must be seeked back before)
     155          55 :     xSeekable->seek( 0 );
     156          55 :     if( !ContainerHelper::insertByName( mxStorage, maElementName, Any( mxTempFile ) ) )
     157           0 :         throw IOException();
     158          55 : }
     159             : 
     160          55 : void OleOutputStream::ensureSeekable() const throw( IOException )
     161             : {
     162          55 :     if( !mxSeekable.is() )
     163           0 :         throw IOException();
     164          55 : }
     165             : 
     166         165 : void OleOutputStream::ensureConnected() const throw( NotConnectedException )
     167             : {
     168         165 :     if( !mxOutStrm.is() )
     169           0 :         throw NotConnectedException();
     170         165 : }
     171             : 
     172             : } // namespace
     173             : 
     174             : // ============================================================================
     175             : 
     176         134 : OleStorage::OleStorage( const Reference< XComponentContext >& rxContext,
     177             :         const Reference< XInputStream >& rxInStream, bool bBaseStreamAccess ) :
     178             :     StorageBase( rxInStream, bBaseStreamAccess ),
     179             :     mxContext( rxContext ),
     180         134 :     mpParentStorage( 0 )
     181             : {
     182             :     OSL_ENSURE( mxContext.is(), "OleStorage::OleStorage - missing component context" );
     183         134 :     initStorage( rxInStream );
     184         134 : }
     185             : 
     186           3 : OleStorage::OleStorage( const Reference< XComponentContext >& rxContext,
     187             :         const Reference< XStream >& rxOutStream, bool bBaseStreamAccess ) :
     188             :     StorageBase( rxOutStream, bBaseStreamAccess ),
     189             :     mxContext( rxContext ),
     190           3 :     mpParentStorage( 0 )
     191             : {
     192             :     OSL_ENSURE( mxContext.is(), "OleStorage::OleStorage - missing component context" );
     193           3 :     initStorage( rxOutStream );
     194           3 : }
     195             : 
     196           7 : OleStorage::OleStorage( const OleStorage& rParentStorage,
     197             :         const Reference< XNameContainer >& rxStorage, const OUString& rElementName, bool bReadOnly ) :
     198             :     StorageBase( rParentStorage, rElementName, bReadOnly ),
     199             :     mxContext( rParentStorage.mxContext ),
     200             :     mxStorage( rxStorage ),
     201           7 :     mpParentStorage( &rParentStorage )
     202             : {
     203             :     OSL_ENSURE( mxStorage.is(), "OleStorage::OleStorage - missing substorage elements" );
     204           7 : }
     205             : 
     206           3 : OleStorage::OleStorage( const OleStorage& rParentStorage,
     207             :         const Reference< XStream >& rxOutStream, const OUString& rElementName ) :
     208             :     StorageBase( rParentStorage, rElementName, false ),
     209             :     mxContext( rParentStorage.mxContext ),
     210           3 :     mpParentStorage( &rParentStorage )
     211             : {
     212           3 :     initStorage( rxOutStream );
     213           3 : }
     214             : 
     215         251 : OleStorage::~OleStorage()
     216             : {
     217         251 : }
     218             : 
     219             : // ----------------------------------------------------------------------------
     220             : 
     221         134 : void OleStorage::initStorage( const Reference< XInputStream >& rxInStream )
     222             : {
     223             :     // if stream is not seekable, create temporary copy
     224         134 :     Reference< XInputStream > xInStrm = rxInStream;
     225         134 :     if( !Reference< XSeekable >( xInStrm, UNO_QUERY ).is() ) try
     226             :     {
     227          94 :         Reference< XStream > xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
     228             :         {
     229          94 :             Reference< XOutputStream > xOutStrm( xTempFile->getOutputStream(), UNO_SET_THROW );
     230             :             /*  Pass false to both binary stream objects to keep the UNO
     231             :                 streams alive. Life time of these streams is controlled by the
     232             :                 tempfile implementation. */
     233          94 :             BinaryXOutputStream aOutStrm( xOutStrm, false );
     234          94 :             BinaryXInputStream aInStrm( xInStrm, false );
     235          94 :             aInStrm.copyToStream( aOutStrm );
     236             :         } // scope closes output stream of tempfile
     237          94 :         xInStrm = xTempFile->getInputStream();
     238             :     }
     239           0 :     catch(const Exception& )
     240             :     {
     241             :         OSL_FAIL( "OleStorage::initStorage - cannot create temporary copy of input stream" );
     242             :     }
     243             : 
     244             :     // create base storage object
     245         134 :     if( xInStrm.is() ) try
     246             :     {
     247         134 :         Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW );
     248         134 :         Sequence< Any > aArgs( 2 );
     249         134 :         aArgs[ 0 ] <<= xInStrm;
     250         134 :         aArgs[ 1 ] <<= true;        // true = do not create a copy of the input stream
     251         134 :         mxStorage.set( xFactory->createInstanceWithArguments(
     252         264 :             CREATE_OUSTRING( "com.sun.star.embed.OLESimpleStorage" ), aArgs ), UNO_QUERY_THROW );
     253             :     }
     254         130 :     catch(const Exception& )
     255             :     {
     256         134 :     }
     257         134 : }
     258             : 
     259           6 : void OleStorage::initStorage( const Reference< XStream >& rxOutStream )
     260             : {
     261             :     // create base storage object
     262           6 :     if( rxOutStream.is() ) try
     263             :     {
     264           6 :         Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW );
     265           6 :         Sequence< Any > aArgs( 2 );
     266           6 :         aArgs[ 0 ] <<= rxOutStream;
     267           6 :         aArgs[ 1 ] <<= true;        // true = do not create a copy of the stream
     268           6 :         mxStorage.set( xFactory->createInstanceWithArguments(
     269           6 :             CREATE_OUSTRING( "com.sun.star.embed.OLESimpleStorage" ), aArgs ), UNO_QUERY_THROW );
     270             :     }
     271           0 :     catch(const Exception& )
     272             :     {
     273             :     }
     274           6 : }
     275             : 
     276             : // StorageBase interface ------------------------------------------------------
     277             : 
     278         161 : bool OleStorage::implIsStorage() const
     279             : {
     280         161 :     if( mxStorage.is() ) try
     281             :     {
     282             :         /*  If this is not an OLE storage, hasElements() of the OLESimpleStorage
     283             :             implementation throws an exception. But we do not return the result
     284             :             of hasElements(), because an empty storage is a valid storage too. */
     285          67 :         mxStorage->hasElements();
     286          67 :         return true;
     287             :     }
     288           0 :     catch(const Exception& )
     289             :     {
     290             :     }
     291          94 :     return false;
     292             : }
     293             : 
     294           0 : Reference< XStorage > OleStorage::implGetXStorage() const
     295             : {
     296             :     OSL_FAIL( "OleStorage::getXStorage - not implemented" );
     297           0 :     return Reference< XStorage >();
     298             : }
     299             : 
     300           9 : void OleStorage::implGetElementNames( ::std::vector< OUString >& orElementNames ) const
     301             : {
     302           9 :     Sequence< OUString > aNames;
     303           9 :     if( mxStorage.is() ) try
     304             :     {
     305           9 :         aNames = mxStorage->getElementNames();
     306           9 :         if( aNames.getLength() > 0 )
     307           9 :             orElementNames.insert( orElementNames.end(), aNames.getConstArray(), aNames.getConstArray() + aNames.getLength() );
     308             :     }
     309           0 :     catch(const Exception& )
     310             :     {
     311           9 :     }
     312           9 : }
     313             : 
     314         107 : StorageRef OleStorage::implOpenSubStorage( const OUString& rElementName, bool bCreateMissing )
     315             : {
     316         107 :     StorageRef xSubStorage;
     317         107 :     if( mxStorage.is() && !rElementName.isEmpty() )
     318             :     {
     319             :         try
     320             :         {
     321         132 :             Reference< XNameContainer > xSubElements( mxStorage->getByName( rElementName ), UNO_QUERY_THROW );
     322           7 :             xSubStorage.reset( new OleStorage( *this, xSubElements, rElementName, true ) );
     323             :         }
     324          64 :         catch(const Exception& )
     325             :         {
     326             :         }
     327             : 
     328             :         /*  The OLESimpleStorage API implementation seems to be buggy in the
     329             :             area of writable inplace substorage (sometimes it overwrites other
     330             :             unrelated streams with zero bytes). We go the save way and create a
     331             :             new OLE storage based on a temporary file. All operations are
     332             :             performed on this clean storage. On committing, the storage will be
     333             :             completely re-inserted into the parent storage. */
     334          71 :         if( !isReadOnly() && (bCreateMissing || xSubStorage.get()) ) try
     335             :         {
     336             :             // create new storage based on a temp file
     337           3 :             Reference< XStream > xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
     338           3 :             StorageRef xTempStorage( new OleStorage( *this, xTempFile, rElementName ) );
     339             :             // copy existing substorage into temp storage
     340           3 :             if( xSubStorage.get() )
     341           0 :                 xSubStorage->copyStorageToStorage( *xTempStorage );
     342             :             // return the temp storage to caller
     343           3 :             xSubStorage = xTempStorage;
     344             :         }
     345           0 :         catch(const Exception& )
     346             :         {
     347             :         }
     348             :     }
     349         107 :     return xSubStorage;
     350             : }
     351             : 
     352          76 : Reference< XInputStream > OleStorage::implOpenInputStream( const OUString& rElementName )
     353             : {
     354          76 :     Reference< XInputStream > xInStream;
     355          76 :     if( mxStorage.is() ) try
     356             :     {
     357          76 :         xInStream.set( mxStorage->getByName( rElementName ), UNO_QUERY );
     358             :     }
     359           0 :     catch(const Exception& )
     360             :     {
     361             :     }
     362          76 :     return xInStream;
     363             : }
     364             : 
     365          55 : Reference< XOutputStream > OleStorage::implOpenOutputStream( const OUString& rElementName )
     366             : {
     367          55 :     Reference< XOutputStream > xOutStream;
     368          55 :     if( mxStorage.is() && !rElementName.isEmpty() )
     369          55 :         xOutStream.set( new OleOutputStream( mxContext, mxStorage, rElementName ) );
     370          55 :     return xOutStream;
     371             : }
     372             : 
     373           6 : void OleStorage::implCommit() const
     374             : {
     375             :     try
     376             :     {
     377             :         // commit this storage (finalizes the file this storage is based on)
     378           6 :         Reference< XTransactedObject >( mxStorage, UNO_QUERY_THROW )->commit();
     379             :         // re-insert this storage into the parent storage
     380           6 :         if( mpParentStorage )
     381             :         {
     382           3 :             if( mpParentStorage->mxStorage->hasByName( getName() ) )
     383             :             {
     384             :                 // replaceByName() does not work (#i109539#)
     385           0 :                 mpParentStorage->mxStorage->removeByName( getName() );
     386           0 :                 Reference< XTransactedObject >( mpParentStorage->mxStorage, UNO_QUERY_THROW )->commit();
     387             :             }
     388           3 :             mpParentStorage->mxStorage->insertByName( getName(), Any( mxStorage ) );
     389             :             // this requires another commit(), which will be performed by the parent storage
     390             :         }
     391             :     }
     392           0 :     catch(const Exception& )
     393             :     {
     394             :     }
     395           6 : }
     396             : 
     397             : // ============================================================================
     398             : 
     399             : } // namespace ole
     400          51 : } // namespace oox
     401             : 
     402             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10