LCOV - code coverage report
Current view: top level - oox/source/ole - olestorage.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 121 144 84.0 %
Date: 2015-06-13 12:38:46 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 <osl/diagnose.h>
      34             : #include "oox/helper/binaryinputstream.hxx"
      35             : #include "oox/helper/binaryoutputstream.hxx"
      36             : #include "oox/helper/containerhelper.hxx"
      37             : #include "oox/helper/helper.hxx"
      38             : 
      39             : namespace oox {
      40             : namespace ole {
      41             : 
      42             : using namespace ::com::sun::star::beans;
      43             : using namespace ::com::sun::star::container;
      44             : using namespace ::com::sun::star::embed;
      45             : using namespace ::com::sun::star::io;
      46             : using namespace ::com::sun::star::lang;
      47             : using namespace ::com::sun::star::uno;
      48             : 
      49             : namespace {
      50             : 
      51             : typedef ::cppu::WeakImplHelper2< XSeekable, XOutputStream > OleOutputStreamBase;
      52             : 
      53             : /** Implementation of an OLE storage output stream that inserts itself into the
      54             :     storage when it is closed.
      55             :  */
      56             : class OleOutputStream : public OleOutputStreamBase
      57             : {
      58             : public:
      59             :     explicit            OleOutputStream(
      60             :                             const Reference< XComponentContext >& rxContext,
      61             :                             const Reference< XNameContainer >& rxStorage,
      62             :                             const OUString& rElementName );
      63             :     virtual             ~OleOutputStream();
      64             : 
      65             :     virtual void SAL_CALL seek( sal_Int64 nPos ) throw( IllegalArgumentException, IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
      66             :     virtual sal_Int64 SAL_CALL getPosition() throw( IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
      67             :     virtual sal_Int64 SAL_CALL getLength() throw( IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
      68             : 
      69             :     virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& rData ) throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
      70             :     virtual void SAL_CALL flush() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
      71             :     virtual void SAL_CALL closeOutput() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception ) SAL_OVERRIDE;
      72             : 
      73             : private:
      74             :     void                ensureSeekable() const throw( IOException );
      75             :     void                ensureConnected() const throw( NotConnectedException );
      76             : 
      77             : private:
      78             :     Reference< XNameContainer > mxStorage;
      79             :     Reference< XStream > mxTempFile;
      80             :     Reference< XOutputStream > mxOutStrm;
      81             :     Reference< XSeekable > mxSeekable;
      82             :     OUString            maElementName;
      83             : };
      84             : 
      85         475 : OleOutputStream::OleOutputStream( const Reference< XComponentContext >& rxContext,
      86             :         const Reference< XNameContainer >& rxStorage, const OUString& rElementName ) :
      87             :     mxStorage( rxStorage ),
      88         475 :     maElementName( rElementName )
      89             : {
      90             :     try
      91             :     {
      92         475 :         mxTempFile.set( TempFile::create(rxContext), UNO_QUERY_THROW );
      93         475 :         mxOutStrm = mxTempFile->getOutputStream();
      94         475 :         mxSeekable.set( mxOutStrm, UNO_QUERY );
      95             :     }
      96           0 :     catch(const Exception& )
      97             :     {
      98             :     }
      99         475 : }
     100             : 
     101         950 : OleOutputStream::~OleOutputStream()
     102             : {
     103         950 : }
     104             : 
     105           0 : void SAL_CALL OleOutputStream::seek( sal_Int64 nPos ) throw( IllegalArgumentException, IOException, RuntimeException, std::exception )
     106             : {
     107           0 :     ensureSeekable();
     108           0 :     mxSeekable->seek( nPos );
     109           0 : }
     110             : 
     111           0 : sal_Int64 SAL_CALL OleOutputStream::getPosition() throw( IOException, RuntimeException, std::exception )
     112             : {
     113           0 :     ensureSeekable();
     114           0 :     return mxSeekable->getPosition();
     115             : }
     116             : 
     117           0 : sal_Int64 SAL_CALL OleOutputStream::getLength() throw( IOException, RuntimeException, std::exception )
     118             : {
     119           0 :     ensureSeekable();
     120           0 :     return mxSeekable->getLength();
     121             : }
     122             : 
     123         477 : void SAL_CALL OleOutputStream::writeBytes( const Sequence< sal_Int8 >& rData ) throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception )
     124             : {
     125         477 :     ensureConnected();
     126         477 :     mxOutStrm->writeBytes( rData );
     127         477 : }
     128             : 
     129         475 : void SAL_CALL OleOutputStream::flush() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception )
     130             : {
     131         475 :     ensureConnected();
     132         475 :     mxOutStrm->flush();
     133         475 : }
     134             : 
     135         475 : void SAL_CALL OleOutputStream::closeOutput() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception )
     136             : {
     137         475 :     ensureConnected();
     138         475 :     ensureSeekable();
     139             :     // remember the class members
     140         475 :     Reference< XOutputStream > xOutStrm = mxOutStrm;
     141         950 :     Reference< XSeekable > xSeekable = mxSeekable;
     142             :     // reset all class members
     143         475 :     mxOutStrm.clear();
     144         475 :     mxSeekable.clear();
     145             :     // close stream (and let it throw something if needed)
     146         475 :     xOutStrm->closeOutput();
     147             :     // on success, insert the stream into the OLE storage (must be seek-ed back before)
     148         475 :     xSeekable->seek( 0 );
     149         475 :     if( !ContainerHelper::insertByName( mxStorage, maElementName, Any( mxTempFile ) ) )
     150         475 :         throw IOException();
     151         475 : }
     152             : 
     153         475 : void OleOutputStream::ensureSeekable() const throw( IOException )
     154             : {
     155         475 :     if( !mxSeekable.is() )
     156           0 :         throw IOException();
     157         475 : }
     158             : 
     159        1427 : void OleOutputStream::ensureConnected() const throw( NotConnectedException )
     160             : {
     161        1427 :     if( !mxOutStrm.is() )
     162           0 :         throw NotConnectedException();
     163        1427 : }
     164             : 
     165             : } // namespace
     166             : 
     167        3365 : OleStorage::OleStorage( const Reference< XComponentContext >& rxContext,
     168             :         const Reference< XInputStream >& rxInStream, bool bBaseStreamAccess ) :
     169             :     StorageBase( rxInStream, bBaseStreamAccess ),
     170             :     mxContext( rxContext ),
     171        3365 :     mpParentStorage( 0 )
     172             : {
     173             :     OSL_ENSURE( mxContext.is(), "OleStorage::OleStorage - missing component context" );
     174        3365 :     initStorage( rxInStream );
     175        3365 : }
     176             : 
     177          31 : OleStorage::OleStorage( const Reference< XComponentContext >& rxContext,
     178             :         const Reference< XStream >& rxOutStream, bool bBaseStreamAccess ) :
     179             :     StorageBase( rxOutStream, bBaseStreamAccess ),
     180             :     mxContext( rxContext ),
     181          31 :     mpParentStorage( 0 )
     182             : {
     183             :     OSL_ENSURE( mxContext.is(), "OleStorage::OleStorage - missing component context" );
     184          31 :     initStorage( rxOutStream );
     185          31 : }
     186             : 
     187          65 : OleStorage::OleStorage( const OleStorage& rParentStorage,
     188             :         const Reference< XNameContainer >& rxStorage, const OUString& rElementName, bool bReadOnly ) :
     189             :     StorageBase( rParentStorage, rElementName, bReadOnly ),
     190             :     mxContext( rParentStorage.mxContext ),
     191             :     mxStorage( rxStorage ),
     192          65 :     mpParentStorage( &rParentStorage )
     193             : {
     194             :     OSL_ENSURE( mxStorage.is(), "OleStorage::OleStorage - missing substorage elements" );
     195          65 : }
     196             : 
     197          33 : OleStorage::OleStorage( const OleStorage& rParentStorage,
     198             :         const Reference< XStream >& rxOutStream, const OUString& rElementName ) :
     199             :     StorageBase( rParentStorage, rElementName, false ),
     200             :     mxContext( rParentStorage.mxContext ),
     201          33 :     mpParentStorage( &rParentStorage )
     202             : {
     203          33 :     initStorage( rxOutStream );
     204          33 : }
     205             : 
     206        5115 : OleStorage::~OleStorage()
     207             : {
     208        5115 : }
     209             : 
     210        3365 : void OleStorage::initStorage( const Reference< XInputStream >& rxInStream )
     211             : {
     212             :     // if stream is not seekable, create temporary copy
     213        3365 :     Reference< XInputStream > xInStrm = rxInStream;
     214        3365 :     if( !Reference< XSeekable >( xInStrm, UNO_QUERY ).is() ) try
     215             :     {
     216        1523 :         Reference< XStream > xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
     217             :         {
     218        1523 :             Reference< XOutputStream > xOutStrm( xTempFile->getOutputStream(), UNO_SET_THROW );
     219             :             /*  Pass false to both binary stream objects to keep the UNO
     220             :                 streams alive. Life time of these streams is controlled by the
     221             :                 tempfile implementation. */
     222        3046 :             BinaryXOutputStream aOutStrm( xOutStrm, false );
     223        3046 :             BinaryXInputStream aInStrm( xInStrm, false );
     224        3046 :             aInStrm.copyToStream( aOutStrm );
     225             :         } // scope closes output stream of tempfile
     226        1523 :         xInStrm = xTempFile->getInputStream();
     227             :     }
     228           0 :     catch(const Exception& )
     229             :     {
     230             :         OSL_FAIL( "OleStorage::initStorage - cannot create temporary copy of input stream" );
     231             :     }
     232             : 
     233             :     // create base storage object
     234        3365 :     if( xInStrm.is() ) try
     235             :     {
     236        3365 :         Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW );
     237        6730 :         Sequence< Any > aArgs( 2 );
     238        3365 :         aArgs[ 0 ] <<= xInStrm;
     239        3365 :         aArgs[ 1 ] <<= true;        // true = do not create a copy of the input stream
     240        8633 :         mxStorage.set( xFactory->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", aArgs ), UNO_QUERY_THROW );
     241             :     }
     242        1903 :     catch(const Exception& )
     243             :     {
     244        3365 :     }
     245        3365 : }
     246             : 
     247          64 : void OleStorage::initStorage( const Reference< XStream >& rxOutStream )
     248             : {
     249             :     // create base storage object
     250          64 :     if( rxOutStream.is() ) try
     251             :     {
     252          64 :         Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW );
     253         128 :         Sequence< Any > aArgs( 2 );
     254          64 :         aArgs[ 0 ] <<= rxOutStream;
     255          64 :         aArgs[ 1 ] <<= true;        // true = do not create a copy of the stream
     256         128 :         mxStorage.set( xFactory->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", aArgs ), UNO_QUERY_THROW );
     257             :     }
     258           0 :     catch(const Exception& )
     259             :     {
     260             :     }
     261          64 : }
     262             : 
     263             : // StorageBase interface ------------------------------------------------------
     264             : 
     265        3830 : bool OleStorage::implIsStorage() const
     266             : {
     267        3830 :     if( mxStorage.is() ) try
     268             :     {
     269             :         /*  If this is not an OLE storage, hasElements() of the OLESimpleStorage
     270             :             implementation throws an exception. But we do not return the result
     271             :             of hasElements(), because an empty storage is a valid storage too. */
     272        2048 :         (void)mxStorage->hasElements();
     273         634 :         return true;
     274             :     }
     275        1414 :     catch(const Exception& )
     276             :     {
     277             :     }
     278        3196 :     return false;
     279             : }
     280             : 
     281           0 : Reference< XStorage > OleStorage::implGetXStorage() const
     282             : {
     283             :     OSL_FAIL( "OleStorage::getXStorage - not implemented" );
     284           0 :     return Reference< XStorage >();
     285             : }
     286             : 
     287          96 : void OleStorage::implGetElementNames( ::std::vector< OUString >& orElementNames ) const
     288             : {
     289          96 :     Sequence< OUString > aNames;
     290          96 :     if( mxStorage.is() ) try
     291             :     {
     292          96 :         aNames = mxStorage->getElementNames();
     293          96 :         if( aNames.getLength() > 0 )
     294          96 :             orElementNames.insert( orElementNames.end(), aNames.getConstArray(), aNames.getConstArray() + aNames.getLength() );
     295             :     }
     296           0 :     catch(const Exception& )
     297             :     {
     298          96 :     }
     299          96 : }
     300             : 
     301         759 : StorageRef OleStorage::implOpenSubStorage( const OUString& rElementName, bool bCreateMissing )
     302             : {
     303         759 :     StorageRef xSubStorage;
     304         759 :     if( mxStorage.is() && !rElementName.isEmpty() )
     305             :     {
     306             :         try
     307             :         {
     308        1177 :             Reference< XNameContainer > xSubElements( mxStorage->getByName( rElementName ), UNO_QUERY_THROW );
     309          65 :             xSubStorage.reset( new OleStorage( *this, xSubElements, rElementName, true ) );
     310             :         }
     311         573 :         catch(const Exception& )
     312             :         {
     313             :         }
     314             : 
     315             :         /*  The OLESimpleStorage API implementation seems to be buggy in the
     316             :             area of writable inplace substorage (sometimes it overwrites other
     317             :             unrelated streams with zero bytes). We go the save way and create a
     318             :             new OLE storage based on a temporary file. All operations are
     319             :             performed on this clean storage. On committing, the storage will be
     320             :             completely re-inserted into the parent storage. */
     321         638 :         if( !isReadOnly() && (bCreateMissing || xSubStorage.get()) ) try
     322             :         {
     323             :             // create new storage based on a temp file
     324          33 :             Reference< XStream > xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
     325          66 :             StorageRef xTempStorage( new OleStorage( *this, xTempFile, rElementName ) );
     326             :             // copy existing substorage into temp storage
     327          33 :             if( xSubStorage.get() )
     328           0 :                 xSubStorage->copyStorageToStorage( *xTempStorage );
     329             :             // return the temp storage to caller
     330          66 :             xSubStorage = xTempStorage;
     331             :         }
     332           0 :         catch(const Exception& )
     333             :         {
     334             :         }
     335             :     }
     336         759 :     return xSubStorage;
     337             : }
     338             : 
     339         720 : Reference< XInputStream > OleStorage::implOpenInputStream( const OUString& rElementName )
     340             : {
     341         720 :     Reference< XInputStream > xInStream;
     342         720 :     if( mxStorage.is() ) try
     343             :     {
     344         720 :         xInStream.set( mxStorage->getByName( rElementName ), UNO_QUERY );
     345             :     }
     346          15 :     catch(const Exception& )
     347             :     {
     348             :     }
     349         720 :     return xInStream;
     350             : }
     351             : 
     352         475 : Reference< XOutputStream > OleStorage::implOpenOutputStream( const OUString& rElementName )
     353             : {
     354         475 :     Reference< XOutputStream > xOutStream;
     355         475 :     if( mxStorage.is() && !rElementName.isEmpty() )
     356         475 :         xOutStream.set( new OleOutputStream( mxContext, mxStorage, rElementName ) );
     357         475 :     return xOutStream;
     358             : }
     359             : 
     360          64 : void OleStorage::implCommit() const
     361             : {
     362             :     try
     363             :     {
     364             :         // commit this storage (finalizes the file this storage is based on)
     365          64 :         Reference< XTransactedObject >( mxStorage, UNO_QUERY_THROW )->commit();
     366             :         // re-insert this storage into the parent storage
     367          64 :         if( mpParentStorage )
     368             :         {
     369          33 :             if( mpParentStorage->mxStorage->hasByName( getName() ) )
     370             :             {
     371             :                 // replaceByName() does not work (#i109539#)
     372           0 :                 mpParentStorage->mxStorage->removeByName( getName() );
     373           0 :                 Reference< XTransactedObject >( mpParentStorage->mxStorage, UNO_QUERY_THROW )->commit();
     374             :             }
     375          33 :             mpParentStorage->mxStorage->insertByName( getName(), Any( mxStorage ) );
     376             :             // this requires another commit(), which will be performed by the parent storage
     377             :         }
     378             :     }
     379           0 :     catch(const Exception& )
     380             :     {
     381             :     }
     382          64 : }
     383             : 
     384             : } // namespace ole
     385         246 : } // namespace oox
     386             : 
     387             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11