diff options
Diffstat (limited to 'embedserv/source/embed/ed_ipersiststr.cxx')
-rw-r--r-- | embedserv/source/embed/ed_ipersiststr.cxx | 967 |
1 files changed, 967 insertions, 0 deletions
diff --git a/embedserv/source/embed/ed_ipersiststr.cxx b/embedserv/source/embed/ed_ipersiststr.cxx new file mode 100644 index 000000000..698bbe13f --- /dev/null +++ b/embedserv/source/embed/ed_ipersiststr.cxx @@ -0,0 +1,967 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <embeddoc.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/io/TempFile.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XLoadable.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <comphelper/processfactory.hxx> +#include <o3tl/char16_t2wchar_t.hxx> +#include <osl/mutex.hxx> +#include <osl/diagnose.h> +#include <sal/types.h> + +#include "guid.hxx" + +#include <string.h> + +#define EXT_STREAM_LENGTH 4 + +namespace { + +const sal_Int32 nConstBufferSize = 32000; + +} + +using namespace ::com::sun::star; + +const wchar_t aOfficeEmbedStreamName[] = L"package_stream"; +const wchar_t aExtentStreamName[] = L"properties_stream"; + +static uno::Reference< io::XInputStream > createTempXInStreamFromIStream( + uno::Reference< lang::XMultiServiceFactory > const & xFactory, + IStream *pStream ) +{ + uno::Reference< io::XInputStream > xResult; + + if ( !pStream ) + return xResult; + + uno::Reference < io::XOutputStream > xTempOut( io::TempFile::create(comphelper::getComponentContext(xFactory)), + uno::UNO_QUERY_THROW ); + ULARGE_INTEGER nNewPos; + LARGE_INTEGER const aZero = { 0, 0 }; + HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); + if ( FAILED( hr ) ) return xResult; + + STATSTG aStat; + hr = pStream->Stat( &aStat, STATFLAG_NONAME ); + if ( FAILED( hr ) ) return xResult; + + sal_uInt32 nSize = static_cast<sal_uInt32>(aStat.cbSize.QuadPart); + sal_uInt32 nCopied = 0; + uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize ); + try + { + sal_uInt32 nRead = 0; + do + { + pStream->Read( aBuffer.getArray(), nConstBufferSize, &nRead ); + + if ( nRead < nConstBufferSize ) + aBuffer.realloc( nRead ); + + xTempOut->writeBytes( aBuffer ); + nCopied += nRead; + } while( nRead == nConstBufferSize ); + + if ( nCopied == nSize ) + { + uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY ); + if ( xTempSeek.is() ) + { + xTempSeek->seek ( 0 ); + xResult.set( xTempOut, uno::UNO_QUERY ); + } + } + } + catch( const uno::Exception& ) + { + } + + return xResult; +} + +static HRESULT copyXTempOutToIStream( uno::Reference< io::XOutputStream > const & xTempOut, IStream* pStream ) +{ + if ( !xTempOut.is() || !pStream ) + return E_FAIL; + + uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY ); + if ( !xTempSeek.is() ) + return E_FAIL; + + xTempSeek->seek ( 0 ); + + uno::Reference< io::XInputStream > xTempIn ( xTempOut, uno::UNO_QUERY ); + if ( !xTempSeek.is() ) + return E_FAIL; + + // Seek to zero and truncate the stream + ULARGE_INTEGER nNewPos; + LARGE_INTEGER const aZero = { 0, 0 }; + HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); + if ( FAILED( hr ) ) return E_FAIL; + ULARGE_INTEGER const aUZero = { 0, 0 }; + hr = pStream->SetSize( aUZero ); + if ( FAILED( hr ) ) return E_FAIL; + + uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize ); + sal_uInt32 nReadBytes = 0; + + do + { + try { + nReadBytes = xTempIn->readBytes( aBuffer, nConstBufferSize ); + } + catch( const uno::Exception& ) + { + return E_FAIL; + } + + sal_uInt32 nWritten = 0; + hr = pStream->Write( aBuffer.getArray(), nReadBytes, &nWritten ); + if ( !SUCCEEDED( hr ) || nWritten != nReadBytes ) + return E_FAIL; + + } while( nReadBytes == nConstBufferSize ); + + return S_OK; +} + + +// EmbedDocument_Impl + + +EmbedDocument_Impl::EmbedDocument_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory, const GUID* guid ) +: m_refCount( 0 ) +, m_xFactory( xFactory ) +, m_guid( *guid ) +, m_bIsDirty( false ) +, m_nAdviseNum( 0 ) +, m_bIsInVerbHandling( false ) +//, m_bLoadedFromFile( sal_False ) +{ + m_xOwnAccess = new EmbeddedDocumentInstanceAccess_Impl( this ); + m_pDocHolder = new DocumentHolder( xFactory, m_xOwnAccess ); +} + +EmbedDocument_Impl::~EmbedDocument_Impl() +{ + m_pDocHolder->FreeOffice(); + + if ( m_pDocHolder->HasFrame() && m_pDocHolder->IsLink() ) + { + // a link with frame should be only disconnected, not closed + m_pDocHolder->DisconnectFrameDocument( true ); + } + else + { + m_pDocHolder->CloseDocument(); + m_pDocHolder->CloseFrame(); + } +} + +uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForLoading_Impl( uno::Reference< io::XInputStream > const & xStream, DWORD /*nStreamMode*/, LPCOLESTR pFilePath ) +{ + uno::Sequence< beans::PropertyValue > aArgs( xStream.is() ? 3 : 2 ); + auto pArgs = aArgs.getArray(); + pArgs[0].Name = "FilterName"; + pArgs[0].Value <<= getFilterNameFromGUID_Impl( &m_guid ); + + if ( xStream.is() ) + { + pArgs[1].Name = "InputStream"; + pArgs[1].Value <<= xStream; + pArgs[2].Name = "URL"; + pArgs[2].Value <<= OUString( "private:stream" ); + } + else + { + pArgs[1].Name = "URL"; + + OUString sDocUrl; + if ( pFilePath ) + { + uno::Reference< util::XURLTransformer > aTransformer( util::URLTransformer::create(comphelper::getComponentContext(m_xFactory)) ); + util::URL aURL; + + aURL.Complete = o3tl::toU(pFilePath); + + if ( aTransformer->parseSmart( aURL, OUString() ) ) + sDocUrl = aURL.Complete; + } + + pArgs[1].Value <<= sDocUrl; + } + + // aArgs[].Name = "ReadOnly"; + // aArgs[].Value <<= sal_False; //( ( nStreamMode & ( STGM_READWRITE | STGM_WRITE ) ) ? sal_True : sal_False ); + + return aArgs; +} + +uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForStoring_Impl( uno::Reference< io::XOutputStream > const & xStream) +{ + uno::Sequence< beans::PropertyValue > aArgs( xStream.is() ? 2 : 1 ); + auto pArgs = aArgs.getArray(); + pArgs[0].Name = "FilterName"; + pArgs[0].Value <<= getFilterNameFromGUID_Impl( &m_guid ); + + if ( xStream.is() ) + { + pArgs[1].Name = "OutputStream"; + pArgs[1].Value <<= xStream; + } + + return aArgs; +} + +HRESULT EmbedDocument_Impl::SaveTo_Impl( IStorage* pStg ) +{ + if ( !pStg || pStg == m_pMasterStorage ) + return E_FAIL; + + // for saveto operation the master storage + // should not enter NoScribble mode + CComPtr< IStream > pOrigOwn = m_pOwnStream; + CComPtr< IStream > pOrigExt = m_pExtStream; + HRESULT hr = Save( pStg, false ); + pStg->Commit( STGC_ONLYIFCURRENT ); + m_pOwnStream = pOrigOwn; + m_pExtStream = pOrigExt; + + return hr; +} + + +// IUnknown + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::QueryInterface(REFIID riid, void** ppv) +{ + if(IsEqualIID(riid, IID_IUnknown)) + { + AddRef(); + *ppv = static_cast<IUnknown*>(static_cast<IPersistStorage*>(this)); + return S_OK; + } + else if (IsEqualIID(riid, IID_IPersist)) + { + AddRef(); + *ppv = static_cast<IPersist*>(static_cast<IPersistStorage*>(this)); + return S_OK; + } + else if (IsEqualIID(riid, IID_IExternalConnection)) + { + AddRef(); + *ppv = static_cast<IExternalConnection*>(this); + return S_OK; + } + else if (IsEqualIID(riid, IID_IPersistStorage)) + { + AddRef(); + *ppv = static_cast<IPersistStorage*>(this); + return S_OK; + } + else if (IsEqualIID(riid, IID_IDataObject)) + { + AddRef(); + *ppv = static_cast<IDataObject*>(this); + return S_OK; + } + else if (IsEqualIID(riid, IID_IOleObject)) + { + AddRef(); + *ppv = static_cast<IOleObject*>(this); + return S_OK; + } + else if (IsEqualIID(riid, IID_IOleWindow)) + { + AddRef(); + *ppv = static_cast<IOleWindow*>(this); + return S_OK; + } + else if (IsEqualIID(riid, IID_IOleInPlaceObject)) + { + AddRef(); + *ppv = static_cast<IOleInPlaceObject*>(this); + return S_OK; + } + else if (IsEqualIID(riid, IID_IPersistFile)) + { + AddRef(); + *ppv = static_cast<IPersistFile*>(this); + return S_OK; + } + else if (IsEqualIID(riid, IID_IDispatch)) + { + AddRef(); + *ppv = static_cast<IDispatch*>(this); + return S_OK; + } + + *ppv = nullptr; + return ResultFromScode(E_NOINTERFACE); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl::AddRef() +{ + return osl_atomic_increment( &m_refCount); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl::Release() +{ + // if there is a time when the last reference is destructed, that means that only internal pointers are alive + // after the following call either the refcount is increased or the pointers are empty + if ( m_refCount == 1 ) + m_xOwnAccess->ClearEmbedDocument(); + + sal_Int32 nCount = osl_atomic_decrement( &m_refCount ); + if ( nCount == 0 ) + delete this; + return nCount; +} + + +// IPersist + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::GetClassID( CLSID* pClassId ) +{ + *pClassId = m_guid; + return S_OK; +} + + +// IPersistStorage + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::IsDirty() +{ + // the link modified state is controlled by the document + if ( m_bIsDirty && !m_aFileName.getLength() ) + return S_OK; + + uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); + if ( xMod.is() ) + return xMod->isModified() ? S_OK : S_FALSE; + return S_FALSE; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::InitNew( IStorage *pStg ) +{ + HRESULT hr = CO_E_ALREADYINITIALIZED; + + if ( !m_pDocHolder->GetDocument().is() ) + { + + STATSTG aStat; + hr = pStg->Stat( &aStat, STATFLAG_NONAME ); + if ( FAILED( hr ) ) return E_FAIL; + + DWORD nStreamMode = aStat.grfMode; + + hr = E_FAIL; + if ( m_xFactory.is() && pStg ) + { + uno::Reference< frame::XModel > aDocument( + m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ), + uno::UNO_QUERY ); + if ( aDocument.is() ) + { + m_pDocHolder->SetDocument( aDocument ); + + uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); + if( xLoadable.is() ) + { + try + { + xLoadable->initNew(); + // xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), nStreamMode ) ); + hr = S_OK; + } + catch( const uno::Exception& ) + { + } + } + + if ( hr == S_OK ) + { + wchar_t const * aCurType = getStorageTypeFromGUID_Impl( &m_guid ); // ??? + CLIPFORMAT cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" )); + hr = WriteFmtUserTypeStg( pStg, + cf, // ??? + const_cast<wchar_t *>(aCurType) ); + + if ( hr == S_OK ) + { + hr = pStg->CreateStream( aOfficeEmbedStreamName, + STGM_CREATE | ( nStreamMode & 0x73 ), + 0, + 0, + &m_pOwnStream ); + + if ( hr == S_OK && m_pOwnStream ) + { + hr = pStg->CreateStream( aExtentStreamName, + STGM_CREATE | ( nStreamMode & 0x73 ), + 0, + 0, + &m_pExtStream ); + + if ( hr == S_OK && m_pExtStream ) + { + + m_pMasterStorage = pStg; + m_bIsDirty = true; + } + else + hr = E_FAIL; + } + else + hr = E_FAIL; + } + else + hr = E_FAIL; + } + + if ( hr != S_OK ) + m_pDocHolder->CloseDocument(); + } + } + } + + return hr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Load( IStorage *pStg ) +{ + if ( m_pDocHolder->GetDocument().is() ) + return CO_E_ALREADYINITIALIZED; + + if ( !m_xFactory.is() || !pStg ) + return E_FAIL; + + HRESULT hr = E_FAIL; + + STATSTG aStat; + hr = pStg->Stat( &aStat, STATFLAG_NONAME ); + if ( FAILED( hr ) ) return E_FAIL; + + DWORD nStreamMode = aStat.grfMode; + hr = pStg->OpenStream( aOfficeEmbedStreamName, + nullptr, + nStreamMode & 0x73, + 0, + &m_pOwnStream ); + if ( !m_pOwnStream ) hr = E_FAIL; + + if ( SUCCEEDED( hr ) ) + { + hr = pStg->OpenStream( aExtentStreamName, + nullptr, + nStreamMode & 0x73, + 0, + &m_pExtStream ); + if ( !m_pExtStream ) hr = E_FAIL; + } + + // RECTL aRectToSet; + SIZEL aSizeToSet; + if ( SUCCEEDED( hr ) ) + { + ULARGE_INTEGER nNewPos; + LARGE_INTEGER const aZero = { 0, 0 }; + hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); + if ( SUCCEEDED( hr ) ) + { + sal_uInt32 nRead; + sal_Int32 aInf[EXT_STREAM_LENGTH]; + hr = m_pExtStream->Read( aInf, sizeof aInf, &nRead ); + if ( nRead != sizeof aInf ) hr = E_FAIL; + + if ( SUCCEEDED( hr ) ) + { + // aRectToSet.left = *((sal_Int32*)aInf); + // aRectToSet.top = *((sal_Int32*)&aInf[4]); + // aRectToSet.right = *((sal_Int32*)&aInf[8]); + // aRectToSet.bottom = *((sal_Int32*)&aInf[12]); + aSizeToSet.cx = aInf[2] - aInf[0]; + aSizeToSet.cy = aInf[3] - aInf[1]; + } + } + } + + if ( SUCCEEDED( hr ) ) + { + hr = E_FAIL; + + uno::Reference < io::XInputStream > xTempIn = createTempXInStreamFromIStream( m_xFactory, m_pOwnStream ); + if ( xTempIn.is() ) + { + uno::Reference< frame::XModel > aDocument( + m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ), + uno::UNO_QUERY ); + if ( aDocument.is() ) + { + m_pDocHolder->SetDocument( aDocument ); + + uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); + if( xLoadable.is() ) + { + try + { + xLoadable->load( fillArgsForLoading_Impl( xTempIn, nStreamMode ) ); + m_pMasterStorage = pStg; + hr = m_pDocHolder->SetExtent( &aSizeToSet ); + // hr = m_pDocHolder->SetVisArea( &aRectToSet ); + } + catch( const uno::Exception& ) + { + } + } + + if ( FAILED( hr ) ) + m_pDocHolder->CloseDocument(); + } + } + } + + if ( FAILED( hr ) ) + { + m_pOwnStream = CComPtr< IStream >(); + m_pExtStream = CComPtr< IStream >(); + hr = pStg->DestroyElement( aOfficeEmbedStreamName ); + hr = pStg->DestroyElement( aExtentStreamName ); + + OSL_ENSURE( SUCCEEDED( hr ), "Can not destroy created stream!" ); + if ( FAILED( hr ) ) + hr = E_FAIL; + } + + return hr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Save( IStorage *pStgSave, BOOL fSameAsLoad ) +{ + if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() || !pStgSave || !m_pOwnStream || !m_pExtStream ) + return E_FAIL; + + CComPtr< IStream > pTargetStream; + CComPtr< IStream > pNewExtStream; + + if ( !fSameAsLoad && pStgSave != m_pMasterStorage ) + { + OSL_ENSURE( m_pMasterStorage, "How could the document be initialized without storage!??" ); + HRESULT hr = m_pMasterStorage->CopyTo( 0, nullptr, nullptr, pStgSave ); + if ( FAILED( hr ) ) return E_FAIL; + + STATSTG aStat; + hr = pStgSave->Stat( &aStat, STATFLAG_NONAME ); + if ( FAILED( hr ) ) return E_FAIL; + + DWORD nStreamMode = aStat.grfMode; + hr = pStgSave->CreateStream( aOfficeEmbedStreamName, + STGM_CREATE | ( nStreamMode & 0x73 ), + 0, + 0, + &pTargetStream ); + if ( FAILED( hr ) || !pTargetStream ) return E_FAIL; + + hr = pStgSave->CreateStream( aExtentStreamName, + STGM_CREATE | ( nStreamMode & 0x73 ), + 0, + 0, + &pNewExtStream ); + if ( FAILED( hr ) || !pNewExtStream ) return E_FAIL; + } + else + { + pTargetStream = m_pOwnStream; + pNewExtStream = m_pExtStream; + } + + HRESULT hr = E_FAIL; + + uno::Reference < io::XOutputStream > xTempOut( io::TempFile::create(comphelper::getComponentContext(m_xFactory)), + uno::UNO_QUERY_THROW ); + + uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); + if( xStorable.is() ) + { + try + { + xStorable->storeToURL( "private:stream", + fillArgsForStoring_Impl( xTempOut ) ); + hr = copyXTempOutToIStream( xTempOut, pTargetStream ); + if ( SUCCEEDED( hr ) ) + { + // no need to truncate the stream, the size of the stream is always the same + ULARGE_INTEGER nNewPos; + LARGE_INTEGER const aZero = { 0, 0 }; + hr = pNewExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); + if ( SUCCEEDED( hr ) ) + { + SIZEL aSize; + hr = m_pDocHolder->GetExtent( &aSize ); + + if ( SUCCEEDED( hr ) ) + { + sal_uInt32 nWritten; + sal_Int32 aInf[EXT_STREAM_LENGTH] = {0, 0, aSize.cx, aSize.cy}; + + hr = pNewExtStream->Write( aInf, sizeof aInf, &nWritten ); + if ( nWritten != sizeof aInf ) hr = E_FAIL; + + if ( SUCCEEDED( hr ) ) + { + m_pOwnStream = CComPtr< IStream >(); + m_pExtStream = CComPtr< IStream >(); + if ( fSameAsLoad || pStgSave == m_pMasterStorage ) + { + uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); + if ( xMod.is() ) + xMod->setModified( false ); + m_bIsDirty = false; + } + } + } + } + } + } + catch( const uno::Exception& ) + { + } + } + + return hr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::SaveCompleted( IStorage *pStgNew ) +{ + // m_pOwnStream == NULL && m_pMasterStorage != NULL means the object is in NoScribble mode + // m_pOwnStream == NULL && m_pMasterStorage == NULL means the object is in HandsOff mode + + if ( m_pOwnStream || m_pExtStream ) + return E_UNEXPECTED; + + if ( !m_pMasterStorage && !pStgNew ) + return E_INVALIDARG; + + if ( pStgNew ) + m_pMasterStorage = pStgNew; + + STATSTG aStat; + HRESULT hr = m_pMasterStorage->Stat( &aStat, STATFLAG_NONAME ); + if ( FAILED( hr ) ) return E_OUTOFMEMORY; + + DWORD nStreamMode = aStat.grfMode; + hr = m_pMasterStorage->OpenStream( aOfficeEmbedStreamName, + nullptr, + nStreamMode & 0x73, + 0, + &m_pOwnStream ); + if ( FAILED( hr ) || !m_pOwnStream ) return E_OUTOFMEMORY; + + hr = m_pMasterStorage->OpenStream( aExtentStreamName, + nullptr, + nStreamMode & 0x73, + 0, + &m_pExtStream ); + if ( FAILED( hr ) || !m_pExtStream ) return E_OUTOFMEMORY; + + for (auto const& advise : m_aAdviseHashMap) + { + if ( advise.second ) + advise.second->OnSave(); + } + + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::HandsOffStorage() +{ + m_pMasterStorage = CComPtr< IStorage >(); + m_pOwnStream = CComPtr< IStream >(); + m_pExtStream = CComPtr< IStream >(); + + return S_OK; +} + + +// IPersistFile + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Load( LPCOLESTR pszFileName, DWORD /*dwMode*/ ) +{ + if ( m_pDocHolder->GetDocument().is() ) + return CO_E_ALREADYINITIALIZED; + + if ( !m_xFactory.is() ) + return E_FAIL; + + DWORD nStreamMode = STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE | STGM_SHARE_EXCLUSIVE; + HRESULT hr = StgCreateDocfile( nullptr, + nStreamMode , + 0, + &m_pMasterStorage ); + + if ( FAILED( hr ) || !m_pMasterStorage ) return E_FAIL; + + std::u16string_view aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ??? + CLIPFORMAT cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" )); + hr = WriteFmtUserTypeStg( m_pMasterStorage, + cf, // ??? + const_cast<LPOLESTR>( o3tl::toW(aCurType.data())) ); + if ( FAILED( hr ) ) return E_FAIL; + + hr = m_pMasterStorage->SetClass( m_guid ); + if ( FAILED( hr ) ) return E_FAIL; + + hr = m_pMasterStorage->CreateStream( aOfficeEmbedStreamName, + STGM_CREATE | ( nStreamMode & 0x73 ), + 0, + 0, + &m_pOwnStream ); + if ( FAILED( hr ) || !m_pOwnStream ) return E_FAIL; + + hr = m_pMasterStorage->CreateStream( aExtentStreamName, + STGM_CREATE | ( nStreamMode & 0x73 ), + 0, + 0, + &m_pExtStream ); + if ( FAILED( hr ) || !m_pExtStream ) return E_FAIL; + + + uno::Reference< frame::XModel > aDocument( + m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ), + uno::UNO_QUERY ); + if ( aDocument.is() ) + { + m_pDocHolder->SetDocument( aDocument, true ); + + uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY ); + if( xLoadable.is() ) + { + try + { + xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), + STGM_READWRITE, + pszFileName ) ); + hr = S_OK; + + m_aFileName = o3tl::toU(pszFileName); + } + catch( const uno::Exception& ) + { + } + } + + if ( hr == S_OK ) + { + aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ??? + cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" )); + hr = WriteFmtUserTypeStg( m_pMasterStorage, + cf, // ??? + const_cast<LPOLESTR>( o3tl::toW(aCurType.data())) ); + + if ( SUCCEEDED( hr ) ) + { + // no need to truncate the stream, the size of the stream is always the same + ULARGE_INTEGER nNewPos; + LARGE_INTEGER const aZero = { 0, 0 }; + hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos ); + if ( SUCCEEDED( hr ) ) + { + SIZEL aSize; + hr = m_pDocHolder->GetExtent( &aSize ); + + if ( SUCCEEDED( hr ) ) + { + sal_uInt32 nWritten; + sal_Int32 aInf[EXT_STREAM_LENGTH] = {0, 0, aSize.cx, aSize.cy}; + + hr = m_pExtStream->Write( aInf, sizeof aInf, &nWritten ); + if ( nWritten != sizeof aInf ) hr = E_FAIL; + } + } + } + + if ( SUCCEEDED( hr ) ) + m_bIsDirty = true; + else + hr = E_FAIL; + } + + if ( FAILED( hr ) ) + { + m_pDocHolder->CloseDocument(); + m_pOwnStream = nullptr; + m_pExtStream = nullptr; + m_pMasterStorage = nullptr; + } + } + + return hr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Save( LPCOLESTR pszFileName, BOOL fRemember ) +{ + if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() ) + return E_FAIL; + + HRESULT hr = E_FAIL; + + // TODO/LATER: currently there is no hands off state implemented + try + { + uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY_THROW ); + + if ( !pszFileName ) + xStorable->store(); + else + { + util::URL aURL; + aURL.Complete = o3tl::toU( pszFileName ); + + uno::Reference< util::XURLTransformer > aTransformer( util::URLTransformer::create(comphelper::getComponentContext(m_xFactory)) ); + + if ( aTransformer->parseSmart( aURL, OUString() ) && aURL.Complete.getLength() ) + { + if ( fRemember ) + { + xStorable->storeAsURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) ); + m_aFileName = aURL.Complete; + } + else + xStorable->storeToURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) ); + } + } + + hr = S_OK; + } + catch( const uno::Exception& ) + { + } + + return hr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::SaveCompleted( LPCOLESTR pszFileName ) +{ + // the different file name would mean error here + m_aFileName = o3tl::toU(pszFileName); + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::GetCurFile( LPOLESTR *ppszFileName ) +{ + CComPtr<IMalloc> pMalloc; + + HRESULT hr = CoGetMalloc( 1, &pMalloc ); + if ( FAILED( hr ) || !pMalloc ) return E_FAIL; + + *ppszFileName = static_cast<LPOLESTR>( pMalloc->Alloc( sizeof( sal_Unicode ) * ( m_aFileName.getLength() + 1 ) ) ); + wcsncpy( *ppszFileName, o3tl::toW(m_aFileName.getStr()), m_aFileName.getLength() + 1 ); + + return m_aFileName.getLength() ? S_OK : S_FALSE; +} + + +LockedEmbedDocument_Impl EmbeddedDocumentInstanceAccess_Impl::GetEmbedDocument() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return LockedEmbedDocument_Impl( m_pEmbedDocument ); +} + +void EmbeddedDocumentInstanceAccess_Impl::ClearEmbedDocument() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + m_pEmbedDocument = nullptr; +} + + +LockedEmbedDocument_Impl::LockedEmbedDocument_Impl() +: m_pEmbedDocument( nullptr ) +{} + +LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( EmbedDocument_Impl* pEmbedDocument ) +: m_pEmbedDocument( pEmbedDocument ) +{ + if ( m_pEmbedDocument ) + m_pEmbedDocument->AddRef(); +} + +LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( const LockedEmbedDocument_Impl& aDocLock ) +: m_pEmbedDocument( aDocLock.m_pEmbedDocument ) +{ + if ( m_pEmbedDocument ) + m_pEmbedDocument->AddRef(); +} + +LockedEmbedDocument_Impl& LockedEmbedDocument_Impl::operator=( const LockedEmbedDocument_Impl& aDocLock ) +{ + if ( m_pEmbedDocument ) + m_pEmbedDocument->Release(); + + m_pEmbedDocument = aDocLock.m_pEmbedDocument; + if ( m_pEmbedDocument ) + m_pEmbedDocument->AddRef(); + + return *this; +} + +LockedEmbedDocument_Impl::~LockedEmbedDocument_Impl() +{ + if ( m_pEmbedDocument ) + m_pEmbedDocument->Release(); +} + +void LockedEmbedDocument_Impl::ExecuteMethod( sal_Int16 nId ) +{ + if ( m_pEmbedDocument ) + { + if ( nId == OLESERV_SAVEOBJECT ) + m_pEmbedDocument->SaveObject(); + else if ( nId == OLESERV_CLOSE ) + m_pEmbedDocument->Close( 0 ); + else if ( nId == OLESERV_NOTIFY ) + m_pEmbedDocument->notify(); + else if ( nId == OLESERV_NOTIFYCLOSING ) + m_pEmbedDocument->OLENotifyClosing(); + else if ( nId == OLESERV_SHOWOBJECT ) + m_pEmbedDocument->ShowObject(); + else if ( nId == OLESERV_DEACTIVATE ) + m_pEmbedDocument->Deactivate(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |