Fix GNU C++ version check
[LibreOffice.git] / embedserv / source / embed / ed_ipersiststr.cxx
blobc82a46d5f8454c0b7f37810512260e2335f93c44
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <embeddoc.hxx>
25 #include <com/sun/star/uno/Exception.hpp>
26 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <com/sun/star/lang/XComponent.hpp>
28 #include <com/sun/star/io/TempFile.hpp>
29 #include <com/sun/star/io/XInputStream.hpp>
30 #include <com/sun/star/io/XOutputStream.hpp>
31 #include <com/sun/star/io/XSeekable.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/frame/XLoadable.hpp>
34 #include <com/sun/star/util/XModifiable.hpp>
35 #include <com/sun/star/frame/XStorable.hpp>
36 #include <com/sun/star/util/URLTransformer.hpp>
37 #include <com/sun/star/util/XURLTransformer.hpp>
39 #include <comphelper/processfactory.hxx>
40 #include <o3tl/char16_t2wchar_t.hxx>
41 #include <osl/mutex.hxx>
42 #include <osl/diagnose.h>
43 #include <sal/types.h>
45 #include "guid.hxx"
47 #include <string.h>
49 #define EXT_STREAM_LENGTH 4
51 namespace {
53 const sal_Int32 nConstBufferSize = 32000;
57 using namespace ::com::sun::star;
59 const wchar_t aOfficeEmbedStreamName[] = L"package_stream";
60 const wchar_t aExtentStreamName[] = L"properties_stream";
62 static uno::Reference< io::XInputStream > createTempXInStreamFromIStream(
63 uno::Reference< lang::XMultiServiceFactory > const & xFactory,
64 IStream *pStream )
66 uno::Reference< io::XInputStream > xResult;
68 if ( !pStream )
69 return xResult;
71 uno::Reference < io::XOutputStream > xTempOut( io::TempFile::create(comphelper::getComponentContext(xFactory)),
72 uno::UNO_QUERY_THROW );
73 ULARGE_INTEGER nNewPos;
74 LARGE_INTEGER const aZero = { 0, 0 };
75 HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
76 if ( FAILED( hr ) ) return xResult;
78 STATSTG aStat;
79 hr = pStream->Stat( &aStat, STATFLAG_NONAME );
80 if ( FAILED( hr ) ) return xResult;
82 sal_uInt32 nSize = static_cast<sal_uInt32>(aStat.cbSize.QuadPart);
83 sal_uInt32 nCopied = 0;
84 uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize );
85 try
87 sal_uInt32 nRead = 0;
90 pStream->Read( aBuffer.getArray(), nConstBufferSize, &nRead );
92 if ( nRead < nConstBufferSize )
93 aBuffer.realloc( nRead );
95 xTempOut->writeBytes( aBuffer );
96 nCopied += nRead;
97 } while( nRead == nConstBufferSize );
99 if ( nCopied == nSize )
101 uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY );
102 if ( xTempSeek.is() )
104 xTempSeek->seek ( 0 );
105 xResult.set( xTempOut, uno::UNO_QUERY );
109 catch( const uno::Exception& )
113 return xResult;
116 static HRESULT copyXTempOutToIStream( uno::Reference< io::XOutputStream > const & xTempOut, IStream* pStream )
118 if ( !xTempOut.is() || !pStream )
119 return E_FAIL;
121 uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY );
122 if ( !xTempSeek.is() )
123 return E_FAIL;
125 xTempSeek->seek ( 0 );
127 uno::Reference< io::XInputStream > xTempIn ( xTempOut, uno::UNO_QUERY );
128 if ( !xTempSeek.is() )
129 return E_FAIL;
131 // Seek to zero and truncate the stream
132 ULARGE_INTEGER nNewPos;
133 LARGE_INTEGER const aZero = { 0, 0 };
134 HRESULT hr = pStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
135 if ( FAILED( hr ) ) return E_FAIL;
136 ULARGE_INTEGER const aUZero = { 0, 0 };
137 hr = pStream->SetSize( aUZero );
138 if ( FAILED( hr ) ) return E_FAIL;
140 uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize );
141 sal_uInt32 nReadBytes = 0;
145 try {
146 nReadBytes = xTempIn->readBytes( aBuffer, nConstBufferSize );
148 catch( const uno::Exception& )
150 return E_FAIL;
153 sal_uInt32 nWritten = 0;
154 hr = pStream->Write( aBuffer.getArray(), nReadBytes, &nWritten );
155 if ( !SUCCEEDED( hr ) || nWritten != nReadBytes )
156 return E_FAIL;
158 } while( nReadBytes == nConstBufferSize );
160 return S_OK;
164 // EmbedDocument_Impl
167 EmbedDocument_Impl::EmbedDocument_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory, const GUID* guid )
168 : m_refCount( 0 )
169 , m_xFactory( xFactory )
170 , m_guid( *guid )
171 , m_bIsDirty( false )
172 , m_nAdviseNum( 0 )
173 , m_bIsInVerbHandling( false )
174 //, m_bLoadedFromFile( sal_False )
176 m_xOwnAccess = new EmbeddedDocumentInstanceAccess_Impl( this );
177 m_pDocHolder = new DocumentHolder( xFactory, m_xOwnAccess );
180 EmbedDocument_Impl::~EmbedDocument_Impl()
182 m_pDocHolder->FreeOffice();
184 if ( m_pDocHolder->HasFrame() && m_pDocHolder->IsLink() )
186 // a link with frame should be only disconnected, not closed
187 m_pDocHolder->DisconnectFrameDocument( true );
189 else
191 m_pDocHolder->CloseDocument();
192 m_pDocHolder->CloseFrame();
196 uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForLoading_Impl( uno::Reference< io::XInputStream > const & xStream, DWORD /*nStreamMode*/, LPCOLESTR pFilePath )
198 uno::Sequence< beans::PropertyValue > aArgs( xStream.is() ? 3 : 2 );
199 auto pArgs = aArgs.getArray();
200 pArgs[0].Name = "FilterName";
201 pArgs[0].Value <<= getFilterNameFromGUID_Impl( m_guid );
203 if ( xStream.is() )
205 pArgs[1].Name = "InputStream";
206 pArgs[1].Value <<= xStream;
207 pArgs[2].Name = "URL";
208 pArgs[2].Value <<= OUString( "private:stream" );
210 else
212 pArgs[1].Name = "URL";
214 OUString sDocUrl;
215 if ( pFilePath )
217 uno::Reference< util::XURLTransformer > aTransformer( util::URLTransformer::create(comphelper::getComponentContext(m_xFactory)) );
218 util::URL aURL;
220 aURL.Complete = o3tl::toU(pFilePath);
222 if ( aTransformer->parseSmart( aURL, OUString() ) )
223 sDocUrl = aURL.Complete;
226 pArgs[1].Value <<= sDocUrl;
229 // aArgs[].Name = "ReadOnly";
230 // aArgs[].Value <<= sal_False; //( ( nStreamMode & ( STGM_READWRITE | STGM_WRITE ) ) ? sal_True : sal_False );
232 return aArgs;
235 uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForStoring_Impl( uno::Reference< io::XOutputStream > const & xStream)
237 uno::Sequence< beans::PropertyValue > aArgs( xStream.is() ? 2 : 1 );
238 auto pArgs = aArgs.getArray();
239 pArgs[0].Name = "FilterName";
240 pArgs[0].Value <<= getFilterNameFromGUID_Impl( m_guid );
242 if ( xStream.is() )
244 pArgs[1].Name = "OutputStream";
245 pArgs[1].Value <<= xStream;
248 return aArgs;
251 HRESULT EmbedDocument_Impl::SaveTo_Impl( IStorage* pStg )
253 if ( !pStg || pStg == m_pMasterStorage )
254 return E_FAIL;
256 // for saveto operation the master storage
257 // should not enter NoScribble mode
258 CComPtr< IStream > pOrigOwn = m_pOwnStream;
259 CComPtr< IStream > pOrigExt = m_pExtStream;
260 HRESULT hr = Save( pStg, false );
261 pStg->Commit( STGC_ONLYIFCURRENT );
262 m_pOwnStream = pOrigOwn;
263 m_pExtStream = pOrigExt;
265 return hr;
269 // IUnknown
271 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::QueryInterface(REFIID riid, void** ppv)
273 if(IsEqualIID(riid, IID_IUnknown))
275 AddRef();
276 *ppv = static_cast<IUnknown*>(static_cast<IPersistStorage*>(this));
277 return S_OK;
279 else if (IsEqualIID(riid, IID_IPersist))
281 AddRef();
282 *ppv = static_cast<IPersist*>(static_cast<IPersistStorage*>(this));
283 return S_OK;
285 else if (IsEqualIID(riid, IID_IExternalConnection))
287 AddRef();
288 *ppv = static_cast<IExternalConnection*>(this);
289 return S_OK;
291 else if (IsEqualIID(riid, IID_IPersistStorage))
293 AddRef();
294 *ppv = static_cast<IPersistStorage*>(this);
295 return S_OK;
297 else if (IsEqualIID(riid, IID_IDataObject))
299 AddRef();
300 *ppv = static_cast<IDataObject*>(this);
301 return S_OK;
303 else if (IsEqualIID(riid, IID_IOleObject))
305 AddRef();
306 *ppv = static_cast<IOleObject*>(this);
307 return S_OK;
309 else if (IsEqualIID(riid, IID_IOleWindow))
311 AddRef();
312 *ppv = static_cast<IOleWindow*>(this);
313 return S_OK;
315 else if (IsEqualIID(riid, IID_IOleInPlaceObject))
317 AddRef();
318 *ppv = static_cast<IOleInPlaceObject*>(this);
319 return S_OK;
321 else if (IsEqualIID(riid, IID_IPersistFile))
323 AddRef();
324 *ppv = static_cast<IPersistFile*>(this);
325 return S_OK;
327 else if (IsEqualIID(riid, IID_IDispatch))
329 AddRef();
330 *ppv = static_cast<IDispatch*>(this);
331 return S_OK;
334 *ppv = nullptr;
335 return ResultFromScode(E_NOINTERFACE);
338 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl::AddRef()
340 return osl_atomic_increment( &m_refCount);
343 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl::Release()
345 // if there is a time when the last reference is destructed, that means that only internal pointers are alive
346 // after the following call either the refcount is increased or the pointers are empty
347 if ( m_refCount == 1 )
348 m_xOwnAccess->ClearEmbedDocument();
350 sal_Int32 nCount = osl_atomic_decrement( &m_refCount );
351 if ( nCount == 0 )
352 delete this;
353 return nCount;
357 // IPersist
359 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::GetClassID( CLSID* pClassId )
361 *pClassId = m_guid;
362 return S_OK;
366 // IPersistStorage
368 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::IsDirty()
370 // the link modified state is controlled by the document
371 if ( m_bIsDirty && !m_aFileName.getLength() )
372 return S_OK;
374 uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
375 if ( xMod.is() )
376 return xMod->isModified() ? S_OK : S_FALSE;
377 return S_FALSE;
380 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::InitNew( IStorage *pStg )
382 HRESULT hr = CO_E_ALREADYINITIALIZED;
384 if ( !m_pDocHolder->GetDocument().is() )
387 STATSTG aStat;
388 hr = pStg->Stat( &aStat, STATFLAG_NONAME );
389 if ( FAILED( hr ) ) return E_FAIL;
391 DWORD nStreamMode = aStat.grfMode;
393 hr = E_FAIL;
394 if ( m_xFactory.is() && pStg )
396 uno::Reference< frame::XModel > aDocument(
397 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( m_guid )) ),
398 uno::UNO_QUERY );
399 if ( aDocument.is() )
401 m_pDocHolder->SetDocument( aDocument );
403 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
404 if( xLoadable.is() )
408 xLoadable->initNew();
409 // xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), nStreamMode ) );
410 hr = S_OK;
412 catch( const uno::Exception& )
417 if ( hr == S_OK )
419 wchar_t const * aCurType = getStorageTypeFromGUID_Impl( m_guid ); // ???
420 CLIPFORMAT cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" ));
421 hr = WriteFmtUserTypeStg( pStg,
422 cf, // ???
423 const_cast<wchar_t *>(aCurType) );
425 if ( hr == S_OK )
427 hr = pStg->CreateStream( aOfficeEmbedStreamName,
428 STGM_CREATE | ( nStreamMode & 0x73 ),
431 &m_pOwnStream );
433 if ( hr == S_OK && m_pOwnStream )
435 hr = pStg->CreateStream( aExtentStreamName,
436 STGM_CREATE | ( nStreamMode & 0x73 ),
439 &m_pExtStream );
441 if ( hr == S_OK && m_pExtStream )
444 m_pMasterStorage = pStg;
445 m_bIsDirty = true;
447 else
448 hr = E_FAIL;
450 else
451 hr = E_FAIL;
453 else
454 hr = E_FAIL;
457 if ( hr != S_OK )
458 m_pDocHolder->CloseDocument();
463 return hr;
466 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Load( IStorage *pStg )
468 if ( m_pDocHolder->GetDocument().is() )
469 return CO_E_ALREADYINITIALIZED;
471 if ( !m_xFactory.is() || !pStg )
472 return E_FAIL;
474 HRESULT hr = E_FAIL;
476 STATSTG aStat;
477 hr = pStg->Stat( &aStat, STATFLAG_NONAME );
478 if ( FAILED( hr ) ) return E_FAIL;
480 DWORD nStreamMode = aStat.grfMode;
481 hr = pStg->OpenStream( aOfficeEmbedStreamName,
482 nullptr,
483 nStreamMode & 0x73,
485 &m_pOwnStream );
486 if ( !m_pOwnStream ) hr = E_FAIL;
488 if ( SUCCEEDED( hr ) )
490 hr = pStg->OpenStream( aExtentStreamName,
491 nullptr,
492 nStreamMode & 0x73,
494 &m_pExtStream );
495 if ( !m_pExtStream ) hr = E_FAIL;
498 // RECTL aRectToSet;
499 SIZEL aSizeToSet;
500 if ( SUCCEEDED( hr ) )
502 ULARGE_INTEGER nNewPos;
503 LARGE_INTEGER const aZero = { 0, 0 };
504 hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
505 if ( SUCCEEDED( hr ) )
507 sal_uInt32 nRead;
508 sal_Int32 aInf[EXT_STREAM_LENGTH];
509 hr = m_pExtStream->Read( aInf, sizeof aInf, &nRead );
510 if ( nRead != sizeof aInf ) hr = E_FAIL;
512 if ( SUCCEEDED( hr ) )
514 // aRectToSet.left = *((sal_Int32*)aInf);
515 // aRectToSet.top = *((sal_Int32*)&aInf[4]);
516 // aRectToSet.right = *((sal_Int32*)&aInf[8]);
517 // aRectToSet.bottom = *((sal_Int32*)&aInf[12]);
518 aSizeToSet.cx = aInf[2] - aInf[0];
519 aSizeToSet.cy = aInf[3] - aInf[1];
524 if ( SUCCEEDED( hr ) )
526 hr = E_FAIL;
528 uno::Reference < io::XInputStream > xTempIn = createTempXInStreamFromIStream( m_xFactory, m_pOwnStream );
529 if ( xTempIn.is() )
531 uno::Reference< frame::XModel > aDocument(
532 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( m_guid )) ),
533 uno::UNO_QUERY );
534 if ( aDocument.is() )
536 m_pDocHolder->SetDocument( aDocument );
538 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
539 if( xLoadable.is() )
543 xLoadable->load( fillArgsForLoading_Impl( xTempIn, nStreamMode ) );
544 m_pMasterStorage = pStg;
545 hr = m_pDocHolder->SetExtent( &aSizeToSet );
546 // hr = m_pDocHolder->SetVisArea( &aRectToSet );
548 catch( const uno::Exception& )
553 if ( FAILED( hr ) )
554 m_pDocHolder->CloseDocument();
559 if ( FAILED( hr ) )
561 m_pOwnStream = CComPtr< IStream >();
562 m_pExtStream = CComPtr< IStream >();
563 hr = pStg->DestroyElement( aOfficeEmbedStreamName );
564 hr = pStg->DestroyElement( aExtentStreamName );
566 OSL_ENSURE( SUCCEEDED( hr ), "Can not destroy created stream!" );
567 if ( FAILED( hr ) )
568 hr = E_FAIL;
571 return hr;
574 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Save( IStorage *pStgSave, BOOL fSameAsLoad )
576 if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() || !pStgSave || !m_pOwnStream || !m_pExtStream )
577 return E_FAIL;
579 CComPtr< IStream > pTargetStream;
580 CComPtr< IStream > pNewExtStream;
582 if ( !fSameAsLoad && pStgSave != m_pMasterStorage )
584 OSL_ENSURE( m_pMasterStorage, "How could the document be initialized without storage!??" );
585 HRESULT hr = m_pMasterStorage->CopyTo( 0, nullptr, nullptr, pStgSave );
586 if ( FAILED( hr ) ) return E_FAIL;
588 STATSTG aStat;
589 hr = pStgSave->Stat( &aStat, STATFLAG_NONAME );
590 if ( FAILED( hr ) ) return E_FAIL;
592 DWORD nStreamMode = aStat.grfMode;
593 hr = pStgSave->CreateStream( aOfficeEmbedStreamName,
594 STGM_CREATE | ( nStreamMode & 0x73 ),
597 &pTargetStream );
598 if ( FAILED( hr ) || !pTargetStream ) return E_FAIL;
600 hr = pStgSave->CreateStream( aExtentStreamName,
601 STGM_CREATE | ( nStreamMode & 0x73 ),
604 &pNewExtStream );
605 if ( FAILED( hr ) || !pNewExtStream ) return E_FAIL;
607 else
609 pTargetStream = m_pOwnStream;
610 pNewExtStream = m_pExtStream;
613 HRESULT hr = E_FAIL;
615 uno::Reference < io::XOutputStream > xTempOut( io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
616 uno::UNO_QUERY_THROW );
618 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
619 if( xStorable.is() )
623 xStorable->storeToURL( "private:stream",
624 fillArgsForStoring_Impl( xTempOut ) );
625 hr = copyXTempOutToIStream( xTempOut, pTargetStream );
626 if ( SUCCEEDED( hr ) )
628 // no need to truncate the stream, the size of the stream is always the same
629 ULARGE_INTEGER nNewPos;
630 LARGE_INTEGER const aZero = { 0, 0 };
631 hr = pNewExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
632 if ( SUCCEEDED( hr ) )
634 SIZEL aSize;
635 hr = m_pDocHolder->GetExtent( &aSize );
637 if ( SUCCEEDED( hr ) )
639 sal_uInt32 nWritten;
640 sal_Int32 aInf[EXT_STREAM_LENGTH] = {0, 0, aSize.cx, aSize.cy};
642 hr = pNewExtStream->Write( aInf, sizeof aInf, &nWritten );
643 if ( nWritten != sizeof aInf ) hr = E_FAIL;
645 if ( SUCCEEDED( hr ) )
647 m_pOwnStream = CComPtr< IStream >();
648 m_pExtStream = CComPtr< IStream >();
649 if ( fSameAsLoad || pStgSave == m_pMasterStorage )
651 uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
652 if ( xMod.is() )
653 xMod->setModified( false );
654 m_bIsDirty = false;
661 catch( const uno::Exception& )
666 return hr;
669 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::SaveCompleted( IStorage *pStgNew )
671 // m_pOwnStream == NULL && m_pMasterStorage != NULL means the object is in NoScribble mode
672 // m_pOwnStream == NULL && m_pMasterStorage == NULL means the object is in HandsOff mode
674 if ( m_pOwnStream || m_pExtStream )
675 return E_UNEXPECTED;
677 if ( !m_pMasterStorage && !pStgNew )
678 return E_INVALIDARG;
680 if ( pStgNew )
681 m_pMasterStorage = pStgNew;
683 STATSTG aStat;
684 HRESULT hr = m_pMasterStorage->Stat( &aStat, STATFLAG_NONAME );
685 if ( FAILED( hr ) ) return E_OUTOFMEMORY;
687 DWORD nStreamMode = aStat.grfMode;
688 hr = m_pMasterStorage->OpenStream( aOfficeEmbedStreamName,
689 nullptr,
690 nStreamMode & 0x73,
692 &m_pOwnStream );
693 if ( FAILED( hr ) || !m_pOwnStream ) return E_OUTOFMEMORY;
695 hr = m_pMasterStorage->OpenStream( aExtentStreamName,
696 nullptr,
697 nStreamMode & 0x73,
699 &m_pExtStream );
700 if ( FAILED( hr ) || !m_pExtStream ) return E_OUTOFMEMORY;
702 for (auto const& advise : m_aAdviseHashMap)
704 if ( advise.second )
705 advise.second->OnSave();
708 return S_OK;
711 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::HandsOffStorage()
713 m_pMasterStorage = CComPtr< IStorage >();
714 m_pOwnStream = CComPtr< IStream >();
715 m_pExtStream = CComPtr< IStream >();
717 return S_OK;
721 // IPersistFile
723 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Load( LPCOLESTR pszFileName, DWORD /*dwMode*/ )
725 if ( m_pDocHolder->GetDocument().is() )
726 return CO_E_ALREADYINITIALIZED;
728 if ( !m_xFactory.is() )
729 return E_FAIL;
731 DWORD nStreamMode = STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE | STGM_SHARE_EXCLUSIVE;
732 HRESULT hr = StgCreateDocfile( nullptr,
733 nStreamMode ,
735 &m_pMasterStorage );
737 if ( FAILED( hr ) || !m_pMasterStorage ) return E_FAIL;
739 std::u16string_view aCurType = getServiceNameFromGUID_Impl( m_guid ); // ???
740 CLIPFORMAT cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" ));
741 hr = WriteFmtUserTypeStg( m_pMasterStorage,
742 cf, // ???
743 const_cast<LPOLESTR>( o3tl::toW(aCurType.data())) );
744 if ( FAILED( hr ) ) return E_FAIL;
746 hr = m_pMasterStorage->SetClass( m_guid );
747 if ( FAILED( hr ) ) return E_FAIL;
749 hr = m_pMasterStorage->CreateStream( aOfficeEmbedStreamName,
750 STGM_CREATE | ( nStreamMode & 0x73 ),
753 &m_pOwnStream );
754 if ( FAILED( hr ) || !m_pOwnStream ) return E_FAIL;
756 hr = m_pMasterStorage->CreateStream( aExtentStreamName,
757 STGM_CREATE | ( nStreamMode & 0x73 ),
760 &m_pExtStream );
761 if ( FAILED( hr ) || !m_pExtStream ) return E_FAIL;
764 uno::Reference< frame::XModel > aDocument(
765 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( m_guid )) ),
766 uno::UNO_QUERY );
767 if ( aDocument.is() )
769 m_pDocHolder->SetDocument( aDocument, true );
771 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
772 if( xLoadable.is() )
776 xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(),
777 STGM_READWRITE,
778 pszFileName ) );
779 hr = S_OK;
781 m_aFileName = o3tl::toU(pszFileName);
783 catch( const uno::Exception& )
788 if ( hr == S_OK )
790 aCurType = getServiceNameFromGUID_Impl( m_guid ); // ???
791 cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" ));
792 hr = WriteFmtUserTypeStg( m_pMasterStorage,
793 cf, // ???
794 const_cast<LPOLESTR>( o3tl::toW(aCurType.data())) );
796 if ( SUCCEEDED( hr ) )
798 // no need to truncate the stream, the size of the stream is always the same
799 ULARGE_INTEGER nNewPos;
800 LARGE_INTEGER const aZero = { 0, 0 };
801 hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
802 if ( SUCCEEDED( hr ) )
804 SIZEL aSize;
805 hr = m_pDocHolder->GetExtent( &aSize );
807 if ( SUCCEEDED( hr ) )
809 sal_uInt32 nWritten;
810 sal_Int32 aInf[EXT_STREAM_LENGTH] = {0, 0, aSize.cx, aSize.cy};
812 hr = m_pExtStream->Write( aInf, sizeof aInf, &nWritten );
813 if ( nWritten != sizeof aInf ) hr = E_FAIL;
818 if ( SUCCEEDED( hr ) )
819 m_bIsDirty = true;
820 else
821 hr = E_FAIL;
824 if ( FAILED( hr ) )
826 m_pDocHolder->CloseDocument();
827 m_pOwnStream = nullptr;
828 m_pExtStream = nullptr;
829 m_pMasterStorage = nullptr;
833 return hr;
836 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Save( LPCOLESTR pszFileName, BOOL fRemember )
838 if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() )
839 return E_FAIL;
841 HRESULT hr = E_FAIL;
843 // TODO/LATER: currently there is no hands off state implemented
846 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY_THROW );
848 if ( !pszFileName )
849 xStorable->store();
850 else
852 util::URL aURL;
853 aURL.Complete = o3tl::toU( pszFileName );
855 uno::Reference< util::XURLTransformer > aTransformer( util::URLTransformer::create(comphelper::getComponentContext(m_xFactory)) );
857 if ( aTransformer->parseSmart( aURL, OUString() ) && aURL.Complete.getLength() )
859 if ( fRemember )
861 xStorable->storeAsURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) );
862 m_aFileName = aURL.Complete;
864 else
865 xStorable->storeToURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) );
869 hr = S_OK;
871 catch( const uno::Exception& )
875 return hr;
878 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::SaveCompleted( LPCOLESTR pszFileName )
880 // the different file name would mean error here
881 m_aFileName = o3tl::toU(pszFileName);
882 return S_OK;
885 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::GetCurFile( LPOLESTR *ppszFileName )
887 CComPtr<IMalloc> pMalloc;
889 HRESULT hr = CoGetMalloc( 1, &pMalloc );
890 if ( FAILED( hr ) || !pMalloc ) return E_FAIL;
892 *ppszFileName = static_cast<LPOLESTR>( pMalloc->Alloc( sizeof( sal_Unicode ) * ( m_aFileName.getLength() + 1 ) ) );
893 wcsncpy( *ppszFileName, o3tl::toW(m_aFileName.getStr()), m_aFileName.getLength() + 1 );
895 return m_aFileName.getLength() ? S_OK : S_FALSE;
899 LockedEmbedDocument_Impl EmbeddedDocumentInstanceAccess_Impl::GetEmbedDocument()
901 ::osl::MutexGuard aGuard( m_aMutex );
902 return LockedEmbedDocument_Impl( m_pEmbedDocument );
905 void EmbeddedDocumentInstanceAccess_Impl::ClearEmbedDocument()
907 ::osl::MutexGuard aGuard( m_aMutex );
908 m_pEmbedDocument = nullptr;
912 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl()
913 : m_pEmbedDocument( nullptr )
916 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( EmbedDocument_Impl* pEmbedDocument )
917 : m_pEmbedDocument( pEmbedDocument )
919 if ( m_pEmbedDocument )
920 m_pEmbedDocument->AddRef();
923 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( const LockedEmbedDocument_Impl& aDocLock )
924 : m_pEmbedDocument( aDocLock.m_pEmbedDocument )
926 if ( m_pEmbedDocument )
927 m_pEmbedDocument->AddRef();
930 LockedEmbedDocument_Impl& LockedEmbedDocument_Impl::operator=( const LockedEmbedDocument_Impl& aDocLock )
932 if ( m_pEmbedDocument )
933 m_pEmbedDocument->Release();
935 m_pEmbedDocument = aDocLock.m_pEmbedDocument;
936 if ( m_pEmbedDocument )
937 m_pEmbedDocument->AddRef();
939 return *this;
942 LockedEmbedDocument_Impl::~LockedEmbedDocument_Impl()
944 if ( m_pEmbedDocument )
945 m_pEmbedDocument->Release();
948 void LockedEmbedDocument_Impl::ExecuteMethod( sal_Int16 nId )
950 if ( m_pEmbedDocument )
952 if ( nId == OLESERV_SAVEOBJECT )
953 m_pEmbedDocument->SaveObject();
954 else if ( nId == OLESERV_CLOSE )
955 m_pEmbedDocument->Close( 0 );
956 else if ( nId == OLESERV_NOTIFY )
957 m_pEmbedDocument->notify();
958 else if ( nId == OLESERV_NOTIFYCLOSING )
959 m_pEmbedDocument->OLENotifyClosing();
960 else if ( nId == OLESERV_SHOWOBJECT )
961 m_pEmbedDocument->ShowObject();
962 else if ( nId == OLESERV_DEACTIVATE )
963 m_pEmbedDocument->Deactivate();
967 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */