blob: e7e7a23666a8214859ad731980311e2d3dafd578 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#if defined(_MSC_VER) && (_MSC_VER > 1310)
#pragma warning(disable : 4917 4555)
#endif
#include "embeddoc.hxx"
#include <com/sun/star/uno/Any.h>
#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/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/frame/XComponentLoader.hpp>
#include <com/sun/star/util/XUrlTransformer.hpp>
#include <osl/mutex.hxx>
#include <osl/diagnose.h>
#include <string.h>
#define EXT_STREAM_LENGTH 16
using namespace ::com::sun::star;
extern ::rtl::OUString getStorageTypeFromGUID_Impl( GUID* guid );
extern ::rtl::OUString getServiceNameFromGUID_Impl( GUID* );
extern ::rtl::OUString getFilterNameFromGUID_Impl( GUID* );
// extern CLIPFORMAT getClipFormatFromGUID_Impl( GUID* );
::rtl::OUString getTestFileURLFromGUID_Impl( GUID* guid );
const ::rtl::OUString aOfficeEmbedStreamName( RTL_CONSTASCII_USTRINGPARAM ( "package_stream" ) );
const ::rtl::OUString aExtentStreamName( RTL_CONSTASCII_USTRINGPARAM ( "properties_stream" ) );
uno::Reference< io::XInputStream > createTempXInStreamFromIStream(
uno::Reference< lang::XMultiServiceFactory > xFactory,
IStream *pStream )
{
uno::Reference< io::XInputStream > xResult;
if ( !pStream )
return xResult;
const ::rtl::OUString aServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
uno::Reference < io::XOutputStream > xTempOut = uno::Reference < io::XOutputStream > (
xFactory->createInstance ( aServiceName ),
uno::UNO_QUERY );
if ( xTempOut.is() )
{
ULARGE_INTEGER nNewPos;
LARGE_INTEGER aZero = { 0L, 0L };
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 = (sal_uInt32)aStat.cbSize.QuadPart;
sal_uInt32 nCopied = 0;
uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize );
try
{
sal_uInt32 nRead = 0;
do
{
pStream->Read( (void*)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 = uno::Reference< io::XInputStream >( xTempOut, uno::UNO_QUERY );
}
}
}
catch( uno::Exception& )
{
}
}
return xResult;
}
HRESULT copyXTempOutToIStream( uno::Reference< io::XOutputStream > 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 aZero = { 0L, 0L };
HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
if ( FAILED( hr ) ) return E_FAIL;
ULARGE_INTEGER aUZero = { 0L, 0L };
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( uno::Exception& )
{
return E_FAIL;
}
sal_uInt32 nWritten = 0;
HRESULT hr = pStream->Write( (void*)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( 0L )
, m_xFactory( xFactory )
, m_guid( *guid )
, m_bIsDirty( sal_False )
, m_nAdviseNum( 0 )
, m_bIsInVerbHandling( sal_False )
//, m_bLoadedFromFile( sal_False )
{
m_xOwnAccess = new EmbeddedDocumentInstanceAccess_Impl( this );
m_pDocHolder = new DocumentHolder( xFactory, m_xOwnAccess );
m_pDocHolder->acquire();
}
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( sal_True );
}
else
{
m_pDocHolder->CloseDocument();
m_pDocHolder->CloseFrame();
}
m_pDocHolder->release();
}
uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForLoading_Impl( uno::Reference< io::XInputStream > xStream, DWORD /*nStreamMode*/, LPCOLESTR pFilePath )
{
uno::Sequence< beans::PropertyValue > aArgs( 3 );
sal_Int32 nInd = 0; // must not be bigger than the preset size
aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "FilterName" ) );
aArgs[nInd++].Value <<= getFilterNameFromGUID_Impl( &m_guid );
if ( xStream.is() )
{
aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "InputStream" ) );
aArgs[nInd++].Value <<= xStream;
aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "URL" ) );
aArgs[nInd++].Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "private:stream" ) );
}
else
{
aArgs[nInd].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "URL" ) );
rtl::OUString sDocUrl;
if ( pFilePath )
{
::rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.util.URLTransformer" ) );
uno::Reference< util::XURLTransformer > aTransformer( m_xFactory->createInstance( aServiceName ),
uno::UNO_QUERY );
if ( aTransformer.is() )
{
util::URL aURL;
aURL.Complete = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pFilePath) );
if ( aTransformer->parseSmart( aURL, ::rtl::OUString() ) )
sDocUrl = aURL.Complete;
}
}
aArgs[nInd++].Value <<= sDocUrl;
}
aArgs.realloc( nInd );
// aArgs[].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "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 > xStream)
{
uno::Sequence< beans::PropertyValue > aArgs( xStream.is() ? 2 : 1 );
aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "FilterName" ) );
aArgs[0].Value <<= getFilterNameFromGUID_Impl( &m_guid );
if ( xStream.is() )
{
aArgs[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "OutputStream" ) );
aArgs[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, sal_False );
pStg->Commit( STGC_ONLYIFCURRENT );
m_pOwnStream = pOrigOwn;
m_pExtStream = pOrigExt;
return hr;
}
//-------------------------------------------------------------------------------
// IUnknown
STDMETHODIMP EmbedDocument_Impl::QueryInterface( REFIID riid, void FAR* FAR* ppv )
{
if(IsEqualIID(riid, IID_IUnknown))
{
AddRef();
*ppv = (IUnknown*) (IPersistStorage*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IPersist))
{
AddRef();
*ppv = (IPersist*) (IPersistStorage*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IExternalConnection))
{
AddRef();
*ppv = (IExternalConnection*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IPersistStorage))
{
AddRef();
*ppv = (IPersistStorage*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IDataObject))
{
AddRef();
*ppv = (IDataObject*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IOleObject))
{
AddRef();
*ppv = (IOleObject*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IOleWindow))
{
AddRef();
*ppv = (IOleWindow*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IOleInPlaceObject))
{
AddRef();
*ppv = (IOleInPlaceObject*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IPersistFile))
{
AddRef();
*ppv = (IPersistFile*) this;
return S_OK;
}
else if (IsEqualIID(riid, IID_IDispatch))
{
AddRef();
*ppv = (IDispatch*) this;
return S_OK;
}
*ppv = NULL;
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) EmbedDocument_Impl::AddRef()
{
return osl_incrementInterlockedCount( &m_refCount);
}
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_decrementInterlockedCount( &m_refCount );
if ( nCount == 0 )
delete this;
return nCount;
}
//-------------------------------------------------------------------------------
// IPersist
STDMETHODIMP EmbedDocument_Impl::GetClassID( CLSID* pClassId )
{
*pClassId = *&m_guid;
return S_OK;
}
//-------------------------------------------------------------------------------
// IPersistStorage
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;
}
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( 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( uno::Exception& )
{
}
}
if ( hr == S_OK )
{
::rtl::OUString aCurType = getStorageTypeFromGUID_Impl( &m_guid ); // ???
CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" );
hr = WriteFmtUserTypeStg( pStg,
cf, // ???
reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) );
if ( hr == S_OK )
{
hr = pStg->CreateStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()),
STGM_CREATE | ( nStreamMode & 0x73 ),
0,
0,
&m_pOwnStream );
if ( hr == S_OK && m_pOwnStream )
{
hr = pStg->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()),
STGM_CREATE | ( nStreamMode & 0x73 ),
0,
0,
&m_pExtStream );
if ( hr == S_OK && m_pExtStream )
{
m_pMasterStorage = pStg;
m_bIsDirty = sal_True;
}
else
hr = E_FAIL;
}
else
hr = E_FAIL;
}
else
hr = E_FAIL;
}
if ( hr != S_OK )
m_pDocHolder->CloseDocument();
}
}
}
return hr;
}
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( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()),
0,
nStreamMode & 0x73,
0,
&m_pOwnStream );
if ( !m_pOwnStream ) hr = E_FAIL;
if ( SUCCEEDED( hr ) )
{
hr = pStg->OpenStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()),
0,
nStreamMode & 0x73,
0,
&m_pExtStream );
if ( !m_pExtStream ) hr = E_FAIL;
}
// RECTL aRectToSet;
SIZEL aSizeToSet;
if ( SUCCEEDED( hr ) )
{
ULARGE_INTEGER nNewPos;
LARGE_INTEGER aZero = { 0L, 0L };
hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
if ( SUCCEEDED( hr ) )
{
sal_uInt32 nRead;
sal_Int8 aInf[EXT_STREAM_LENGTH];
hr = m_pExtStream->Read( (void*)aInf, EXT_STREAM_LENGTH, &nRead );
if ( nRead != EXT_STREAM_LENGTH ) 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 = *((sal_Int32*)&aInf[8]) - *((sal_Int32*)aInf);
aSizeToSet.cy = *((sal_Int32*)&aInf[12]) - *((sal_Int32*)&aInf[4]);
}
}
}
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( 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( uno::Exception& )
{
}
}
if ( FAILED( hr ) )
m_pDocHolder->CloseDocument();
}
}
}
if ( FAILED( hr ) )
{
m_pOwnStream = CComPtr< IStream >();
m_pExtStream = CComPtr< IStream >();
hr = pStg->DestroyElement( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()) );
hr = pStg->DestroyElement( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()) );
OSL_ENSURE( SUCCEEDED( hr ), "Can not destroy created stream!\n" );
if ( FAILED( hr ) )
hr = E_FAIL;
}
return hr;
}
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!??\n" );
HRESULT hr = m_pMasterStorage->CopyTo( NULL, NULL, NULL, 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( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()),
STGM_CREATE | ( nStreamMode & 0x73 ),
0,
0,
&pTargetStream );
if ( FAILED( hr ) || !pTargetStream ) return E_FAIL;
hr = pStgSave->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()),
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;
const ::rtl::OUString aServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
uno::Reference < io::XOutputStream > xTempOut = uno::Reference < io::XOutputStream > (
m_xFactory->createInstance ( aServiceName ),
uno::UNO_QUERY );
if ( xTempOut.is() )
{
uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
if( xStorable.is() )
{
try
{
xStorable->storeToURL( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "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 aZero = { 0L, 0L };
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_Int8 aInf[EXT_STREAM_LENGTH];
*((sal_Int32*)aInf) = 0;
*((sal_Int32*)&aInf[4]) = 0;
*((sal_Int32*)&aInf[8]) = aSize.cx;
*((sal_Int32*)&aInf[12]) = aSize.cy;
hr = pNewExtStream->Write( (void*)aInf, EXT_STREAM_LENGTH, &nWritten );
if ( nWritten != EXT_STREAM_LENGTH ) 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( sal_False );
m_bIsDirty = sal_False;
}
}
}
}
}
}
catch( uno::Exception& )
{
}
}
}
return hr;
}
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( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()),
0,
nStreamMode & 0x73,
0,
&m_pOwnStream );
if ( FAILED( hr ) || !m_pOwnStream ) return E_OUTOFMEMORY;
hr = m_pMasterStorage->OpenStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()),
0,
nStreamMode & 0x73,
0,
&m_pExtStream );
if ( FAILED( hr ) || !m_pExtStream ) return E_OUTOFMEMORY;
sal_Bool bModified = sal_False;
uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
if ( xMod.is() )
bModified = xMod->isModified();
for ( AdviseSinkHashMapIterator iAdvise = m_aAdviseHashMap.begin(); iAdvise != m_aAdviseHashMap.end(); iAdvise++ )
{
if ( iAdvise->second )
iAdvise->second->OnSave();
}
if ( xMod.is() )
bModified = xMod->isModified();
return S_OK;
}
STDMETHODIMP EmbedDocument_Impl::HandsOffStorage()
{
m_pMasterStorage = CComPtr< IStorage >();
m_pOwnStream = CComPtr< IStream >();
m_pExtStream = CComPtr< IStream >();
return S_OK;
}
//-------------------------------------------------------------------------------
// IPersistFile
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( NULL,
nStreamMode ,
0,
&m_pMasterStorage );
if ( FAILED( hr ) || !m_pMasterStorage ) return E_FAIL;
::rtl::OUString aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ???
CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" );
hr = WriteFmtUserTypeStg( m_pMasterStorage,
cf, // ???
reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) );
if ( FAILED( hr ) ) return E_FAIL;
hr = m_pMasterStorage->SetClass( m_guid );
if ( FAILED( hr ) ) return E_FAIL;
hr = m_pMasterStorage->CreateStream( reinterpret_cast<LPCWSTR>(aOfficeEmbedStreamName.getStr()),
STGM_CREATE | ( nStreamMode & 0x73 ),
0,
0,
&m_pOwnStream );
if ( FAILED( hr ) || !m_pOwnStream ) return E_FAIL;
hr = m_pMasterStorage->CreateStream( reinterpret_cast<LPCWSTR>(aExtentStreamName.getStr()),
STGM_CREATE | ( nStreamMode & 0x73 ),
0,
0,
&m_pExtStream );
if ( FAILED( hr ) || !m_pExtStream ) return E_FAIL;
uno::Reference< frame::XModel > aDocument(
m_xFactory->createInstance( getServiceNameFromGUID_Impl( &m_guid ) ),
uno::UNO_QUERY );
if ( aDocument.is() )
{
m_pDocHolder->SetDocument( aDocument, sal_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 = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pszFileName) );
}
catch( uno::Exception& )
{
}
}
if ( hr == S_OK )
{
::rtl::OUString aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ???
CLIPFORMAT cf = (CLIPFORMAT)RegisterClipboardFormatA( "Embedded Object" );
hr = WriteFmtUserTypeStg( m_pMasterStorage,
cf, // ???
reinterpret_cast<LPWSTR>(( sal_Unicode* )aCurType.getStr()) );
if ( SUCCEEDED( hr ) )
{
// no need to truncate the stream, the size of the stream is always the same
ULARGE_INTEGER nNewPos;
LARGE_INTEGER aZero = { 0L, 0L };
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_Int8 aInf[EXT_STREAM_LENGTH];
*((sal_Int32*)aInf) = 0;
*((sal_Int32*)&aInf[4]) = 0;
*((sal_Int32*)&aInf[8]) = aSize.cx;
*((sal_Int32*)&aInf[12]) = aSize.cy;
hr = m_pExtStream->Write( (void*)aInf, EXT_STREAM_LENGTH, &nWritten );
if ( nWritten != EXT_STREAM_LENGTH ) hr = E_FAIL;
}
}
}
if ( SUCCEEDED( hr ) )
m_bIsDirty = sal_True;
else
hr = E_FAIL;
}
if ( FAILED( hr ) )
{
m_pDocHolder->CloseDocument();
m_pOwnStream = NULL;
m_pExtStream = NULL;
m_pMasterStorage = NULL;
}
}
return hr;
}
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 = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>( pszFileName ) );
::rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.util.URLTransformer" ) );
uno::Reference< util::XURLTransformer > aTransformer( m_xFactory->createInstance( aServiceName ),
uno::UNO_QUERY_THROW );
if ( aTransformer->parseSmart( aURL, ::rtl::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( uno::Exception& )
{
}
return hr;
}
STDMETHODIMP EmbedDocument_Impl::SaveCompleted( LPCOLESTR pszFileName )
{
// the different file name would mean error here
m_aFileName = ::rtl::OUString( reinterpret_cast<const sal_Unicode*>(pszFileName) );
return S_OK;
}
STDMETHODIMP EmbedDocument_Impl::GetCurFile( LPOLESTR *ppszFileName )
{
CComPtr<IMalloc> pMalloc;
HRESULT hr = CoGetMalloc( 1, &pMalloc );
if ( FAILED( hr ) || !pMalloc ) return E_FAIL;
*ppszFileName = (LPOLESTR)( pMalloc->Alloc( sizeof( sal_Unicode ) * ( m_aFileName.getLength() + 1 ) ) );
wcsncpy( *ppszFileName, reinterpret_cast<LPCWSTR>(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 = NULL;
}
// ===============================================
LockedEmbedDocument_Impl::LockedEmbedDocument_Impl()
: m_pEmbedDocument( NULL )
{}
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();
}
}
// Fix strange warnings about some
// ATL::CAxHostWindow::QueryInterface|AddRef|Releae functions.
// warning C4505: 'xxx' : unreferenced local function has been removed
#if defined(_MSC_VER)
#pragma warning(disable: 4505)
#endif