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

Generated by: LCOV version 1.10