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

Generated by: LCOV version 1.10