LibreOffice Module embedserv (master) 1
ed_ipersiststr.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <string_view>
23
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>
38
41#include <osl/mutex.hxx>
42#include <osl/diagnose.h>
43#include <sal/types.h>
44
45#include "guid.hxx"
46
47#include <string.h>
48
49#define EXT_STREAM_LENGTH 4
50
51namespace {
52
53const sal_Int32 nConstBufferSize = 32000;
54
55}
56
57using namespace ::com::sun::star;
58
59const wchar_t aOfficeEmbedStreamName[] = L"package_stream";
60const wchar_t aExtentStreamName[] = L"properties_stream";
61
62static uno::Reference< io::XInputStream > createTempXInStreamFromIStream(
63 uno::Reference< lang::XMultiServiceFactory > const & xFactory,
64 IStream *pStream )
65{
66 uno::Reference< io::XInputStream > xResult;
67
68 if ( !pStream )
69 return xResult;
70
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;
77
78 STATSTG aStat;
79 hr = pStream->Stat( &aStat, STATFLAG_NONAME );
80 if ( FAILED( hr ) ) return xResult;
81
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
86 {
87 sal_uInt32 nRead = 0;
88 do
89 {
90 pStream->Read( aBuffer.getArray(), nConstBufferSize, &nRead );
91
92 if ( nRead < nConstBufferSize )
93 aBuffer.realloc( nRead );
94
95 xTempOut->writeBytes( aBuffer );
96 nCopied += nRead;
97 } while( nRead == nConstBufferSize );
98
99 if ( nCopied == nSize )
100 {
101 uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY );
102 if ( xTempSeek.is() )
103 {
104 xTempSeek->seek ( 0 );
105 xResult.set( xTempOut, uno::UNO_QUERY );
106 }
107 }
108 }
109 catch( const uno::Exception& )
110 {
111 }
112
113 return xResult;
114}
115
116static HRESULT copyXTempOutToIStream( uno::Reference< io::XOutputStream > const & xTempOut, IStream* pStream )
117{
118 if ( !xTempOut.is() || !pStream )
119 return E_FAIL;
120
121 uno::Reference < io::XSeekable > xTempSeek ( xTempOut, uno::UNO_QUERY );
122 if ( !xTempSeek.is() )
123 return E_FAIL;
124
125 xTempSeek->seek ( 0 );
126
127 uno::Reference< io::XInputStream > xTempIn ( xTempOut, uno::UNO_QUERY );
128 if ( !xTempSeek.is() )
129 return E_FAIL;
130
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;
139
140 uno::Sequence< sal_Int8 > aBuffer( nConstBufferSize );
141 sal_uInt32 nReadBytes = 0;
142
143 do
144 {
145 try {
146 nReadBytes = xTempIn->readBytes( aBuffer, nConstBufferSize );
147 }
148 catch( const uno::Exception& )
149 {
150 return E_FAIL;
151 }
152
153 sal_uInt32 nWritten = 0;
154 hr = pStream->Write( aBuffer.getArray(), nReadBytes, &nWritten );
155 if ( !SUCCEEDED( hr ) || nWritten != nReadBytes )
156 return E_FAIL;
157
158 } while( nReadBytes == nConstBufferSize );
159
160 return S_OK;
161}
162
163
164// EmbedDocument_Impl
165
166
167EmbedDocument_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 )
175{
178}
179
181{
182 m_pDocHolder->FreeOffice();
183
184 if ( m_pDocHolder->HasFrame() && m_pDocHolder->IsLink() )
185 {
186 // a link with frame should be only disconnected, not closed
187 m_pDocHolder->DisconnectFrameDocument( true );
188 }
189 else
190 {
191 m_pDocHolder->CloseDocument();
192 m_pDocHolder->CloseFrame();
193 }
194}
195
196uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForLoading_Impl( uno::Reference< io::XInputStream > const & xStream, DWORD /*nStreamMode*/, LPCOLESTR pFilePath )
197{
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 );
202
203 if ( xStream.is() )
204 {
205 pArgs[1].Name = "InputStream";
206 pArgs[1].Value <<= xStream;
207 pArgs[2].Name = "URL";
208 pArgs[2].Value <<= OUString( "private:stream" );
209 }
210 else
211 {
212 pArgs[1].Name = "URL";
213
214 OUString sDocUrl;
215 if ( pFilePath )
216 {
217 uno::Reference< util::XURLTransformer > aTransformer( util::URLTransformer::create(comphelper::getComponentContext(m_xFactory)) );
218 util::URL aURL;
219
220 aURL.Complete = o3tl::toU(pFilePath);
221
222 if ( aTransformer->parseSmart( aURL, OUString() ) )
223 sDocUrl = aURL.Complete;
224 }
225
226 pArgs[1].Value <<= sDocUrl;
227 }
228
229 // aArgs[].Name = "ReadOnly";
230 // aArgs[].Value <<= sal_False; //( ( nStreamMode & ( STGM_READWRITE | STGM_WRITE ) ) ? sal_True : sal_False );
231
232 return aArgs;
233}
234
235uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForStoring_Impl( uno::Reference< io::XOutputStream > const & xStream)
236{
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 );
241
242 if ( xStream.is() )
243 {
244 pArgs[1].Name = "OutputStream";
245 pArgs[1].Value <<= xStream;
246 }
247
248 return aArgs;
249}
250
251HRESULT EmbedDocument_Impl::SaveTo_Impl( IStorage* pStg )
252{
253 if ( !pStg || pStg == m_pMasterStorage )
254 return E_FAIL;
255
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;
264
265 return hr;
266}
267
268
269// IUnknown
270
271COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::QueryInterface(REFIID riid, void** ppv)
272{
273 if(IsEqualIID(riid, IID_IUnknown))
274 {
275 AddRef();
276 *ppv = static_cast<IUnknown*>(static_cast<IPersistStorage*>(this));
277 return S_OK;
278 }
279 else if (IsEqualIID(riid, IID_IPersist))
280 {
281 AddRef();
282 *ppv = static_cast<IPersist*>(static_cast<IPersistStorage*>(this));
283 return S_OK;
284 }
285 else if (IsEqualIID(riid, IID_IExternalConnection))
286 {
287 AddRef();
288 *ppv = static_cast<IExternalConnection*>(this);
289 return S_OK;
290 }
291 else if (IsEqualIID(riid, IID_IPersistStorage))
292 {
293 AddRef();
294 *ppv = static_cast<IPersistStorage*>(this);
295 return S_OK;
296 }
297 else if (IsEqualIID(riid, IID_IDataObject))
298 {
299 AddRef();
300 *ppv = static_cast<IDataObject*>(this);
301 return S_OK;
302 }
303 else if (IsEqualIID(riid, IID_IOleObject))
304 {
305 AddRef();
306 *ppv = static_cast<IOleObject*>(this);
307 return S_OK;
308 }
309 else if (IsEqualIID(riid, IID_IOleWindow))
310 {
311 AddRef();
312 *ppv = static_cast<IOleWindow*>(this);
313 return S_OK;
314 }
315 else if (IsEqualIID(riid, IID_IOleInPlaceObject))
316 {
317 AddRef();
318 *ppv = static_cast<IOleInPlaceObject*>(this);
319 return S_OK;
320 }
321 else if (IsEqualIID(riid, IID_IPersistFile))
322 {
323 AddRef();
324 *ppv = static_cast<IPersistFile*>(this);
325 return S_OK;
326 }
327 else if (IsEqualIID(riid, IID_IDispatch))
328 {
329 AddRef();
330 *ppv = static_cast<IDispatch*>(this);
331 return S_OK;
332 }
333
334 *ppv = nullptr;
335 return ResultFromScode(E_NOINTERFACE);
336}
337
338COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl::AddRef()
339{
340 return osl_atomic_increment( &m_refCount);
341}
342
343COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl::Release()
344{
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();
349
350 sal_Int32 nCount = osl_atomic_decrement( &m_refCount );
351 if ( nCount == 0 )
352 delete this;
353 return nCount;
354}
355
356
357// IPersist
358
359COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::GetClassID( CLSID* pClassId )
360{
361 *pClassId = m_guid;
362 return S_OK;
363}
364
365
366// IPersistStorage
367
368COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::IsDirty()
369{
370 // the link modified state is controlled by the document
371 if ( m_bIsDirty && !m_aFileName.getLength() )
372 return S_OK;
373
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;
378}
379
380COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::InitNew( IStorage *pStg )
381{
382 HRESULT hr = CO_E_ALREADYINITIALIZED;
383
384 if ( !m_pDocHolder->GetDocument().is() )
385 {
386
387 STATSTG aStat;
388 hr = pStg->Stat( &aStat, STATFLAG_NONAME );
389 if ( FAILED( hr ) ) return E_FAIL;
390
391 DWORD nStreamMode = aStat.grfMode;
392
393 hr = E_FAIL;
394 if ( m_xFactory.is() && pStg )
395 {
396 uno::Reference< frame::XModel > aDocument(
397 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ),
398 uno::UNO_QUERY );
399 if ( aDocument.is() )
400 {
401 m_pDocHolder->SetDocument( aDocument );
402
403 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
404 if( xLoadable.is() )
405 {
406 try
407 {
408 xLoadable->initNew();
409 // xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), nStreamMode ) );
410 hr = S_OK;
411 }
412 catch( const uno::Exception& )
413 {
414 }
415 }
416
417 if ( hr == S_OK )
418 {
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) );
424
425 if ( hr == S_OK )
426 {
427 hr = pStg->CreateStream( aOfficeEmbedStreamName,
428 STGM_CREATE | ( nStreamMode & 0x73 ),
429 0,
430 0,
431 &m_pOwnStream );
432
433 if ( hr == S_OK && m_pOwnStream )
434 {
435 hr = pStg->CreateStream( aExtentStreamName,
436 STGM_CREATE | ( nStreamMode & 0x73 ),
437 0,
438 0,
439 &m_pExtStream );
440
441 if ( hr == S_OK && m_pExtStream )
442 {
443
444 m_pMasterStorage = pStg;
445 m_bIsDirty = true;
446 }
447 else
448 hr = E_FAIL;
449 }
450 else
451 hr = E_FAIL;
452 }
453 else
454 hr = E_FAIL;
455 }
456
457 if ( hr != S_OK )
458 m_pDocHolder->CloseDocument();
459 }
460 }
461 }
462
463 return hr;
464}
465
466COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Load( IStorage *pStg )
467{
468 if ( m_pDocHolder->GetDocument().is() )
469 return CO_E_ALREADYINITIALIZED;
470
471 if ( !m_xFactory.is() || !pStg )
472 return E_FAIL;
473
474 HRESULT hr = E_FAIL;
475
476 STATSTG aStat;
477 hr = pStg->Stat( &aStat, STATFLAG_NONAME );
478 if ( FAILED( hr ) ) return E_FAIL;
479
480 DWORD nStreamMode = aStat.grfMode;
481 hr = pStg->OpenStream( aOfficeEmbedStreamName,
482 nullptr,
483 nStreamMode & 0x73,
484 0,
485 &m_pOwnStream );
486 if ( !m_pOwnStream ) hr = E_FAIL;
487
488 if ( SUCCEEDED( hr ) )
489 {
490 hr = pStg->OpenStream( aExtentStreamName,
491 nullptr,
492 nStreamMode & 0x73,
493 0,
494 &m_pExtStream );
495 if ( !m_pExtStream ) hr = E_FAIL;
496 }
497
498 // RECTL aRectToSet;
499 SIZEL aSizeToSet;
500 if ( SUCCEEDED( hr ) )
501 {
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 ) )
506 {
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;
511
512 if ( SUCCEEDED( hr ) )
513 {
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];
520 }
521 }
522 }
523
524 if ( SUCCEEDED( hr ) )
525 {
526 hr = E_FAIL;
527
528 uno::Reference < io::XInputStream > xTempIn = createTempXInStreamFromIStream( m_xFactory, m_pOwnStream );
529 if ( xTempIn.is() )
530 {
531 uno::Reference< frame::XModel > aDocument(
532 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ),
533 uno::UNO_QUERY );
534 if ( aDocument.is() )
535 {
536 m_pDocHolder->SetDocument( aDocument );
537
538 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
539 if( xLoadable.is() )
540 {
541 try
542 {
543 xLoadable->load( fillArgsForLoading_Impl( xTempIn, nStreamMode ) );
544 m_pMasterStorage = pStg;
545 hr = m_pDocHolder->SetExtent( &aSizeToSet );
546 // hr = m_pDocHolder->SetVisArea( &aRectToSet );
547 }
548 catch( const uno::Exception& )
549 {
550 }
551 }
552
553 if ( FAILED( hr ) )
554 m_pDocHolder->CloseDocument();
555 }
556 }
557 }
558
559 if ( FAILED( hr ) )
560 {
561 m_pOwnStream = CComPtr< IStream >();
562 m_pExtStream = CComPtr< IStream >();
563 hr = pStg->DestroyElement( aOfficeEmbedStreamName );
564 hr = pStg->DestroyElement( aExtentStreamName );
565
566 OSL_ENSURE( SUCCEEDED( hr ), "Can not destroy created stream!" );
567 if ( FAILED( hr ) )
568 hr = E_FAIL;
569 }
570
571 return hr;
572}
573
574COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Save( IStorage *pStgSave, BOOL fSameAsLoad )
575{
576 if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() || !pStgSave || !m_pOwnStream || !m_pExtStream )
577 return E_FAIL;
578
579 CComPtr< IStream > pTargetStream;
580 CComPtr< IStream > pNewExtStream;
581
582 if ( !fSameAsLoad && pStgSave != m_pMasterStorage )
583 {
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;
587
588 STATSTG aStat;
589 hr = pStgSave->Stat( &aStat, STATFLAG_NONAME );
590 if ( FAILED( hr ) ) return E_FAIL;
591
592 DWORD nStreamMode = aStat.grfMode;
593 hr = pStgSave->CreateStream( aOfficeEmbedStreamName,
594 STGM_CREATE | ( nStreamMode & 0x73 ),
595 0,
596 0,
597 &pTargetStream );
598 if ( FAILED( hr ) || !pTargetStream ) return E_FAIL;
599
600 hr = pStgSave->CreateStream( aExtentStreamName,
601 STGM_CREATE | ( nStreamMode & 0x73 ),
602 0,
603 0,
604 &pNewExtStream );
605 if ( FAILED( hr ) || !pNewExtStream ) return E_FAIL;
606 }
607 else
608 {
609 pTargetStream = m_pOwnStream;
610 pNewExtStream = m_pExtStream;
611 }
612
613 HRESULT hr = E_FAIL;
614
615 uno::Reference < io::XOutputStream > xTempOut( io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
616 uno::UNO_QUERY_THROW );
617
618 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
619 if( xStorable.is() )
620 {
621 try
622 {
623 xStorable->storeToURL( "private:stream",
624 fillArgsForStoring_Impl( xTempOut ) );
625 hr = copyXTempOutToIStream( xTempOut, pTargetStream );
626 if ( SUCCEEDED( hr ) )
627 {
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 ) )
633 {
634 SIZEL aSize;
635 hr = m_pDocHolder->GetExtent( &aSize );
636
637 if ( SUCCEEDED( hr ) )
638 {
639 sal_uInt32 nWritten;
640 sal_Int32 aInf[EXT_STREAM_LENGTH] = {0, 0, aSize.cx, aSize.cy};
641
642 hr = pNewExtStream->Write( aInf, sizeof aInf, &nWritten );
643 if ( nWritten != sizeof aInf ) hr = E_FAIL;
644
645 if ( SUCCEEDED( hr ) )
646 {
647 m_pOwnStream = CComPtr< IStream >();
648 m_pExtStream = CComPtr< IStream >();
649 if ( fSameAsLoad || pStgSave == m_pMasterStorage )
650 {
651 uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
652 if ( xMod.is() )
653 xMod->setModified( false );
654 m_bIsDirty = false;
655 }
656 }
657 }
658 }
659 }
660 }
661 catch( const uno::Exception& )
662 {
663 }
664 }
665
666 return hr;
667}
668
669COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::SaveCompleted( IStorage *pStgNew )
670{
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
673
674 if ( m_pOwnStream || m_pExtStream )
675 return E_UNEXPECTED;
676
677 if ( !m_pMasterStorage && !pStgNew )
678 return E_INVALIDARG;
679
680 if ( pStgNew )
681 m_pMasterStorage = pStgNew;
682
683 STATSTG aStat;
684 HRESULT hr = m_pMasterStorage->Stat( &aStat, STATFLAG_NONAME );
685 if ( FAILED( hr ) ) return E_OUTOFMEMORY;
686
687 DWORD nStreamMode = aStat.grfMode;
689 nullptr,
690 nStreamMode & 0x73,
691 0,
692 &m_pOwnStream );
693 if ( FAILED( hr ) || !m_pOwnStream ) return E_OUTOFMEMORY;
694
696 nullptr,
697 nStreamMode & 0x73,
698 0,
699 &m_pExtStream );
700 if ( FAILED( hr ) || !m_pExtStream ) return E_OUTOFMEMORY;
701
702 for (auto const& advise : m_aAdviseHashMap)
703 {
704 if ( advise.second )
705 advise.second->OnSave();
706 }
707
708 return S_OK;
709}
710
711COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::HandsOffStorage()
712{
713 m_pMasterStorage = CComPtr< IStorage >();
714 m_pOwnStream = CComPtr< IStream >();
715 m_pExtStream = CComPtr< IStream >();
716
717 return S_OK;
718}
719
720
721// IPersistFile
722
723COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Load( LPCOLESTR pszFileName, DWORD /*dwMode*/ )
724{
725 if ( m_pDocHolder->GetDocument().is() )
726 return CO_E_ALREADYINITIALIZED;
727
728 if ( !m_xFactory.is() )
729 return E_FAIL;
730
731 DWORD nStreamMode = STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE | STGM_SHARE_EXCLUSIVE;
732 HRESULT hr = StgCreateDocfile( nullptr,
733 nStreamMode ,
734 0,
736
737 if ( FAILED( hr ) || !m_pMasterStorage ) return E_FAIL;
738
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;
745
746 hr = m_pMasterStorage->SetClass( m_guid );
747 if ( FAILED( hr ) ) return E_FAIL;
748
750 STGM_CREATE | ( nStreamMode & 0x73 ),
751 0,
752 0,
753 &m_pOwnStream );
754 if ( FAILED( hr ) || !m_pOwnStream ) return E_FAIL;
755
756 hr = m_pMasterStorage->CreateStream( aExtentStreamName,
757 STGM_CREATE | ( nStreamMode & 0x73 ),
758 0,
759 0,
760 &m_pExtStream );
761 if ( FAILED( hr ) || !m_pExtStream ) return E_FAIL;
762
763
764 uno::Reference< frame::XModel > aDocument(
765 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ),
766 uno::UNO_QUERY );
767 if ( aDocument.is() )
768 {
769 m_pDocHolder->SetDocument( aDocument, true );
770
771 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
772 if( xLoadable.is() )
773 {
774 try
775 {
776 xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(),
777 STGM_READWRITE,
778 pszFileName ) );
779 hr = S_OK;
780
781 m_aFileName = o3tl::toU(pszFileName);
782 }
783 catch( const uno::Exception& )
784 {
785 }
786 }
787
788 if ( hr == S_OK )
789 {
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())) );
795
796 if ( SUCCEEDED( hr ) )
797 {
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 ) )
803 {
804 SIZEL aSize;
805 hr = m_pDocHolder->GetExtent( &aSize );
806
807 if ( SUCCEEDED( hr ) )
808 {
809 sal_uInt32 nWritten;
810 sal_Int32 aInf[EXT_STREAM_LENGTH] = {0, 0, aSize.cx, aSize.cy};
811
812 hr = m_pExtStream->Write( aInf, sizeof aInf, &nWritten );
813 if ( nWritten != sizeof aInf ) hr = E_FAIL;
814 }
815 }
816 }
817
818 if ( SUCCEEDED( hr ) )
819 m_bIsDirty = true;
820 else
821 hr = E_FAIL;
822 }
823
824 if ( FAILED( hr ) )
825 {
826 m_pDocHolder->CloseDocument();
827 m_pOwnStream = nullptr;
828 m_pExtStream = nullptr;
829 m_pMasterStorage = nullptr;
830 }
831 }
832
833 return hr;
834}
835
836COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Save( LPCOLESTR pszFileName, BOOL fRemember )
837{
838 if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() )
839 return E_FAIL;
840
841 HRESULT hr = E_FAIL;
842
843 // TODO/LATER: currently there is no hands off state implemented
844 try
845 {
846 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY_THROW );
847
848 if ( !pszFileName )
849 xStorable->store();
850 else
851 {
852 util::URL aURL;
853 aURL.Complete = o3tl::toU( pszFileName );
854
855 uno::Reference< util::XURLTransformer > aTransformer( util::URLTransformer::create(comphelper::getComponentContext(m_xFactory)) );
856
857 if ( aTransformer->parseSmart( aURL, OUString() ) && aURL.Complete.getLength() )
858 {
859 if ( fRemember )
860 {
861 xStorable->storeAsURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) );
862 m_aFileName = aURL.Complete;
863 }
864 else
865 xStorable->storeToURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) );
866 }
867 }
868
869 hr = S_OK;
870 }
871 catch( const uno::Exception& )
872 {
873 }
874
875 return hr;
876}
877
878COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::SaveCompleted( LPCOLESTR pszFileName )
879{
880 // the different file name would mean error here
881 m_aFileName = o3tl::toU(pszFileName);
882 return S_OK;
883}
884
885COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::GetCurFile( LPOLESTR *ppszFileName )
886{
887 CComPtr<IMalloc> pMalloc;
888
889 HRESULT hr = CoGetMalloc( 1, &pMalloc );
890 if ( FAILED( hr ) || !pMalloc ) return E_FAIL;
891
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 );
894
895 return m_aFileName.getLength() ? S_OK : S_FALSE;
896}
897
898
900{
901 ::osl::MutexGuard aGuard( m_aMutex );
903}
904
906{
907 ::osl::MutexGuard aGuard( m_aMutex );
908 m_pEmbedDocument = nullptr;
909}
910
911
913: m_pEmbedDocument( nullptr )
914{}
915
917: m_pEmbedDocument( pEmbedDocument )
918{
919 if ( m_pEmbedDocument )
920 m_pEmbedDocument->AddRef();
921}
922
924: m_pEmbedDocument( aDocLock.m_pEmbedDocument )
925{
926 if ( m_pEmbedDocument )
927 m_pEmbedDocument->AddRef();
928}
929
931{
932 if ( m_pEmbedDocument )
933 m_pEmbedDocument->Release();
934
936 if ( m_pEmbedDocument )
937 m_pEmbedDocument->AddRef();
938
939 return *this;
940}
941
943{
944 if ( m_pEmbedDocument )
945 m_pEmbedDocument->Release();
946}
947
949{
950 if ( m_pEmbedDocument )
951 {
952 if ( nId == OLESERV_SAVEOBJECT )
954 else if ( nId == OLESERV_CLOSE )
956 else if ( nId == OLESERV_NOTIFY )
958 else if ( nId == OLESERV_NOTIFYCLOSING )
960 else if ( nId == OLESERV_SHOWOBJECT )
962 else if ( nId == OLESERV_DEACTIVATE )
964 }
965}
966
967/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
ScriptDocument aDocument
HRESULT OLENotifyClosing()
STDMETHOD() InitNew(IStorage *pStg) override
virtual ~EmbedDocument_Impl()
CComPtr< IStream > m_pOwnStream
Definition: embeddoc.hxx:159
STDMETHOD() GetClassID(CLSID *pClassID) override
STDMETHOD() Save(IStorage *pStgSave, BOOL fSameAsLoad) override
STDMETHOD() QueryInterface(REFIID riid, LPVOID *ppvObj) override
OUString m_aFileName
Definition: embeddoc.hxx:156
STDMETHOD() Load(IStorage *pStr) override
STDMETHOD() IsDirty() override
void notify(bool bDataChanged=true)
HRESULT SaveTo_Impl(IStorage *pStg)
oslInterlockedCount m_refCount
Definition: embeddoc.hxx:151
STDMETHOD() GetCurFile(LPOLESTR *ppszFileName) override
AdviseSinkHashMap m_aAdviseHashMap
Definition: embeddoc.hxx:168
rtl::Reference< DocumentHolder > m_pDocHolder
Definition: embeddoc.hxx:155
::rtl::Reference< EmbeddedDocumentInstanceAccess_Impl > m_xOwnAccess
Definition: embeddoc.hxx:171
css::uno::Sequence< css::beans::PropertyValue > fillArgsForStoring_Impl(css::uno::Reference< css::io::XOutputStream > const &xStream)
STDMETHOD() SaveCompleted(IStorage *pStgNew) override
EmbedDocument_Impl(const css::uno::Reference< css::lang::XMultiServiceFactory > &smgr, const GUID *guid)
CComPtr< IStream > m_pExtStream
Definition: embeddoc.hxx:160
css::uno::Sequence< css::beans::PropertyValue > fillArgsForLoading_Impl(css::uno::Reference< css::io::XInputStream > const &xStream, DWORD nStreamMode, LPCOLESTR pFilePath=nullptr)
STDMETHOD() Close(DWORD dwSaveOption) override
STDMETHOD() HandsOffStorage(void) override
css::uno::Reference< css::lang::XMultiServiceFactory > m_xFactory
Definition: embeddoc.hxx:153
CComPtr< IStorage > m_pMasterStorage
Definition: embeddoc.hxx:158
LockedEmbedDocument_Impl GetEmbedDocument()
int nCount
URL aURL
ULONG m_refCount
Definition: dllentry.cxx:155
GUID m_guid
Definition: dllentry.cxx:156
static HRESULT copyXTempOutToIStream(uno::Reference< io::XOutputStream > const &xTempOut, IStream *pStream)
const wchar_t aOfficeEmbedStreamName[]
static uno::Reference< io::XInputStream > createTempXInStreamFromIStream(uno::Reference< lang::XMultiServiceFactory > const &xFactory, IStream *pStream)
const wchar_t aExtentStreamName[]
#define EXT_STREAM_LENGTH
COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl
#define OLESERV_CLOSE
#define OLESERV_SAVEOBJECT
#define OLESERV_NOTIFYCLOSING
#define OLESERV_NOTIFY
#define OLESERV_DEACTIVATE
#define OLESERV_SHOWOBJECT
Reference< XSingleServiceFactory > xFactory
wchar_t const * getStorageTypeFromGUID_Impl(GUID const *guid)
Definition: guid.cxx:26
std::u16string_view getServiceNameFromGUID_Impl(GUID const *guid)
Definition: guid.cxx:61
OUString getFilterNameFromGUID_Impl(GUID const *guid)
Definition: guid.cxx:96
const sal_Int32 nConstBufferSize
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
sal_Int16 nId
const wchar_t *typedef BOOL
return hr
EmbedDocument_Impl * m_pEmbedDocument
LockedEmbedDocument_Impl & operator=(const LockedEmbedDocument_Impl &aDocLock)
void ExecuteMethod(sal_Int16 nId)
sal_uInt16 sal_Unicode
std::unique_ptr< char[]> aBuffer