summaryrefslogtreecommitdiffstats
path: root/embeddedobj/source/msole/olepersist.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /embeddedobj/source/msole/olepersist.cxx
parentInitial commit. (diff)
downloadlibreoffice-cb75148ebd0135178ff46f89a30139c44f8d2040.tar.xz
libreoffice-cb75148ebd0135178ff46f89a30139c44f8d2040.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'embeddedobj/source/msole/olepersist.cxx')
-rw-r--r--embeddedobj/source/msole/olepersist.cxx2019
1 files changed, 2019 insertions, 0 deletions
diff --git a/embeddedobj/source/msole/olepersist.cxx b/embeddedobj/source/msole/olepersist.cxx
new file mode 100644
index 000000000..86403f41b
--- /dev/null
+++ b/embeddedobj/source/msole/olepersist.cxx
@@ -0,0 +1,2019 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <oleembobj.hxx>
+#include "olepersist.hxx"
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+#include <com/sun/star/embed/EntryInitModes.hpp>
+#include <com/sun/star/embed/WrongStateException.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/EmbedUpdateModes.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XOptimizedStorage.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/io/IOException.hpp>
+
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/mimeconfighelper.hxx>
+#include <comphelper/classids.hxx>
+#include <osl/diagnose.h>
+#include <osl/thread.hxx>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+
+#include <closepreventer.hxx>
+
+#if defined(_WIN32)
+#include "olecomponent.hxx"
+#endif
+
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+
+
+bool KillFile_Impl( const OUString& aURL, const uno::Reference< uno::XComponentContext >& xContext )
+{
+ if ( !xContext.is() )
+ return false;
+
+ bool bRet = false;
+
+ try
+ {
+ uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
+ ucb::SimpleFileAccess::create( xContext ) );
+
+ xAccess->kill( aURL );
+ bRet = true;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ return bRet;
+}
+
+
+OUString GetNewTempFileURL_Impl( const uno::Reference< uno::XComponentContext >& xContext )
+{
+ SAL_WARN_IF( !xContext.is(), "embeddedobj.ole", "No factory is provided!" );
+
+ OUString aResult;
+
+ uno::Reference < io::XTempFile > xTempFile(
+ io::TempFile::create(xContext),
+ uno::UNO_SET_THROW );
+
+ try {
+ xTempFile->setRemoveFile( false );
+ aResult = xTempFile->getUri();
+ }
+ catch ( const uno::Exception& )
+ {
+ }
+
+ if ( aResult.isEmpty() )
+ throw uno::RuntimeException("Cannot create tempfile.");
+
+ return aResult;
+}
+
+
+OUString GetNewFilledTempFile_Impl( const uno::Reference< io::XInputStream >& xInStream,
+ const uno::Reference< uno::XComponentContext >& xContext )
+{
+ OSL_ENSURE( xInStream.is() && xContext.is(), "Wrong parameters are provided!" );
+
+ OUString aResult = GetNewTempFileURL_Impl( xContext );
+
+ if ( !aResult.isEmpty() )
+ {
+ try {
+ uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
+ ucb::SimpleFileAccess::create( xContext ) );
+
+ uno::Reference< io::XOutputStream > xTempOutStream = xTempAccess->openFileWrite( aResult );
+ if ( !xTempOutStream.is() )
+ throw io::IOException(); // TODO:
+ // copy stream contents to the file
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOutStream );
+ xTempOutStream->closeOutput();
+ xTempOutStream.clear();
+ }
+ catch( const packages::WrongPasswordException& )
+ {
+ KillFile_Impl( aResult, xContext );
+ throw io::IOException(); //TODO:
+ }
+ catch( const io::IOException& )
+ {
+ KillFile_Impl( aResult, xContext );
+ throw;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ KillFile_Impl( aResult, xContext );
+ throw;
+ }
+ catch( const uno::Exception& )
+ {
+ KillFile_Impl( aResult, xContext );
+ aResult.clear();
+ }
+ }
+
+ return aResult;
+}
+#ifdef _WIN32
+/// @throws io::IOException
+/// @throws uno::RuntimeException
+static OUString GetNewFilledTempFile_Impl( const uno::Reference< embed::XOptimizedStorage >& xParentStorage, const OUString& aEntryName, const uno::Reference< uno::XComponentContext >& xContext )
+{
+ OUString aResult;
+
+ try
+ {
+ uno::Reference < io::XTempFile > xTempFile(
+ io::TempFile::create(xContext),
+ uno::UNO_SET_THROW );
+
+ xParentStorage->copyStreamElementData( aEntryName, xTempFile );
+
+ xTempFile->setRemoveFile( false );
+ aResult = xTempFile->getUri();
+ }
+ catch( const uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ if ( aResult.isEmpty() )
+ throw io::IOException();
+
+ return aResult;
+}
+
+
+static void SetStreamMediaType_Impl( const uno::Reference< io::XStream >& xStream, const OUString& aMediaType )
+{
+ uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY_THROW );
+ xPropSet->setPropertyValue("MediaType", uno::Any( aMediaType ) );
+}
+#endif
+
+static void LetCommonStoragePassBeUsed_Impl( const uno::Reference< io::XStream >& xStream )
+{
+ uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY_THROW );
+ xPropSet->setPropertyValue("UseCommonStoragePasswordEncryption",
+ uno::Any( true ) );
+}
+#ifdef _WIN32
+
+void VerbExecutionController::StartControlExecution()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+
+ // the class is used to detect STAMPIT object, that can never be active
+ if ( !m_bVerbExecutionInProgress && !m_bWasEverActive )
+ {
+ m_bVerbExecutionInProgress = true;
+ m_nVerbExecutionThreadIdentifier = osl::Thread::getCurrentIdentifier();
+ m_bChangedOnVerbExecution = false;
+ }
+}
+
+
+bool VerbExecutionController::EndControlExecution_WasModified()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+
+ bool bResult = false;
+ if ( m_bVerbExecutionInProgress && m_nVerbExecutionThreadIdentifier == osl::Thread::getCurrentIdentifier() )
+ {
+ bResult = m_bChangedOnVerbExecution;
+ m_bVerbExecutionInProgress = false;
+ }
+
+ return bResult;
+}
+
+
+void VerbExecutionController::ModificationNotificationIsDone()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+
+ if ( m_bVerbExecutionInProgress && osl::Thread::getCurrentIdentifier() == m_nVerbExecutionThreadIdentifier )
+ m_bChangedOnVerbExecution = true;
+}
+#endif
+
+void VerbExecutionController::LockNotification()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+ if ( m_nNotificationLock < SAL_MAX_INT32 )
+ m_nNotificationLock++;
+}
+
+
+void VerbExecutionController::UnlockNotification()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+ if ( m_nNotificationLock > 0 )
+ m_nNotificationLock--;
+}
+
+
+uno::Reference< io::XStream > OleEmbeddedObject::GetNewFilledTempStream_Impl( const uno::Reference< io::XInputStream >& xInStream )
+{
+ SAL_WARN_IF( !xInStream.is(), "embeddedobj.ole", "Wrong parameter is provided!" );
+
+ uno::Reference < io::XStream > xTempFile(
+ io::TempFile::create(m_xContext),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XOutputStream > xTempOutStream = xTempFile->getOutputStream();
+ if ( !xTempOutStream.is() )
+ throw io::IOException(); // TODO:
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOutStream );
+ xTempOutStream->flush();
+ return xTempFile;
+}
+
+
+uno::Reference< io::XStream > OleEmbeddedObject::TryToGetAcceptableFormat_Impl( const uno::Reference< io::XStream >& xStream )
+{
+ // TODO/LATER: Actually this should be done by a centralized component ( may be a graphical filter )
+ if ( !m_xContext.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference< io::XInputStream > xInStream = xStream->getInputStream();
+ if ( !xInStream.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference< io::XSeekable > xSeek( xStream, uno::UNO_QUERY_THROW );
+ xSeek->seek( 0 );
+
+ uno::Sequence< sal_Int8 > aData( 8 );
+ sal_Int32 nRead = xInStream->readBytes( aData, 8 );
+ xSeek->seek( 0 );
+
+ if ( ( nRead >= 2 && aData[0] == 'B' && aData[1] == 'M' )
+ || ( nRead >= 4 && aData[0] == 1 && aData[1] == 0 && aData[2] == 9 && aData[3] == 0 ) )
+ {
+ // it should be a bitmap or a Metafile
+ return xStream;
+ }
+
+
+ sal_uInt32 nHeaderOffset = 0;
+ if ( ( nRead >= 8 && aData[0] == -1 && aData[1] == -1 && aData[2] == -1 && aData[3] == -1 )
+ && ( aData[4] == 2 || aData[4] == 3 || aData[4] == 14 ) && aData[5] == 0 && aData[6] == 0 && aData[7] == 0 )
+ {
+ nHeaderOffset = 40;
+ xSeek->seek( 8 );
+
+ // TargetDevice might be used in future, currently the cache has specified NULL
+ uno::Sequence< sal_Int8 > aHeadData( 4 );
+ nRead = xInStream->readBytes( aHeadData, 4 );
+ sal_uInt32 nLen = 0;
+ if ( nRead == 4 && aHeadData.getLength() == 4 )
+ nLen = ( ( ( static_cast<sal_uInt32>(aHeadData[3]) * 0x100 + static_cast<sal_uInt32>(aHeadData[2]) ) * 0x100 ) + static_cast<sal_uInt32>(aHeadData[1]) ) * 0x100 + static_cast<sal_uInt32>(aHeadData[0]);
+ if ( nLen > 4 )
+ {
+ xInStream->skipBytes( nLen - 4 );
+ nHeaderOffset += nLen - 4;
+ }
+
+ }
+ else if ( nRead > 4 )
+ {
+ // check whether the first bytes represent the size
+ sal_uInt32 nSize = 0;
+ for ( sal_Int32 nInd = 3; nInd >= 0; nInd-- )
+ nSize = ( nSize << 8 ) + static_cast<sal_uInt8>(aData[nInd]);
+
+ if ( nSize == xSeek->getLength() - 4 )
+ nHeaderOffset = 4;
+ }
+
+ if ( nHeaderOffset )
+ {
+ // this is either a bitmap or a metafile clipboard format, retrieve the pure stream
+ uno::Reference < io::XStream > xResult(
+ io::TempFile::create(m_xContext),
+ uno::UNO_QUERY_THROW );
+ uno::Reference < io::XSeekable > xResultSeek( xResult, uno::UNO_QUERY_THROW );
+ uno::Reference < io::XOutputStream > xResultOut = xResult->getOutputStream();
+ uno::Reference < io::XInputStream > xResultIn = xResult->getInputStream();
+ if ( !xResultOut.is() || !xResultIn.is() )
+ throw uno::RuntimeException();
+
+ xSeek->seek( nHeaderOffset ); // header size for these formats
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xResultOut );
+ xResultOut->closeOutput();
+ xResultSeek->seek( 0 );
+ xSeek->seek( 0 );
+
+ return xResult;
+ }
+
+ return uno::Reference< io::XStream >();
+}
+
+
+void OleEmbeddedObject::InsertVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream,
+ const uno::Reference< io::XStream >& xCachedVisualRepresentation )
+{
+ OSL_ENSURE( xTargetStream.is() && xCachedVisualRepresentation.is(), "Invalid arguments!" );
+
+ if ( !xTargetStream.is() || !xCachedVisualRepresentation.is() )
+ throw uno::RuntimeException();
+
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xTargetStream),
+ uno::Any(true) }; // do not create copy
+
+ uno::Reference< container::XNameContainer > xNameContainer(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY_THROW );
+ xCachedSeek->seek( 0 );
+
+ uno::Reference < io::XStream > xTempFile(
+ io::TempFile::create(m_xContext),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XSeekable > xTempSeek( xTempFile, uno::UNO_QUERY_THROW );
+ uno::Reference< io::XOutputStream > xTempOutStream = xTempFile->getOutputStream();
+ if ( !xTempOutStream.is() )
+ throw io::IOException(); // TODO:
+
+ // the OlePres stream must have additional header
+ // TODO/LATER: might need to be extended in future (actually makes sense only for SO7 format)
+ uno::Reference< io::XInputStream > xInCacheStream = xCachedVisualRepresentation->getInputStream();
+ if ( !xInCacheStream.is() )
+ throw uno::RuntimeException();
+
+ // write 0xFFFFFFFF at the beginning
+ uno::Sequence< sal_Int8 > aData( 4 );
+ auto pData = aData.getArray();
+ * reinterpret_cast<sal_uInt32*>(pData) = 0xFFFFFFFF;
+
+ xTempOutStream->writeBytes( aData );
+
+ // write clipboard format
+ uno::Sequence< sal_Int8 > aSigData( 2 );
+ xInCacheStream->readBytes( aSigData, 2 );
+ if ( aSigData.getLength() < 2 )
+ throw io::IOException();
+
+ if ( aSigData[0] == 'B' && aSigData[1] == 'M' )
+ {
+ // it's a bitmap
+ pData[0] = 0x02; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ }
+ else
+ {
+ // treat it as a metafile
+ pData[0] = 0x03; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ }
+ xTempOutStream->writeBytes( aData );
+
+ // write job related information
+ pData[0] = 0x04; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ xTempOutStream->writeBytes( aData );
+
+ // write aspect
+ pData[0] = 0x01; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ xTempOutStream->writeBytes( aData );
+
+ // write l-index
+ * reinterpret_cast<sal_uInt32*>(pData) = 0xFFFFFFFF;
+ xTempOutStream->writeBytes( aData );
+
+ // write adv. flags
+ pData[0] = 0x02; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ xTempOutStream->writeBytes( aData );
+
+ // write compression
+ * reinterpret_cast<sal_uInt32*>(pData) = 0x0;
+ xTempOutStream->writeBytes( aData );
+
+ // get the size
+ awt::Size aSize = getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
+ sal_Int32 nIndex = 0;
+
+ // write width
+ for ( nIndex = 0; nIndex < 4; nIndex++ )
+ {
+ pData[nIndex] = static_cast<sal_Int8>( aSize.Width % 0x100 );
+ aSize.Width /= 0x100;
+ }
+ xTempOutStream->writeBytes( aData );
+
+ // write height
+ for ( nIndex = 0; nIndex < 4; nIndex++ )
+ {
+ pData[nIndex] = static_cast<sal_Int8>( aSize.Height % 0x100 );
+ aSize.Height /= 0x100;
+ }
+ xTempOutStream->writeBytes( aData );
+
+ // write garbage, it will be overwritten by the size
+ xTempOutStream->writeBytes( aData );
+
+ // write first bytes that was used to detect the type
+ xTempOutStream->writeBytes( aSigData );
+
+ // write the rest of the stream
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInCacheStream, xTempOutStream );
+
+ // write the size of the stream
+ sal_Int64 nLength = xTempSeek->getLength() - 40;
+ if ( nLength < 0 || nLength >= 0xFFFFFFFF )
+ {
+ SAL_WARN( "embeddedobj.ole", "Length is not acceptable!" );
+ return;
+ }
+ for ( sal_Int32 nInd = 0; nInd < 4; nInd++ )
+ {
+ pData[nInd] = static_cast<sal_Int8>( static_cast<sal_uInt64>(nLength) % 0x100 );
+ nLength /= 0x100;
+ }
+ xTempSeek->seek( 36 );
+ xTempOutStream->writeBytes( aData );
+
+ xTempOutStream->flush();
+
+ xTempSeek->seek( 0 );
+ if ( xCachedSeek.is() )
+ xCachedSeek->seek( 0 );
+
+ // insert the result file as replacement image
+ OUString aCacheName = "\002OlePres000";
+ if ( xNameContainer->hasByName( aCacheName ) )
+ xNameContainer->replaceByName( aCacheName, uno::Any( xTempFile ) );
+ else
+ xNameContainer->insertByName( aCacheName, uno::Any( xTempFile ) );
+
+ uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY_THROW );
+ xTransacted->commit();
+}
+
+
+void OleEmbeddedObject::RemoveVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream )
+{
+ OSL_ENSURE( xTargetStream.is(), "Invalid argument!" );
+ if ( !xTargetStream.is() )
+ throw uno::RuntimeException();
+
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xTargetStream),
+ uno::Any(true) }; // do not create copy
+ uno::Reference< container::XNameContainer > xNameContainer(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY_THROW );
+
+ for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
+ {
+ OUString aStreamName = "\002OlePres00" + OUString::number( nInd );
+ if ( xNameContainer->hasByName( aStreamName ) )
+ xNameContainer->removeByName( aStreamName );
+ }
+
+ uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY_THROW );
+ xTransacted->commit();
+}
+
+
+void OleEmbeddedObject::SetVisReplInStream( bool bExists )
+{
+ m_bVisReplInitialized = true;
+ m_bVisReplInStream = bExists;
+}
+
+
+bool OleEmbeddedObject::HasVisReplInStream()
+{
+ if ( !m_bVisReplInitialized )
+ {
+ if ( m_xCachedVisualRepresentation.is() )
+ SetVisReplInStream( true );
+ else
+ {
+ SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::HasVisualReplInStream, analyzing" );
+
+ uno::Reference< io::XInputStream > xStream;
+
+ OSL_ENSURE( !m_pOleComponent || !m_aTempURL.isEmpty(), "The temporary file must exist if there is a component!" );
+ if ( !m_aTempURL.isEmpty() )
+ {
+ try
+ {
+ // open temporary file for reading
+ uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
+ ucb::SimpleFileAccess::create( m_xContext ) );
+
+ xStream = xTempAccess->openFileRead( m_aTempURL );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+
+ if ( !xStream.is() )
+ xStream = m_xObjectStream->getInputStream();
+
+ if ( xStream.is() )
+ {
+ bool bExists = false;
+
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xStream),
+ uno::Any(true) }; // do not create copy
+ uno::Reference< container::XNameContainer > xNameContainer(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY );
+
+ if ( xNameContainer.is() )
+ {
+ for ( sal_uInt8 nInd = 0; nInd < 10 && !bExists; nInd++ )
+ {
+ OUString aStreamName = "\002OlePres00" + OUString::number( nInd );
+ try
+ {
+ bExists = xNameContainer->hasByName( aStreamName );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ }
+
+ SetVisReplInStream( bExists );
+ }
+ }
+ }
+
+ return m_bVisReplInStream;
+}
+
+
+uno::Reference< io::XStream > OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation_Impl(
+ const uno::Reference< io::XStream >& xStream,
+ bool bAllowToRepair50 )
+ noexcept
+{
+ uno::Reference< io::XStream > xResult;
+
+ if ( xStream.is() )
+ {
+ SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation, retrieving" );
+
+ uno::Reference< container::XNameContainer > xNameContainer;
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xStream),
+ uno::Any(true) }; // do not create copy
+ try
+ {
+ xNameContainer.set(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY );
+ }
+ catch( const uno::Exception& )
+ {}
+
+ if ( xNameContainer.is() )
+ {
+ for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
+ {
+ OUString aStreamName = "\002OlePres00" + OUString::number( nInd );
+ uno::Reference< io::XStream > xCachedCopyStream;
+ try
+ {
+ if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
+ {
+ xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
+ if ( xResult.is() )
+ break;
+ }
+ }
+ catch( const uno::Exception& )
+ {}
+
+ if ( nInd == 0 )
+ {
+ // to be compatible with the old versions Ole10Native is checked after OlePress000
+ aStreamName = "\001Ole10Native";
+ try
+ {
+ if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
+ {
+ xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
+ if ( xResult.is() )
+ break;
+ }
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ }
+
+ try
+ {
+ if ( bAllowToRepair50 && !xResult.is() )
+ {
+ OUString aOrigContName( "Ole-Object" );
+ if ( xNameContainer->hasByName( aOrigContName ) )
+ {
+ uno::Reference< embed::XClassifiedObject > xClassified( xNameContainer, uno::UNO_QUERY_THROW );
+ if ( MimeConfigurationHelper::ClassIDsEqual( xClassified->getClassID(), MimeConfigurationHelper::GetSequenceClassID( SO3_OUT_CLASSID ) ) )
+ {
+ // this is an OLE object wrongly stored in 5.0 format
+ // this object must be repaired since SO7 has done it
+
+ uno::Reference< io::XOutputStream > xOutputStream = xStream->getOutputStream();
+ uno::Reference< io::XTruncate > xTruncate( xOutputStream, uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XInputStream > xOrigInputStream;
+ if ( ( xNameContainer->getByName( aOrigContName ) >>= xOrigInputStream )
+ && xOrigInputStream.is() )
+ {
+ // the provided input stream must be based on temporary medium and must be independent
+ // from the stream the storage is based on
+ uno::Reference< io::XSeekable > xOrigSeekable( xOrigInputStream, uno::UNO_QUERY );
+ if ( xOrigSeekable.is() )
+ xOrigSeekable->seek( 0 );
+
+ uno::Reference< lang::XComponent > xNameContDisp( xNameContainer, uno::UNO_QUERY_THROW );
+ xNameContDisp->dispose(); // free the original stream
+
+ xTruncate->truncate();
+ ::comphelper::OStorageHelper::CopyInputToOutput( xOrigInputStream, xOutputStream );
+ xOutputStream->flush();
+
+ if ( xStream == m_xObjectStream )
+ {
+ if ( !m_aTempURL.isEmpty() )
+ {
+ // this is the own stream, so the temporary URL must be cleaned if it exists
+ KillFile_Impl( m_aTempURL, m_xContext );
+ m_aTempURL.clear();
+ }
+
+#ifdef _WIN32
+ // retry to create the component after recovering
+ GetRidOfComponent();
+
+ try
+ {
+ CreateOleComponentAndLoad_Impl();
+ m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
+ }
+ catch( const uno::Exception& )
+ {
+ GetRidOfComponent();
+ }
+#endif
+ }
+
+ xResult = TryToRetrieveCachedVisualRepresentation_Impl( xStream );
+ }
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ }
+
+ return xResult;
+}
+
+
+void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
+ const uno::Reference< io::XStream >& xNewObjectStream,
+ const OUString& aNewName )
+{
+ if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
+ {
+ SAL_WARN_IF( xNewObjectStream != m_xObjectStream, "embeddedobj.ole", "The streams must be the same!" );
+ return;
+ }
+
+ uno::Reference<io::XSeekable> xNewSeekable(xNewObjectStream, uno::UNO_QUERY);
+ if (xNewSeekable.is() && xNewSeekable->getLength() == 0)
+ {
+ uno::Reference<io::XSeekable> xOldSeekable(m_xObjectStream, uno::UNO_QUERY);
+ if (xOldSeekable.is() && xOldSeekable->getLength() > 0)
+ {
+ SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::SwitchOwnPersistence(stream version): "
+ "empty new stream, reusing old one");
+ uno::Reference<io::XInputStream> xInput = m_xObjectStream->getInputStream();
+ uno::Reference<io::XOutputStream> xOutput = xNewObjectStream->getOutputStream();
+ xOldSeekable->seek(0);
+ comphelper::OStorageHelper::CopyInputToOutput(xInput, xOutput);
+ xNewSeekable->seek(0);
+ }
+ }
+
+ try {
+ uno::Reference< lang::XComponent > xComponent( m_xObjectStream, uno::UNO_QUERY );
+ OSL_ENSURE( !m_xObjectStream.is() || xComponent.is(), "Wrong stream implementation!" );
+ if ( xComponent.is() )
+ xComponent->dispose();
+ }
+ catch ( const uno::Exception& )
+ {
+ }
+
+ m_xObjectStream = xNewObjectStream;
+ m_xParentStorage = xNewParentStorage;
+ m_aEntryName = aNewName;
+}
+
+
+void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
+ const OUString& aNewName )
+{
+ if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
+ return;
+
+ sal_Int32 nStreamMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
+
+ uno::Reference< io::XStream > xNewOwnStream = xNewParentStorage->openStreamElement( aNewName, nStreamMode );
+
+ uno::Reference<io::XSeekable> xNewSeekable (xNewOwnStream, uno::UNO_QUERY);
+ if (xNewSeekable.is() && xNewSeekable->getLength() == 0)
+ {
+ uno::Reference<io::XSeekable> xOldSeekable(m_xObjectStream, uno::UNO_QUERY);
+ if (xOldSeekable.is() && xOldSeekable->getLength() > 0)
+ {
+ SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::SwitchOwnPersistence: empty new stream, reusing old one");
+ uno::Reference<io::XInputStream> xInput = m_xObjectStream->getInputStream();
+ uno::Reference<io::XOutputStream> xOutput = xNewOwnStream->getOutputStream();
+ comphelper::OStorageHelper::CopyInputToOutput(xInput, xOutput);
+ xNewSeekable->seek(0);
+ }
+ }
+
+ SAL_WARN_IF( !xNewOwnStream.is(), "embeddedobj.ole", "The method can not return empty reference!" );
+
+ SwitchOwnPersistence( xNewParentStorage, xNewOwnStream, aNewName );
+}
+
+#ifdef _WIN32
+
+bool OleEmbeddedObject::SaveObject_Impl()
+{
+ bool bResult = false;
+
+ if ( m_xClientSite.is() )
+ {
+ try
+ {
+ m_xClientSite->saveObject();
+ bResult = true;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ return bResult;
+}
+
+
+bool OleEmbeddedObject::OnShowWindow_Impl( bool bShow )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ bool bResult = false;
+
+ SAL_WARN_IF( m_nObjectState == -1, "embeddedobj.ole", "The object has no persistence!" );
+ SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "The object get OnShowWindow in loaded state!" );
+ if ( m_nObjectState == -1 || m_nObjectState == embed::EmbedStates::LOADED )
+ return false;
+
+ // the object is either activated or deactivated
+ sal_Int32 nOldState = m_nObjectState;
+ if ( bShow && m_nObjectState == embed::EmbedStates::RUNNING )
+ {
+ m_nObjectState = embed::EmbedStates::ACTIVE;
+ m_aVerbExecutionController.ObjectIsActive();
+
+ aGuard.clear();
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ }
+ else if ( !bShow && m_nObjectState == embed::EmbedStates::ACTIVE )
+ {
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ aGuard.clear();
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ }
+
+ if ( m_xClientSite.is() )
+ {
+ try
+ {
+ m_xClientSite->visibilityChanged( bShow );
+ bResult = true;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ return bResult;
+}
+
+
+void OleEmbeddedObject::OnIconChanged_Impl()
+{
+ // TODO/LATER: currently this notification seems to be impossible
+ // MakeEventListenerNotification_Impl( OUString( "OnIconChanged" ) );
+}
+
+
+void OleEmbeddedObject::OnViewChanged_Impl()
+{
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ // For performance reasons the notification currently is ignored, STAMPIT object is the exception,
+ // it can never be active and never call SaveObject, so it is the only way to detect that it is changed
+
+ // ==== the STAMPIT related solution =============================
+ // the following variable is used to detect whether the object was modified during verb execution
+ m_aVerbExecutionController.ModificationNotificationIsDone();
+
+ // The following things are controlled by VerbExecutionController:
+ // - if the verb execution is in progress and the view is changed the object will be stored
+ // after the execution, so there is no need to send the notification.
+ // - the STAMPIT object can never be active.
+ if (m_aVerbExecutionController.CanDoNotification() &&
+ m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE &&
+ (MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(0x852ee1c9, 0x9058, 0x44ba, 0x8c, 0x6c, 0x0c, 0x5f, 0xc6, 0x6b, 0xdb, 0x8d)) ||
+ MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(0xcf1b4491, 0xbea3, 0x4c9f, 0xa7, 0x0f, 0x22, 0x1b, 0x1e, 0xca, 0xef, 0x3e)))
+ )
+ {
+ // The view is changed while the object is in running state, save the new object
+ m_xCachedVisualRepresentation.clear();
+ SaveObject_Impl();
+ MakeEventListenerNotification_Impl( "OnVisAreaChanged" );
+ }
+
+}
+
+
+void OleEmbeddedObject::OnClosed_Impl()
+{
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( m_nObjectState != embed::EmbedStates::LOADED )
+ {
+ sal_Int32 nOldState = m_nObjectState;
+ m_nObjectState = embed::EmbedStates::LOADED;
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ }
+}
+
+
+OUString OleEmbeddedObject::CreateTempURLEmpty_Impl()
+{
+ SAL_WARN_IF( !m_aTempURL.isEmpty(), "embeddedobj.ole", "The object has already the temporary file!" );
+ m_aTempURL = GetNewTempFileURL_Impl( m_xContext );
+
+ return m_aTempURL;
+}
+
+
+OUString OleEmbeddedObject::GetTempURL_Impl()
+{
+ if ( m_aTempURL.isEmpty() )
+ {
+ SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::GetTempURL_Impl, tempfile creation" );
+
+ // if there is no temporary file, it will be created from the own entry
+ uno::Reference< embed::XOptimizedStorage > xOptParStorage( m_xParentStorage, uno::UNO_QUERY );
+ if ( xOptParStorage.is() )
+ {
+ m_aTempURL = GetNewFilledTempFile_Impl( xOptParStorage, m_aEntryName, m_xContext );
+ }
+ else if ( m_xObjectStream.is() )
+ {
+ // load object from the stream
+ uno::Reference< io::XInputStream > xInStream = m_xObjectStream->getInputStream();
+ if ( !xInStream.is() )
+ throw io::IOException(); // TODO: access denied
+
+ m_aTempURL = GetNewFilledTempFile_Impl( xInStream, m_xContext );
+ }
+ }
+
+ return m_aTempURL;
+}
+
+
+void OleEmbeddedObject::CreateOleComponent_Impl(
+ rtl::Reference<OleComponent> const & pOleComponent )
+{
+ if ( !m_pOleComponent )
+ {
+ m_pOleComponent = pOleComponent ? pOleComponent : new OleComponent( m_xContext, this );
+
+ if ( !m_xClosePreventer.is() )
+ m_xClosePreventer = new OClosePreventer;
+
+ m_pOleComponent->addCloseListener( m_xClosePreventer );
+ }
+}
+
+
+void OleEmbeddedObject::CreateOleComponentAndLoad_Impl(
+ rtl::Reference<OleComponent> const & pOleComponent )
+{
+ if ( !m_pOleComponent )
+ {
+ if ( !m_xObjectStream.is() )
+ throw uno::RuntimeException();
+
+ CreateOleComponent_Impl( pOleComponent );
+
+ // after the loading the object can appear as a link
+ // will be detected later by olecomponent
+
+ GetTempURL_Impl();
+ if ( m_aTempURL.isEmpty() )
+ throw uno::RuntimeException(); // TODO
+
+ m_pOleComponent->LoadEmbeddedObject( m_aTempURL );
+ }
+}
+
+
+void OleEmbeddedObject::CreateOleComponentFromClipboard_Impl( OleComponent* pOleComponent )
+{
+ if ( !m_pOleComponent )
+ {
+ if ( !m_xObjectStream.is() )
+ throw uno::RuntimeException();
+
+ CreateOleComponent_Impl( pOleComponent );
+
+ // after the loading the object can appear as a link
+ // will be detected later by olecomponent
+ m_pOleComponent->CreateObjectFromClipboard();
+ }
+}
+
+
+uno::Reference< io::XOutputStream > OleEmbeddedObject::GetStreamForSaving()
+{
+ if ( !m_xObjectStream.is() )
+ throw uno::RuntimeException(); //TODO:
+
+ uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
+ if ( !xOutStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ uno::Reference< io::XTruncate > xTruncate( xOutStream, uno::UNO_QUERY_THROW );
+ xTruncate->truncate();
+
+ return xOutStream;
+}
+
+
+void OleEmbeddedObject::StoreObjectToStream( uno::Reference< io::XOutputStream > const & xOutStream )
+{
+ // this method should be used only on windows
+ if ( m_pOleComponent )
+ m_pOleComponent->StoreOwnTmpIfNecessary();
+
+ // now all the changes should be in temporary location
+ if ( m_aTempURL.isEmpty() )
+ throw uno::RuntimeException();
+
+ // open temporary file for reading
+ uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
+ ucb::SimpleFileAccess::create( m_xContext ) );
+
+ uno::Reference< io::XInputStream > xTempInStream = xTempAccess->openFileRead( m_aTempURL );
+ SAL_WARN_IF( !xTempInStream.is(), "embeddedobj.ole", "The object's temporary file can not be reopened for reading!" );
+
+ // TODO: use bStoreVisReplace
+
+ if ( !xTempInStream.is() )
+ {
+ throw io::IOException(); // TODO:
+ }
+
+ // write all the contents to XOutStream
+ uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY_THROW );
+ xTrunc->truncate();
+
+ ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutStream );
+
+ // TODO: should the view replacement be in the stream ???
+ // probably it must be specified on storing
+}
+#endif
+
+void OleEmbeddedObject::StoreToLocation_Impl(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs,
+ bool bSaveAs )
+{
+ // TODO: use lObjArgs
+ // TODO: exchange StoreVisualReplacement by SO file format version?
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "Can't store object without persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!" );
+
+ bool bVisReplIsStored = false;
+
+ bool bTryOptimization = false;
+ bool bStoreVis = m_bStoreVisRepl;
+ uno::Reference< io::XStream > xCachedVisualRepresentation;
+ for ( beans::PropertyValue const & prop : lObjArgs )
+ {
+ if ( prop.Name == "StoreVisualReplacement" )
+ prop.Value >>= bStoreVis;
+ else if ( prop.Name == "VisualReplacement" )
+ prop.Value >>= xCachedVisualRepresentation;
+ else if ( prop.Name == "CanTryOptimization" )
+ prop.Value >>= bTryOptimization;
+ }
+
+ // ignore visual representation provided from outside if it should not be stored
+ if ( !bStoreVis )
+ xCachedVisualRepresentation.clear();
+
+ if ( bStoreVis && !HasVisReplInStream() && !xCachedVisualRepresentation.is() )
+ throw io::IOException(); // TODO: there is no cached visual representation and nothing is provided from outside
+
+ // if the representation is provided from outside it should be copied to a local stream
+ bool bNeedLocalCache = xCachedVisualRepresentation.is();
+
+ uno::Reference< io::XStream > xTargetStream;
+
+ bool bStoreLoaded = false;
+ if ( m_nObjectState == embed::EmbedStates::LOADED
+#ifdef _WIN32
+ // if the object was NOT modified after storing it can be just copied
+ // as if it was in loaded state
+ || ( m_pOleComponent && !m_pOleComponent->IsDirty() )
+#endif
+ )
+ {
+ bool bOptimizedCopyingDone = false;
+
+ if ( bTryOptimization && bStoreVis == HasVisReplInStream() )
+ {
+ try
+ {
+ uno::Reference< embed::XOptimizedStorage > xSourceOptStor( m_xParentStorage, uno::UNO_QUERY_THROW );
+ uno::Reference< embed::XOptimizedStorage > xTargetOptStor( xStorage, uno::UNO_QUERY_THROW );
+ xSourceOptStor->copyElementDirectlyTo( m_aEntryName, xTargetOptStor, sEntName );
+ bOptimizedCopyingDone = true;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ if ( !bOptimizedCopyingDone )
+ {
+ // if optimized copying fails a normal one should be tried
+ m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
+ }
+
+ // the locally retrieved representation is always preferable
+ // since the object is in loaded state the representation is unchanged
+ if ( m_xCachedVisualRepresentation.is() )
+ {
+ xCachedVisualRepresentation = m_xCachedVisualRepresentation;
+ bNeedLocalCache = false;
+ }
+
+ bVisReplIsStored = HasVisReplInStream();
+ bStoreLoaded = true;
+ }
+#ifdef _WIN32
+ else if ( m_pOleComponent )
+ {
+ xTargetStream =
+ xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
+ if ( !xTargetStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ SetStreamMediaType_Impl( xTargetStream, "application/vnd.sun.star.oleobject" );
+ uno::Reference< io::XOutputStream > xOutStream = xTargetStream->getOutputStream();
+ if ( !xOutStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ StoreObjectToStream( xOutStream );
+ bVisReplIsStored = true;
+
+ if ( bSaveAs )
+ {
+ // no need to do it on StoreTo since in this case the replacement is in the stream
+ // and there is no need to cache it even if it is thrown away because the object
+ // is not changed by StoreTo action
+
+ uno::Reference< io::XStream > xTmpCVRepresentation =
+ TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
+
+ // the locally retrieved representation is always preferable
+ if ( xTmpCVRepresentation.is() )
+ {
+ xCachedVisualRepresentation = xTmpCVRepresentation;
+ bNeedLocalCache = false;
+ }
+ }
+ }
+#endif
+ else if (true) // loplugin:flatten
+ {
+ throw io::IOException(); // TODO
+ }
+
+ if ( !xTargetStream.is() )
+ {
+ xTargetStream =
+ xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
+ if ( !xTargetStream.is() )
+ throw io::IOException(); //TODO: access denied
+ }
+
+ LetCommonStoragePassBeUsed_Impl( xTargetStream );
+
+ if ( bStoreVis != bVisReplIsStored )
+ {
+ if ( bStoreVis )
+ {
+ if ( !xCachedVisualRepresentation.is() )
+ xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
+
+ SAL_WARN_IF( !xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
+
+ // the following copying will be done in case it is SaveAs anyway
+ // if it is not SaveAs the seekable access is not required currently
+ // TODO/LATER: may be required in future
+ if ( bSaveAs )
+ {
+ uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY );
+ if ( !xCachedSeek.is() )
+ {
+ xCachedVisualRepresentation
+ = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
+ bNeedLocalCache = false;
+ }
+ }
+
+ InsertVisualCache_Impl( xTargetStream, xCachedVisualRepresentation );
+ }
+ else
+ {
+ // the removed representation could be cached by this method
+ if ( !xCachedVisualRepresentation.is() )
+ xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
+
+ if (!m_bStreamReadOnly)
+ RemoveVisualCache_Impl(xTargetStream);
+ }
+ }
+
+ if ( bSaveAs )
+ {
+ m_bWaitSaveCompleted = true;
+ m_xNewObjectStream = xTargetStream;
+ m_xNewParentStorage = xStorage;
+ m_aNewEntryName = sEntName;
+ m_bNewVisReplInStream = bStoreVis;
+ m_bStoreLoaded = bStoreLoaded;
+
+ if ( xCachedVisualRepresentation.is() )
+ {
+ if ( bNeedLocalCache )
+ m_xNewCachedVisRepl = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
+ else
+ m_xNewCachedVisRepl = xCachedVisualRepresentation;
+ }
+
+ // TODO: register listeners for storages above, in case they are disposed
+ // an exception will be thrown on saveCompleted( true )
+ }
+ else
+ {
+ uno::Reference< lang::XComponent > xComp( xTargetStream, uno::UNO_QUERY );
+ if ( xComp.is() )
+ {
+ try {
+ xComp->dispose();
+ } catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+}
+
+
+void SAL_CALL OleEmbeddedObject::setPersistentEntry(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ sal_Int32 nEntryConnectionMode,
+ const uno::Sequence< beans::PropertyValue >& lArguments,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setPersistentEntry( xStorage, sEntName, nEntryConnectionMode, lArguments, lObjArgs );
+ return;
+ }
+ // end wrapping related part ====================
+
+ // TODO: use lObjArgs
+
+ // the type of the object must be already set
+ // a kind of typedetection should be done in the factory;
+ // the only exception is object initialized from a stream,
+ // the class ID will be detected from the stream
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ // May be LOADED should be forbidden here ???
+ if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
+ && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
+ {
+ // if the object is not loaded
+ // it can not get persistent representation without initialization
+
+ // if the object is loaded
+ // it can switch persistent representation only without initialization
+
+ throw embed::WrongStateException(
+ "Can't change persistent representation of activated object!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ {
+ if ( nEntryConnectionMode != embed::EntryInitModes::NO_INIT )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ saveCompleted( m_xParentStorage != xStorage || m_aEntryName != sEntName );
+ }
+
+ uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
+
+ // detect entry existence
+ bool bElExists = xNameAccess->hasByName( sEntName );
+
+ m_bReadOnly = false;
+ for ( beans::PropertyValue const & prop : lArguments )
+ if ( prop.Name == "ReadOnly" )
+ prop.Value >>= m_bReadOnly;
+
+#ifdef _WIN32
+ sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
+#endif
+
+ SwitchOwnPersistence( xStorage, sEntName );
+
+ for ( beans::PropertyValue const & prop : lObjArgs )
+ if ( prop.Name == "StoreVisualReplacement" )
+ prop.Value >>= m_bStoreVisRepl;
+
+#ifdef _WIN32
+ if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
+ {
+ if ( m_bFromClipboard )
+ {
+ // the object should be initialized from clipboard
+ // impossibility to initialize the object means error here
+ CreateOleComponentFromClipboard_Impl();
+ m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
+ m_pOleComponent->RunObject();
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ }
+ else if ( bElExists )
+ {
+ // load object from the stream
+ // after the loading the object can appear as a link
+ // will be detected by olecomponent
+ try
+ {
+ CreateOleComponentAndLoad_Impl();
+ m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
+ }
+ catch( const uno::Exception& )
+ {
+ // TODO/LATER: detect classID of the object if possible
+ // means that the object inprocess server could not be successfully instantiated
+ GetRidOfComponent();
+ }
+
+ m_nObjectState = embed::EmbedStates::LOADED;
+ }
+ else
+ {
+ // create a new object
+ CreateOleComponent_Impl();
+ m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
+ m_pOleComponent->RunObject();
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ }
+ }
+ else
+ {
+ if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
+ throw io::IOException();
+
+ if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
+ {
+ // the document just already changed its stream to store to;
+ // the links to OLE documents switch their persistence in the same way
+ // as normal embedded objects
+ }
+ else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
+ {
+ // create a new object, that will be stored in specified stream
+ CreateOleComponent_Impl();
+
+ m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
+ m_pOleComponent->RunObject();
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ }
+ else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
+ {
+ // use URL ( may be content or stream later ) from MediaDescriptor to initialize object
+ OUString aURL;
+ for ( beans::PropertyValue const & prop : lArguments )
+ if ( prop.Name == "URL" )
+ prop.Value >>= aURL;
+
+ if ( aURL.isEmpty() )
+ throw lang::IllegalArgumentException(
+ "Empty URL is provided in the media descriptor!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 4 );
+
+ CreateOleComponent_Impl();
+
+ // TODO: the m_bIsLink value must be set already
+ if ( !m_bIsLink )
+ m_pOleComponent->CreateObjectFromFile( aURL );
+ else
+ m_pOleComponent->CreateLinkFromFile( aURL );
+
+ m_pOleComponent->RunObject();
+ m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
+
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ }
+ //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
+ //{
+ //TODO:
+ //}
+ else
+ throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 3 );
+ }
+#else
+ // On Unix the OLE object can not do anything except storing itself somewhere
+ if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT && bElExists )
+ {
+ // TODO/LATER: detect classID of the object
+ // can be a real problem for the links
+
+ m_nObjectState = embed::EmbedStates::LOADED;
+ }
+ else if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
+ {
+ // do nothing, the object has already switched it's persistence
+ }
+ else
+ throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 3 );
+
+#endif
+}
+
+
+void SAL_CALL OleEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& lArguments,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->storeToEntry( xStorage, sEntName, lArguments, lObjArgs );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
+
+ StoreToLocation_Impl( xStorage, sEntName, lObjArgs, false );
+
+ // TODO: should the listener notification be done?
+}
+
+
+void SAL_CALL OleEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& lArguments,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->storeAsEntry( xStorage, sEntName, lArguments, lObjArgs );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
+
+ StoreToLocation_Impl( xStorage, sEntName, lObjArgs, true );
+
+ // TODO: should the listener notification be done here or in saveCompleted?
+}
+
+
+void SAL_CALL OleEmbeddedObject::saveCompleted( sal_Bool bUseNew )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->saveCompleted( bUseNew );
+ return;
+ }
+ // end wrapping related part ====================
+
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "Can't store object without persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ // it is allowed to call saveCompleted( false ) for nonstored objects
+ if ( !m_bWaitSaveCompleted && !bUseNew )
+ return;
+
+ SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.ole", "Unexpected saveCompleted() call!" );
+ if ( !m_bWaitSaveCompleted )
+ throw io::IOException(); // TODO: illegal call
+
+ OSL_ENSURE( m_xNewObjectStream.is() && m_xNewParentStorage.is() , "Internal object information is broken!" );
+ if ( !m_xNewObjectStream.is() || !m_xNewParentStorage.is() )
+ throw uno::RuntimeException(); // TODO: broken internal information
+
+ if ( bUseNew )
+ {
+ SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStream, m_aNewEntryName );
+ m_bStoreVisRepl = m_bNewVisReplInStream;
+ SetVisReplInStream( m_bNewVisReplInStream );
+ m_xCachedVisualRepresentation = m_xNewCachedVisRepl;
+ }
+ else
+ {
+ // close remembered stream
+ try {
+ uno::Reference< lang::XComponent > xComponent( m_xNewObjectStream, uno::UNO_QUERY );
+ SAL_WARN_IF( !xComponent.is(), "embeddedobj.ole", "Wrong storage implementation!" );
+ if ( xComponent.is() )
+ xComponent->dispose();
+ }
+ catch ( const uno::Exception& )
+ {
+ }
+ }
+
+ bool bStoreLoaded = m_bStoreLoaded;
+
+ m_xNewObjectStream.clear();
+ m_xNewParentStorage.clear();
+ m_aNewEntryName.clear();
+ m_bWaitSaveCompleted = false;
+ m_bNewVisReplInStream = false;
+ m_xNewCachedVisRepl.clear();
+ m_bStoreLoaded = false;
+
+ if ( bUseNew && m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded
+ && m_nObjectState != embed::EmbedStates::LOADED )
+ {
+ // the object replacement image should be updated, so the cached size as well
+ m_bHasCachedSize = false;
+ try
+ {
+ // the call will cache the size in case of success
+ // probably it might need to be done earlier, while the object is in active state
+ getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+
+ aGuard.clear();
+ if ( bUseNew )
+ {
+ MakeEventListenerNotification_Impl( "OnSaveAsDone");
+
+ // the object can be changed only on windows
+ // the notification should be done only if the object is not in loaded state
+ if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
+ {
+ MakeEventListenerNotification_Impl( "OnVisAreaChanged");
+ }
+ }
+}
+
+
+sal_Bool SAL_CALL OleEmbeddedObject::hasEntry()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->hasEntry();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( m_xObjectStream.is() )
+ return true;
+
+ return false;
+}
+
+
+OUString SAL_CALL OleEmbeddedObject::getEntryName()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getEntryName();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "The object persistence is not initialized!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ return m_aEntryName;
+}
+
+
+void SAL_CALL OleEmbeddedObject::storeOwn()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->storeOwn();
+ return;
+ }
+ // end wrapping related part ====================
+
+ // during switching from Activated to Running and from Running to Loaded states the object will
+ // ask container to store the object, the container has to make decision
+ // to do so or not
+
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "Can't store object without persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( m_bReadOnly )
+ throw io::IOException(); // TODO: access denied
+
+ LetCommonStoragePassBeUsed_Impl( m_xObjectStream );
+
+ bool bStoreLoaded = true;
+
+#ifdef _WIN32
+ if ( m_nObjectState != embed::EmbedStates::LOADED && m_pOleComponent && m_pOleComponent->IsDirty() )
+ {
+ bStoreLoaded = false;
+
+ OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!" );
+
+ if ( !m_xObjectStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ SetStreamMediaType_Impl( m_xObjectStream, "application/vnd.sun.star.oleobject" );
+ uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
+ if ( !xOutStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ // TODO: does this work for links too?
+ StoreObjectToStream( GetStreamForSaving() );
+
+ // the replacement is changed probably, and it must be in the object stream
+ if ( !m_pOleComponent->IsWorkaroundActive() )
+ m_xCachedVisualRepresentation.clear();
+ SetVisReplInStream( true );
+ }
+#endif
+
+ if ( m_bStoreVisRepl != HasVisReplInStream() )
+ {
+ if ( m_bStoreVisRepl )
+ {
+ // the m_xCachedVisualRepresentation must be set or it should be already stored
+ if ( m_xCachedVisualRepresentation.is() )
+ InsertVisualCache_Impl( m_xObjectStream, m_xCachedVisualRepresentation );
+ else
+ {
+ m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
+ SAL_WARN_IF( !m_xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
+ }
+ }
+ else
+ {
+ if ( !m_xCachedVisualRepresentation.is() )
+ m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
+ RemoveVisualCache_Impl( m_xObjectStream );
+ }
+
+ SetVisReplInStream( m_bStoreVisRepl );
+ }
+
+ if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
+ {
+ // the object replacement image should be updated, so the cached size as well
+ m_bHasCachedSize = false;
+ try
+ {
+ // the call will cache the size in case of success
+ // probably it might need to be done earlier, while the object is in active state
+ getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+
+ aGuard.clear();
+
+ MakeEventListenerNotification_Impl( "OnSaveDone");
+
+ // the object can be changed only on Windows
+ // the notification should be done only if the object is not in loaded state
+ if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
+ MakeEventListenerNotification_Impl( "OnVisAreaChanged");
+}
+
+
+sal_Bool SAL_CALL OleEmbeddedObject::isReadonly()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->isReadonly();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "The object persistence is not initialized!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ return m_bReadOnly;
+}
+
+
+void SAL_CALL OleEmbeddedObject::reload(
+ const uno::Sequence< beans::PropertyValue >& lArguments,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->reload( lArguments, lObjArgs );
+ return;
+ }
+ // end wrapping related part ====================
+
+ // TODO: use lObjArgs
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "The object persistence is not initialized!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ // TODO:
+ // throw away current document
+ // load new document from current storage
+ // use meaningful part of lArguments
+}
+
+
+void SAL_CALL OleEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->breakLink( xStorage, sEntName );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ // TODO: The object must be at least in Running state;
+ if ( !m_bIsLink || m_nObjectState == -1 || !m_pOleComponent )
+ {
+ // it must be a linked initialized object
+ throw embed::WrongStateException(
+ "The object is not a valid linked object!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bReadOnly )
+ throw io::IOException(); // TODO: Access denied
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+
+#ifdef _WIN32
+ // TODO: create an object based on the link
+
+ // disconnect the old temporary URL
+ OUString aOldTempURL = m_aTempURL;
+ m_aTempURL.clear();
+
+ rtl::Reference<OleComponent> pNewOleComponent = new OleComponent(m_xContext, this);
+ try {
+ pNewOleComponent->InitEmbeddedCopyOfLink(m_pOleComponent);
+ }
+ catch (const uno::Exception&)
+ {
+ if (!m_aTempURL.isEmpty())
+ KillFile_Impl(m_aTempURL, m_xContext);
+ m_aTempURL = aOldTempURL;
+ throw;
+ }
+
+ try {
+ GetRidOfComponent();
+ }
+ catch (const uno::Exception&)
+ {
+ if (!m_aTempURL.isEmpty())
+ KillFile_Impl(m_aTempURL, m_xContext);
+ m_aTempURL = aOldTempURL;
+ throw;
+ }
+
+ KillFile_Impl(aOldTempURL, m_xContext);
+
+ CreateOleComponent_Impl(pNewOleComponent);
+
+ if (m_xParentStorage != xStorage || !m_aEntryName.equals(sEntName))
+ SwitchOwnPersistence(xStorage, sEntName);
+
+ if (m_nObjectState != embed::EmbedStates::LOADED)
+ {
+ // TODO: should we activate the new object if the link was activated?
+
+ const sal_Int32 nTargetState = m_nObjectState;
+ m_nObjectState = embed::EmbedStates::LOADED;
+
+ if (nTargetState == embed::EmbedStates::RUNNING)
+ m_pOleComponent->RunObject(); // the object already was in running state, the server must be installed
+ else // nTargetState == embed::EmbedStates::ACTIVE
+ {
+ m_pOleComponent->RunObject(); // the object already was in running state, the server must be installed
+ m_pOleComponent->ExecuteVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN);
+ }
+
+ m_nObjectState = nTargetState;
+ }
+
+ m_bIsLink = false;
+ m_aLinkURL.clear();
+#else // ! _WIN32
+ throw io::IOException(); //TODO:
+#endif // _WIN32
+}
+
+
+sal_Bool SAL_CALL OleEmbeddedObject::isLink()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->isLink();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ return m_bIsLink;
+}
+
+
+OUString SAL_CALL OleEmbeddedObject::getLinkURL()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getLinkURL();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( !m_bIsLink )
+ throw embed::WrongStateException(
+ "The object is not a link object!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ // TODO: probably the link URL can be retrieved from OLE
+
+ return m_aLinkURL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */