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
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>
44
45 #include "guid.hxx"
46
47 #include <string.h>
48
49 #define EXT_STREAM_LENGTH 4
50
51 namespace {
52
53 const sal_Int32 nConstBufferSize = 32000;
54
55 }
56
57 using namespace ::com::sun::star;
58
59 const wchar_t aOfficeEmbedStreamName[] = L"package_stream";
60 const wchar_t aExtentStreamName[] = L"properties_stream";
61
createTempXInStreamFromIStream(uno::Reference<lang::XMultiServiceFactory> const & xFactory,IStream * pStream)62 static 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
copyXTempOutToIStream(uno::Reference<io::XOutputStream> const & xTempOut,IStream * pStream)116 static 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
EmbedDocument_Impl(const uno::Reference<lang::XMultiServiceFactory> & xFactory,const GUID * guid)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 )
175 {
176 m_xOwnAccess = new EmbeddedDocumentInstanceAccess_Impl( this );
177 m_pDocHolder = new DocumentHolder( xFactory, m_xOwnAccess );
178 }
179
~EmbedDocument_Impl()180 EmbedDocument_Impl::~EmbedDocument_Impl()
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
fillArgsForLoading_Impl(uno::Reference<io::XInputStream> const & xStream,DWORD,LPCOLESTR pFilePath)196 uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForLoading_Impl( uno::Reference< io::XInputStream > const & xStream, DWORD /*nStreamMode*/, LPCOLESTR pFilePath )
197 {
198 uno::Sequence< beans::PropertyValue > aArgs( 3 );
199
200 sal_Int32 nInd = 0; // must not be bigger than the preset size
201 aArgs[nInd].Name = "FilterName";
202 aArgs[nInd++].Value <<= getFilterNameFromGUID_Impl( &m_guid );
203
204 if ( xStream.is() )
205 {
206 aArgs[nInd].Name = "InputStream";
207 aArgs[nInd++].Value <<= xStream;
208 aArgs[nInd].Name = "URL";
209 aArgs[nInd++].Value <<= OUString( "private:stream" );
210 }
211 else
212 {
213 aArgs[nInd].Name = "URL";
214
215 OUString sDocUrl;
216 if ( pFilePath )
217 {
218 uno::Reference< util::XURLTransformer > aTransformer( util::URLTransformer::create(comphelper::getComponentContext(m_xFactory)) );
219 util::URL aURL;
220
221 aURL.Complete = o3tl::toU(pFilePath);
222
223 if ( aTransformer->parseSmart( aURL, OUString() ) )
224 sDocUrl = aURL.Complete;
225 }
226
227 aArgs[nInd++].Value <<= sDocUrl;
228 }
229
230 aArgs.realloc( nInd );
231
232 // aArgs[].Name = "ReadOnly";
233 // aArgs[].Value <<= sal_False; //( ( nStreamMode & ( STGM_READWRITE | STGM_WRITE ) ) ? sal_True : sal_False );
234
235 return aArgs;
236 }
237
fillArgsForStoring_Impl(uno::Reference<io::XOutputStream> const & xStream)238 uno::Sequence< beans::PropertyValue > EmbedDocument_Impl::fillArgsForStoring_Impl( uno::Reference< io::XOutputStream > const & xStream)
239 {
240 uno::Sequence< beans::PropertyValue > aArgs( xStream.is() ? 2 : 1 );
241
242 aArgs[0].Name = "FilterName";
243 aArgs[0].Value <<= getFilterNameFromGUID_Impl( &m_guid );
244
245 if ( xStream.is() )
246 {
247 aArgs[1].Name = "OutputStream";
248 aArgs[1].Value <<= xStream;
249 }
250
251 return aArgs;
252 }
253
SaveTo_Impl(IStorage * pStg)254 HRESULT EmbedDocument_Impl::SaveTo_Impl( IStorage* pStg )
255 {
256 if ( !pStg || pStg == m_pMasterStorage )
257 return E_FAIL;
258
259 // for saveto operation the master storage
260 // should not enter NoScribble mode
261 CComPtr< IStream > pOrigOwn = m_pOwnStream;
262 CComPtr< IStream > pOrigExt = m_pExtStream;
263 HRESULT hr = Save( pStg, false );
264 pStg->Commit( STGC_ONLYIFCURRENT );
265 m_pOwnStream = pOrigOwn;
266 m_pExtStream = pOrigExt;
267
268 return hr;
269 }
270
271
272 // IUnknown
273
QueryInterface(REFIID riid,void ** ppv)274 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::QueryInterface(REFIID riid, void** ppv)
275 {
276 if(IsEqualIID(riid, IID_IUnknown))
277 {
278 AddRef();
279 *ppv = static_cast<IUnknown*>(static_cast<IPersistStorage*>(this));
280 return S_OK;
281 }
282 else if (IsEqualIID(riid, IID_IPersist))
283 {
284 AddRef();
285 *ppv = static_cast<IPersist*>(static_cast<IPersistStorage*>(this));
286 return S_OK;
287 }
288 else if (IsEqualIID(riid, IID_IExternalConnection))
289 {
290 AddRef();
291 *ppv = static_cast<IExternalConnection*>(this);
292 return S_OK;
293 }
294 else if (IsEqualIID(riid, IID_IPersistStorage))
295 {
296 AddRef();
297 *ppv = static_cast<IPersistStorage*>(this);
298 return S_OK;
299 }
300 else if (IsEqualIID(riid, IID_IDataObject))
301 {
302 AddRef();
303 *ppv = static_cast<IDataObject*>(this);
304 return S_OK;
305 }
306 else if (IsEqualIID(riid, IID_IOleObject))
307 {
308 AddRef();
309 *ppv = static_cast<IOleObject*>(this);
310 return S_OK;
311 }
312 else if (IsEqualIID(riid, IID_IOleWindow))
313 {
314 AddRef();
315 *ppv = static_cast<IOleWindow*>(this);
316 return S_OK;
317 }
318 else if (IsEqualIID(riid, IID_IOleInPlaceObject))
319 {
320 AddRef();
321 *ppv = static_cast<IOleInPlaceObject*>(this);
322 return S_OK;
323 }
324 else if (IsEqualIID(riid, IID_IPersistFile))
325 {
326 AddRef();
327 *ppv = static_cast<IPersistFile*>(this);
328 return S_OK;
329 }
330 else if (IsEqualIID(riid, IID_IDispatch))
331 {
332 AddRef();
333 *ppv = static_cast<IDispatch*>(this);
334 return S_OK;
335 }
336
337 *ppv = nullptr;
338 return ResultFromScode(E_NOINTERFACE);
339 }
340
STDMETHODIMP_(ULONG)341 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl::AddRef()
342 {
343 return osl_atomic_increment( &m_refCount);
344 }
345
STDMETHODIMP_(ULONG)346 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) EmbedDocument_Impl::Release()
347 {
348 // if there is a time when the last reference is destructed, that means that only internal pointers are alive
349 // after the following call either the refcount is increased or the pointers are empty
350 if ( m_refCount == 1 )
351 m_xOwnAccess->ClearEmbedDocument();
352
353 sal_Int32 nCount = osl_atomic_decrement( &m_refCount );
354 if ( nCount == 0 )
355 delete this;
356 return nCount;
357 }
358
359
360 // IPersist
361
GetClassID(CLSID * pClassId)362 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::GetClassID( CLSID* pClassId )
363 {
364 *pClassId = m_guid;
365 return S_OK;
366 }
367
368
369 // IPersistStorage
370
IsDirty()371 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::IsDirty()
372 {
373 // the link modified state is controlled by the document
374 if ( m_bIsDirty && !m_aFileName.getLength() )
375 return S_OK;
376
377 uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
378 if ( xMod.is() )
379 return xMod->isModified() ? S_OK : S_FALSE;
380 return S_FALSE;
381 }
382
InitNew(IStorage * pStg)383 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::InitNew( IStorage *pStg )
384 {
385 HRESULT hr = CO_E_ALREADYINITIALIZED;
386
387 if ( !m_pDocHolder->GetDocument().is() )
388 {
389
390 STATSTG aStat;
391 hr = pStg->Stat( &aStat, STATFLAG_NONAME );
392 if ( FAILED( hr ) ) return E_FAIL;
393
394 DWORD nStreamMode = aStat.grfMode;
395
396 hr = E_FAIL;
397 if ( m_xFactory.is() && pStg )
398 {
399 uno::Reference< frame::XModel > aDocument(
400 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ),
401 uno::UNO_QUERY );
402 if ( aDocument.is() )
403 {
404 m_pDocHolder->SetDocument( aDocument );
405
406 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
407 if( xLoadable.is() )
408 {
409 try
410 {
411 xLoadable->initNew();
412 // xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(), nStreamMode ) );
413 hr = S_OK;
414 }
415 catch( const uno::Exception& )
416 {
417 }
418 }
419
420 if ( hr == S_OK )
421 {
422 wchar_t const * aCurType = getStorageTypeFromGUID_Impl( &m_guid ); // ???
423 CLIPFORMAT cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" ));
424 hr = WriteFmtUserTypeStg( pStg,
425 cf, // ???
426 const_cast<wchar_t *>(aCurType) );
427
428 if ( hr == S_OK )
429 {
430 hr = pStg->CreateStream( aOfficeEmbedStreamName,
431 STGM_CREATE | ( nStreamMode & 0x73 ),
432 0,
433 0,
434 &m_pOwnStream );
435
436 if ( hr == S_OK && m_pOwnStream )
437 {
438 hr = pStg->CreateStream( aExtentStreamName,
439 STGM_CREATE | ( nStreamMode & 0x73 ),
440 0,
441 0,
442 &m_pExtStream );
443
444 if ( hr == S_OK && m_pExtStream )
445 {
446
447 m_pMasterStorage = pStg;
448 m_bIsDirty = true;
449 }
450 else
451 hr = E_FAIL;
452 }
453 else
454 hr = E_FAIL;
455 }
456 else
457 hr = E_FAIL;
458 }
459
460 if ( hr != S_OK )
461 m_pDocHolder->CloseDocument();
462 }
463 }
464 }
465
466 return hr;
467 }
468
Load(IStorage * pStg)469 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Load( IStorage *pStg )
470 {
471 if ( m_pDocHolder->GetDocument().is() )
472 return CO_E_ALREADYINITIALIZED;
473
474 if ( !m_xFactory.is() || !pStg )
475 return E_FAIL;
476
477 HRESULT hr = E_FAIL;
478
479 STATSTG aStat;
480 hr = pStg->Stat( &aStat, STATFLAG_NONAME );
481 if ( FAILED( hr ) ) return E_FAIL;
482
483 DWORD nStreamMode = aStat.grfMode;
484 hr = pStg->OpenStream( aOfficeEmbedStreamName,
485 nullptr,
486 nStreamMode & 0x73,
487 0,
488 &m_pOwnStream );
489 if ( !m_pOwnStream ) hr = E_FAIL;
490
491 if ( SUCCEEDED( hr ) )
492 {
493 hr = pStg->OpenStream( aExtentStreamName,
494 nullptr,
495 nStreamMode & 0x73,
496 0,
497 &m_pExtStream );
498 if ( !m_pExtStream ) hr = E_FAIL;
499 }
500
501 // RECTL aRectToSet;
502 SIZEL aSizeToSet;
503 if ( SUCCEEDED( hr ) )
504 {
505 ULARGE_INTEGER nNewPos;
506 LARGE_INTEGER const aZero = { 0, 0 };
507 hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
508 if ( SUCCEEDED( hr ) )
509 {
510 sal_uInt32 nRead;
511 sal_Int32 aInf[EXT_STREAM_LENGTH];
512 hr = m_pExtStream->Read( aInf, sizeof aInf, &nRead );
513 if ( nRead != sizeof aInf ) hr = E_FAIL;
514
515 if ( SUCCEEDED( hr ) )
516 {
517 // aRectToSet.left = *((sal_Int32*)aInf);
518 // aRectToSet.top = *((sal_Int32*)&aInf[4]);
519 // aRectToSet.right = *((sal_Int32*)&aInf[8]);
520 // aRectToSet.bottom = *((sal_Int32*)&aInf[12]);
521 aSizeToSet.cx = aInf[2] - aInf[0];
522 aSizeToSet.cy = aInf[3] - aInf[1];
523 }
524 }
525 }
526
527 if ( SUCCEEDED( hr ) )
528 {
529 hr = E_FAIL;
530
531 uno::Reference < io::XInputStream > xTempIn = createTempXInStreamFromIStream( m_xFactory, m_pOwnStream );
532 if ( xTempIn.is() )
533 {
534 uno::Reference< frame::XModel > aDocument(
535 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ),
536 uno::UNO_QUERY );
537 if ( aDocument.is() )
538 {
539 m_pDocHolder->SetDocument( aDocument );
540
541 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
542 if( xLoadable.is() )
543 {
544 try
545 {
546 xLoadable->load( fillArgsForLoading_Impl( xTempIn, nStreamMode ) );
547 m_pMasterStorage = pStg;
548 hr = m_pDocHolder->SetExtent( &aSizeToSet );
549 // hr = m_pDocHolder->SetVisArea( &aRectToSet );
550 }
551 catch( const uno::Exception& )
552 {
553 }
554 }
555
556 if ( FAILED( hr ) )
557 m_pDocHolder->CloseDocument();
558 }
559 }
560 }
561
562 if ( FAILED( hr ) )
563 {
564 m_pOwnStream = CComPtr< IStream >();
565 m_pExtStream = CComPtr< IStream >();
566 hr = pStg->DestroyElement( aOfficeEmbedStreamName );
567 hr = pStg->DestroyElement( aExtentStreamName );
568
569 OSL_ENSURE( SUCCEEDED( hr ), "Can not destroy created stream!" );
570 if ( FAILED( hr ) )
571 hr = E_FAIL;
572 }
573
574 return hr;
575 }
576
Save(IStorage * pStgSave,BOOL fSameAsLoad)577 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Save( IStorage *pStgSave, BOOL fSameAsLoad )
578 {
579 if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() || !pStgSave || !m_pOwnStream || !m_pExtStream )
580 return E_FAIL;
581
582 CComPtr< IStream > pTargetStream;
583 CComPtr< IStream > pNewExtStream;
584
585 if ( !fSameAsLoad && pStgSave != m_pMasterStorage )
586 {
587 OSL_ENSURE( m_pMasterStorage, "How could the document be initialized without storage!??" );
588 HRESULT hr = m_pMasterStorage->CopyTo( NULL, nullptr, nullptr, pStgSave );
589 if ( FAILED( hr ) ) return E_FAIL;
590
591 STATSTG aStat;
592 hr = pStgSave->Stat( &aStat, STATFLAG_NONAME );
593 if ( FAILED( hr ) ) return E_FAIL;
594
595 DWORD nStreamMode = aStat.grfMode;
596 hr = pStgSave->CreateStream( aOfficeEmbedStreamName,
597 STGM_CREATE | ( nStreamMode & 0x73 ),
598 0,
599 0,
600 &pTargetStream );
601 if ( FAILED( hr ) || !pTargetStream ) return E_FAIL;
602
603 hr = pStgSave->CreateStream( aExtentStreamName,
604 STGM_CREATE | ( nStreamMode & 0x73 ),
605 0,
606 0,
607 &pNewExtStream );
608 if ( FAILED( hr ) || !pNewExtStream ) return E_FAIL;
609 }
610 else
611 {
612 pTargetStream = m_pOwnStream;
613 pNewExtStream = m_pExtStream;
614 }
615
616 HRESULT hr = E_FAIL;
617
618 uno::Reference < io::XOutputStream > xTempOut( io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
619 uno::UNO_QUERY_THROW );
620
621 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
622 if( xStorable.is() )
623 {
624 try
625 {
626 xStorable->storeToURL( "private:stream",
627 fillArgsForStoring_Impl( xTempOut ) );
628 hr = copyXTempOutToIStream( xTempOut, pTargetStream );
629 if ( SUCCEEDED( hr ) )
630 {
631 // no need to truncate the stream, the size of the stream is always the same
632 ULARGE_INTEGER nNewPos;
633 LARGE_INTEGER const aZero = { 0, 0 };
634 hr = pNewExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
635 if ( SUCCEEDED( hr ) )
636 {
637 SIZEL aSize;
638 hr = m_pDocHolder->GetExtent( &aSize );
639
640 if ( SUCCEEDED( hr ) )
641 {
642 sal_uInt32 nWritten;
643 sal_Int32 aInf[EXT_STREAM_LENGTH] = {0, 0, aSize.cx, aSize.cy};
644
645 hr = pNewExtStream->Write( aInf, sizeof aInf, &nWritten );
646 if ( nWritten != sizeof aInf ) hr = E_FAIL;
647
648 if ( SUCCEEDED( hr ) )
649 {
650 m_pOwnStream = CComPtr< IStream >();
651 m_pExtStream = CComPtr< IStream >();
652 if ( fSameAsLoad || pStgSave == m_pMasterStorage )
653 {
654 uno::Reference< util::XModifiable > xMod( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
655 if ( xMod.is() )
656 xMod->setModified( false );
657 m_bIsDirty = false;
658 }
659 }
660 }
661 }
662 }
663 }
664 catch( const uno::Exception& )
665 {
666 }
667 }
668
669 return hr;
670 }
671
SaveCompleted(IStorage * pStgNew)672 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::SaveCompleted( IStorage *pStgNew )
673 {
674 // m_pOwnStream == NULL && m_pMasterStorage != NULL means the object is in NoScribble mode
675 // m_pOwnStream == NULL && m_pMasterStorage == NULL means the object is in HandsOff mode
676
677 if ( m_pOwnStream || m_pExtStream )
678 return E_UNEXPECTED;
679
680 if ( !m_pMasterStorage && !pStgNew )
681 return E_INVALIDARG;
682
683 if ( pStgNew )
684 m_pMasterStorage = pStgNew;
685
686 STATSTG aStat;
687 HRESULT hr = m_pMasterStorage->Stat( &aStat, STATFLAG_NONAME );
688 if ( FAILED( hr ) ) return E_OUTOFMEMORY;
689
690 DWORD nStreamMode = aStat.grfMode;
691 hr = m_pMasterStorage->OpenStream( aOfficeEmbedStreamName,
692 nullptr,
693 nStreamMode & 0x73,
694 0,
695 &m_pOwnStream );
696 if ( FAILED( hr ) || !m_pOwnStream ) return E_OUTOFMEMORY;
697
698 hr = m_pMasterStorage->OpenStream( aExtentStreamName,
699 nullptr,
700 nStreamMode & 0x73,
701 0,
702 &m_pExtStream );
703 if ( FAILED( hr ) || !m_pExtStream ) return E_OUTOFMEMORY;
704
705 for (auto const& advise : m_aAdviseHashMap)
706 {
707 if ( advise.second )
708 advise.second->OnSave();
709 }
710
711 return S_OK;
712 }
713
HandsOffStorage()714 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::HandsOffStorage()
715 {
716 m_pMasterStorage = CComPtr< IStorage >();
717 m_pOwnStream = CComPtr< IStream >();
718 m_pExtStream = CComPtr< IStream >();
719
720 return S_OK;
721 }
722
723
724 // IPersistFile
725
Load(LPCOLESTR pszFileName,DWORD)726 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Load( LPCOLESTR pszFileName, DWORD /*dwMode*/ )
727 {
728 if ( m_pDocHolder->GetDocument().is() )
729 return CO_E_ALREADYINITIALIZED;
730
731 if ( !m_xFactory.is() )
732 return E_FAIL;
733
734 DWORD nStreamMode = STGM_CREATE | STGM_READWRITE | STGM_DELETEONRELEASE | STGM_SHARE_EXCLUSIVE;
735 HRESULT hr = StgCreateDocfile( nullptr,
736 nStreamMode ,
737 0,
738 &m_pMasterStorage );
739
740 if ( FAILED( hr ) || !m_pMasterStorage ) return E_FAIL;
741
742 std::u16string_view aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ???
743 CLIPFORMAT cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" ));
744 hr = WriteFmtUserTypeStg( m_pMasterStorage,
745 cf, // ???
746 const_cast<LPOLESTR>( o3tl::toW(aCurType.data())) );
747 if ( FAILED( hr ) ) return E_FAIL;
748
749 hr = m_pMasterStorage->SetClass( m_guid );
750 if ( FAILED( hr ) ) return E_FAIL;
751
752 hr = m_pMasterStorage->CreateStream( aOfficeEmbedStreamName,
753 STGM_CREATE | ( nStreamMode & 0x73 ),
754 0,
755 0,
756 &m_pOwnStream );
757 if ( FAILED( hr ) || !m_pOwnStream ) return E_FAIL;
758
759 hr = m_pMasterStorage->CreateStream( aExtentStreamName,
760 STGM_CREATE | ( nStreamMode & 0x73 ),
761 0,
762 0,
763 &m_pExtStream );
764 if ( FAILED( hr ) || !m_pExtStream ) return E_FAIL;
765
766
767 uno::Reference< frame::XModel > aDocument(
768 m_xFactory->createInstance( OUString(getServiceNameFromGUID_Impl( &m_guid )) ),
769 uno::UNO_QUERY );
770 if ( aDocument.is() )
771 {
772 m_pDocHolder->SetDocument( aDocument, true );
773
774 uno::Reference< frame::XLoadable > xLoadable( m_pDocHolder->GetDocument(), uno::UNO_QUERY );
775 if( xLoadable.is() )
776 {
777 try
778 {
779 xLoadable->load( fillArgsForLoading_Impl( uno::Reference< io::XInputStream >(),
780 STGM_READWRITE,
781 pszFileName ) );
782 hr = S_OK;
783
784 m_aFileName = o3tl::toU(pszFileName);
785 }
786 catch( const uno::Exception& )
787 {
788 }
789 }
790
791 if ( hr == S_OK )
792 {
793 aCurType = getServiceNameFromGUID_Impl( &m_guid ); // ???
794 cf = static_cast<CLIPFORMAT>(RegisterClipboardFormatW( L"Embedded Object" ));
795 hr = WriteFmtUserTypeStg( m_pMasterStorage,
796 cf, // ???
797 const_cast<LPOLESTR>( o3tl::toW(aCurType.data())) );
798
799 if ( SUCCEEDED( hr ) )
800 {
801 // no need to truncate the stream, the size of the stream is always the same
802 ULARGE_INTEGER nNewPos;
803 LARGE_INTEGER const aZero = { 0, 0 };
804 hr = m_pExtStream->Seek( aZero, STREAM_SEEK_SET, &nNewPos );
805 if ( SUCCEEDED( hr ) )
806 {
807 SIZEL aSize;
808 hr = m_pDocHolder->GetExtent( &aSize );
809
810 if ( SUCCEEDED( hr ) )
811 {
812 sal_uInt32 nWritten;
813 sal_Int32 aInf[EXT_STREAM_LENGTH] = {0, 0, aSize.cx, aSize.cy};
814
815 hr = m_pExtStream->Write( aInf, sizeof aInf, &nWritten );
816 if ( nWritten != sizeof aInf ) hr = E_FAIL;
817 }
818 }
819 }
820
821 if ( SUCCEEDED( hr ) )
822 m_bIsDirty = true;
823 else
824 hr = E_FAIL;
825 }
826
827 if ( FAILED( hr ) )
828 {
829 m_pDocHolder->CloseDocument();
830 m_pOwnStream = nullptr;
831 m_pExtStream = nullptr;
832 m_pMasterStorage = nullptr;
833 }
834 }
835
836 return hr;
837 }
838
Save(LPCOLESTR pszFileName,BOOL fRemember)839 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::Save( LPCOLESTR pszFileName, BOOL fRemember )
840 {
841 if ( !m_pDocHolder->GetDocument().is() || !m_xFactory.is() )
842 return E_FAIL;
843
844 HRESULT hr = E_FAIL;
845
846 // TODO/LATER: currently there is no hands off state implemented
847 try
848 {
849 uno::Reference< frame::XStorable > xStorable( m_pDocHolder->GetDocument(), uno::UNO_QUERY_THROW );
850
851 if ( !pszFileName )
852 xStorable->store();
853 else
854 {
855 util::URL aURL;
856 aURL.Complete = o3tl::toU( pszFileName );
857
858 uno::Reference< util::XURLTransformer > aTransformer( util::URLTransformer::create(comphelper::getComponentContext(m_xFactory)) );
859
860 if ( aTransformer->parseSmart( aURL, OUString() ) && aURL.Complete.getLength() )
861 {
862 if ( fRemember )
863 {
864 xStorable->storeAsURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) );
865 m_aFileName = aURL.Complete;
866 }
867 else
868 xStorable->storeToURL( aURL.Complete, fillArgsForStoring_Impl( uno::Reference< io::XOutputStream >() ) );
869 }
870 }
871
872 hr = S_OK;
873 }
874 catch( const uno::Exception& )
875 {
876 }
877
878 return hr;
879 }
880
SaveCompleted(LPCOLESTR pszFileName)881 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::SaveCompleted( LPCOLESTR pszFileName )
882 {
883 // the different file name would mean error here
884 m_aFileName = o3tl::toU(pszFileName);
885 return S_OK;
886 }
887
GetCurFile(LPOLESTR * ppszFileName)888 COM_DECLSPEC_NOTHROW STDMETHODIMP EmbedDocument_Impl::GetCurFile( LPOLESTR *ppszFileName )
889 {
890 CComPtr<IMalloc> pMalloc;
891
892 HRESULT hr = CoGetMalloc( 1, &pMalloc );
893 if ( FAILED( hr ) || !pMalloc ) return E_FAIL;
894
895 *ppszFileName = static_cast<LPOLESTR>( pMalloc->Alloc( sizeof( sal_Unicode ) * ( m_aFileName.getLength() + 1 ) ) );
896 wcsncpy( *ppszFileName, o3tl::toW(m_aFileName.getStr()), m_aFileName.getLength() + 1 );
897
898 return m_aFileName.getLength() ? S_OK : S_FALSE;
899 }
900
901
GetEmbedDocument()902 LockedEmbedDocument_Impl EmbeddedDocumentInstanceAccess_Impl::GetEmbedDocument()
903 {
904 ::osl::MutexGuard aGuard( m_aMutex );
905 return LockedEmbedDocument_Impl( m_pEmbedDocument );
906 }
907
ClearEmbedDocument()908 void EmbeddedDocumentInstanceAccess_Impl::ClearEmbedDocument()
909 {
910 ::osl::MutexGuard aGuard( m_aMutex );
911 m_pEmbedDocument = nullptr;
912 }
913
914
LockedEmbedDocument_Impl()915 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl()
916 : m_pEmbedDocument( nullptr )
917 {}
918
LockedEmbedDocument_Impl(EmbedDocument_Impl * pEmbedDocument)919 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( EmbedDocument_Impl* pEmbedDocument )
920 : m_pEmbedDocument( pEmbedDocument )
921 {
922 if ( m_pEmbedDocument )
923 m_pEmbedDocument->AddRef();
924 }
925
LockedEmbedDocument_Impl(const LockedEmbedDocument_Impl & aDocLock)926 LockedEmbedDocument_Impl::LockedEmbedDocument_Impl( const LockedEmbedDocument_Impl& aDocLock )
927 : m_pEmbedDocument( aDocLock.m_pEmbedDocument )
928 {
929 if ( m_pEmbedDocument )
930 m_pEmbedDocument->AddRef();
931 }
932
operator =(const LockedEmbedDocument_Impl & aDocLock)933 LockedEmbedDocument_Impl& LockedEmbedDocument_Impl::operator=( const LockedEmbedDocument_Impl& aDocLock )
934 {
935 if ( m_pEmbedDocument )
936 m_pEmbedDocument->Release();
937
938 m_pEmbedDocument = aDocLock.m_pEmbedDocument;
939 if ( m_pEmbedDocument )
940 m_pEmbedDocument->AddRef();
941
942 return *this;
943 }
944
~LockedEmbedDocument_Impl()945 LockedEmbedDocument_Impl::~LockedEmbedDocument_Impl()
946 {
947 if ( m_pEmbedDocument )
948 m_pEmbedDocument->Release();
949 }
950
ExecuteMethod(sal_Int16 nId)951 void LockedEmbedDocument_Impl::ExecuteMethod( sal_Int16 nId )
952 {
953 if ( m_pEmbedDocument )
954 {
955 if ( nId == OLESERV_SAVEOBJECT )
956 m_pEmbedDocument->SaveObject();
957 else if ( nId == OLESERV_CLOSE )
958 m_pEmbedDocument->Close( 0 );
959 else if ( nId == OLESERV_NOTIFY )
960 m_pEmbedDocument->notify();
961 else if ( nId == OLESERV_NOTIFYCLOSING )
962 m_pEmbedDocument->OLENotifyClosing();
963 else if ( nId == OLESERV_SHOWOBJECT )
964 m_pEmbedDocument->ShowObject();
965 else if ( nId == OLESERV_DEACTIVATE )
966 m_pEmbedDocument->Deactivate();
967 }
968 }
969
970 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
971