LibreOffice Module embeddedobj (master) 1
oleembed.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 <oleembobj.hxx>
25#include <com/sun/star/embed/EmbedStates.hpp>
26#include <com/sun/star/embed/EmbedVerbs.hpp>
27#include <com/sun/star/embed/UnreachableStateException.hpp>
28#include <com/sun/star/embed/XStorage.hpp>
29#include <com/sun/star/embed/ElementModes.hpp>
30#include <com/sun/star/embed/EmbedUpdateModes.hpp>
31#include <com/sun/star/embed/NeedsRunningStateException.hpp>
32#include <com/sun/star/embed/StateChangeInProgressException.hpp>
33#include <com/sun/star/embed/EmbedMisc.hpp>
34#include <com/sun/star/embed/XEmbedObjectCreator.hpp>
35#include <com/sun/star/io/TempFile.hpp>
36#include <com/sun/star/io/XSeekable.hpp>
37#include <com/sun/star/lang/DisposedException.hpp>
38#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
39#include <com/sun/star/beans/NamedValue.hpp>
40#include <com/sun/star/beans/XPropertySet.hpp>
41#include <com/sun/star/frame/XLoadable.hpp>
42#include <com/sun/star/document/XStorageBasedDocument.hpp>
43#include <com/sun/star/ucb/SimpleFileAccess.hpp>
44#include <com/sun/star/container/XNameAccess.hpp>
45#include <com/sun/star/container/XNameContainer.hpp>
46#include <com/sun/star/system/SystemShellExecute.hpp>
47#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
48
53#include <sal/log.hxx>
55
56
58
59#include "ownview.hxx"
60
61#if defined(_WIN32)
62#include "olecomponent.hxx"
63#endif
64
65using namespace ::com::sun::star;
66
67#ifdef _WIN32
68
69void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
70{
71 if ( !m_pOleComponent )
72 {
73 throw embed::UnreachableStateException();
74 }
75 try
76 {
77 m_pOleComponent->RunObject();
78 }
79 catch( const embed::UnreachableStateException& )
80 {
82 throw;
83 }
84 catch( const embed::WrongStateException& )
85 {
87 throw;
88 }
89}
90
91
92uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl(
93 const uno::Sequence< embed::VerbDescriptor >& aVerbList )
94{
95 uno::Sequence< sal_Int32 > aStates { embed::EmbedStates::LOADED, embed::EmbedStates::RUNNING };
96 for ( embed::VerbDescriptor const & vd : aVerbList )
97 if ( vd.VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
98 {
99 aStates.realloc(3);
100 aStates.getArray()[2] = embed::EmbedStates::ACTIVE;
101 break;
102 }
103
104 return aStates;
105}
106
107
108uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState )
109{
110 SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "Loaded object is switched to running state without verbs using!" );
111
112 // actually there will be only one verb
113 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
114 {
115 return { embed::EmbedVerbs::MS_OLEVERB_OPEN };
116 }
117
118 return uno::Sequence< sal_Int32 >();
119}
120#endif
121
123{
125 return;
126
127 // move state change listeners
128 {
129 comphelper::OInterfaceContainerHelper2* pStateChangeContainer =
131 if ( pStateChangeContainer != nullptr )
132 {
133 if ( m_xWrappedObject.is() )
134 {
135 comphelper::OInterfaceIteratorHelper2 pIterator( *pStateChangeContainer );
136 while ( pIterator.hasMoreElements() )
137 {
138 try
139 {
140 m_xWrappedObject->addStateChangeListener( static_cast<embed::XStateChangeListener*>(pIterator.next()) );
141 }
142 catch( const uno::RuntimeException& )
143 {
144 pIterator.remove();
145 }
146 }
147 }
148 }
149 }
150
151 // move event listeners
152 {
155 if ( pEventContainer != nullptr )
156 {
157 if ( m_xWrappedObject.is() )
158 {
159 comphelper::OInterfaceIteratorHelper2 pIterator( *pEventContainer );
160 while ( pIterator.hasMoreElements() )
161 {
162 try
163 {
164 m_xWrappedObject->addEventListener( static_cast<document::XEventListener*>(pIterator.next()) );
165 }
166 catch( const uno::RuntimeException& )
167 {
168 pIterator.remove();
169 }
170 }
171 }
172 }
173 }
174
175 // move close listeners
176 {
179 if ( pCloseContainer != nullptr )
180 {
181 if ( m_xWrappedObject.is() )
182 {
183 comphelper::OInterfaceIteratorHelper2 pIterator( *pCloseContainer );
184 while ( pIterator.hasMoreElements() )
185 {
186 try
187 {
188 m_xWrappedObject->addCloseListener( static_cast<util::XCloseListener*>(pIterator.next()) );
189 }
190 catch( const uno::RuntimeException& )
191 {
192 pIterator.remove();
193 }
194 }
195 }
196 }
197 }
198
199 m_pInterfaceContainer.reset();
200}
201
202
203uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( OUString& o_aStorageName )
204{
205 uno::Reference< embed::XStorage > xResult;
206
207 for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ )
208 {
209 OUString aName = OUString::number( nInd ) + "TMPSTOR" + m_aEntryName;
210 if ( !m_xParentStorage->hasByName( aName ) )
211 {
212 xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE );
213 o_aStorageName = aName;
214 }
215 }
216
217 if ( !xResult.is() )
218 {
219 o_aStorageName.clear();
220 throw uno::RuntimeException("Failed to create temporary storage for OLE embed object");
221 }
222
223 return xResult;
224}
225
226
228{
229 OUString aResult;
230 for ( sal_Int32 nInd = 0; nInd < 32000 && aResult.isEmpty(); nInd++ )
231 {
232 OUString aName = OUString::number( nInd ) + "TMPSTREAM" + m_aEntryName;
233 if ( !m_xParentStorage->hasByName( aName ) )
234 {
235 m_xParentStorage->renameElement( m_aEntryName, aName );
236 aResult = aName;
237 }
238 }
239
240 if ( aResult.isEmpty() )
241 throw uno::RuntimeException("Failed to rename temporary storage for OLE embed object");
242
243 return aResult;
244}
245
246
247bool OleEmbeddedObject::TryToConvertToOOo( const uno::Reference< io::XStream >& xStream )
248{
249 bool bResult = false;
250
251 OUString aStorageName;
252 OUString aTmpStreamName;
253 sal_Int32 nStep = 0;
254
256 return false;
257
258 try
259 {
260 changeState( embed::EmbedStates::LOADED );
261
262 // the stream must be seekable
263 uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY_THROW );
264 xSeekable->seek( 0 );
265 m_aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xContext, std::u16string_view(), xStream->getInputStream() );
266
267 if ( !m_aFilterName.isEmpty()
268 && ( m_aFilterName == "Calc MS Excel 2007 XML" || m_aFilterName == "Impress MS PowerPoint 2007 XML" || m_aFilterName == "MS Word 2007 XML"
269 || m_aFilterName == "MS Excel 97 Vorlage/Template" || m_aFilterName == "MS Word 97 Vorlage" ) )
270 {
271 uno::Reference< container::XNameAccess > xFilterFactory(
272 m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", m_xContext),
273 uno::UNO_QUERY_THROW );
274
275 OUString aDocServiceName;
276 uno::Any aFilterAnyData = xFilterFactory->getByName( m_aFilterName );
277 uno::Sequence< beans::PropertyValue > aFilterData;
278 if ( aFilterAnyData >>= aFilterData )
279 {
280 for ( beans::PropertyValue const & prop : std::as_const(aFilterData) )
281 if ( prop.Name == "DocumentService" )
282 prop.Value >>= aDocServiceName;
283 }
284
285 if ( !aDocServiceName.isEmpty() )
286 {
287 // create the model
288 uno::Sequence< uno::Any > aArguments{ uno::Any(
289 beans::NamedValue( "EmbeddedObject", uno::Any( true ))) };
290
291 uno::Reference< util::XCloseable > xDocument( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( aDocServiceName, aArguments, m_xContext ), uno::UNO_QUERY_THROW );
292 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
293 uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW );
294
295 // let the model behave as embedded one
296 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW );
297 uno::Sequence< beans::PropertyValue > aSeq{ comphelper::makePropertyValue(
298 "SetEmbedded", true) };
299 xModel->attachResource( OUString(), aSeq );
300
301 // load the model from the stream
302 uno::Sequence< beans::PropertyValue > aArgs{
303 comphelper::makePropertyValue("HierarchicalDocumentName", m_aEntryName),
304 comphelper::makePropertyValue("ReadOnly", true),
306 comphelper::makePropertyValue("URL", OUString( "private:stream" )),
307 comphelper::makePropertyValue("InputStream", xStream->getInputStream())
308 };
309
310 xSeekable->seek( 0 );
311 xLoadable->load( aArgs );
312
313 // the model is successfully loaded, create a new storage and store the model to the storage
314 uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName );
315 xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() );
316 xDocument->close( true );
317 uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW );
318 OUString aMediaType;
319 xStorProps->getPropertyValue("MediaType") >>= aMediaType;
320 xTmpStorage->dispose();
321
322 // look for the related embedded object factory
324 OUString aEmbedFactory;
325 if ( !aMediaType.isEmpty() )
326 aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType );
327
328 if ( aEmbedFactory.isEmpty() )
329 throw uno::RuntimeException("Failed to get OLE embedded object factory");
330
331 uno::Reference< uno::XInterface > xFact = m_xContext->getServiceManager()->createInstanceWithContext( aEmbedFactory, m_xContext );
332
333 uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW );
334
335 // now the object should be adjusted to become the wrapper
336 nStep = 1;
337 uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW );
338 xComp->dispose();
339 m_xObjectStream.clear();
340 m_nObjectState = -1;
341
342 nStep = 2;
343 aTmpStreamName = MoveToTemporarySubstream();
344
345 nStep = 3;
346 m_xParentStorage->renameElement( aStorageName, m_aEntryName );
347
348 nStep = 4;
349 m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW );
350
351 // remember parent document name to show in the title bar
352 m_xWrappedObject->setContainerName( m_aContainerName );
353
354 bResult = true; // the change is no more revertable
355 try
356 {
357 m_xParentStorage->removeElement( aTmpStreamName );
358 }
359 catch( const uno::Exception& )
360 {
361 // the success of the removing is not so important
362 }
363 }
364 }
365 }
366 catch( const uno::Exception& )
367 {
368 // repair the object if necessary
369 switch( nStep )
370 {
371 case 4:
372 case 3:
373 if ( !aTmpStreamName.isEmpty() && aTmpStreamName != m_aEntryName )
374 try
375 {
376 if ( m_xParentStorage->hasByName( m_aEntryName ) )
377 m_xParentStorage->removeElement( m_aEntryName );
378 m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName );
379 }
380 catch ( const uno::Exception& ex )
381 {
382 css::uno::Any anyEx = cppu::getCaughtException();
383 try {
384 close( true );
385 } catch( const uno::Exception& ) {}
386
387 m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without committing!
388 throw css::lang::WrappedTargetRuntimeException( ex.Message,
389 nullptr, anyEx ); // the repairing is not possible
390 }
391 [[fallthrough]];
392 case 2:
393 try
394 {
395 m_xObjectStream = m_xParentStorage->openStreamElement( m_aEntryName, m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
396 m_nObjectState = embed::EmbedStates::LOADED;
397 }
398 catch( const uno::Exception& ex )
399 {
400 css::uno::Any anyEx = cppu::getCaughtException();
401 try {
402 close( true );
403 } catch( const uno::Exception& ) {}
404
405 throw css::lang::WrappedTargetRuntimeException( ex.Message,
406 nullptr, anyEx ); // the repairing is not possible
407 }
408 [[fallthrough]];
409
410 case 1:
411 case 0:
412 if ( !aStorageName.isEmpty() )
413 try {
414 m_xParentStorage->removeElement( aStorageName );
415 } catch( const uno::Exception& ) { SAL_WARN( "embeddedobj.ole", "Can not remove temporary storage!" ); }
416 break;
417 }
418 }
419
420 if ( bResult )
421 {
422 // the conversion was done successfully, now the additional initializations should happen
423
425 m_xWrappedObject->setClientSite( m_xClientSite );
426 if ( m_xParent.is() )
427 {
428 uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY );
429 if ( xChild.is() )
430 xChild->setParent( m_xParent );
431 }
432
433 }
434
435 return bResult;
436}
437
438
439void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState )
440{
441 // begin wrapping related part ====================
442 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
443 if ( xWrappedObject.is() )
444 {
445 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
446 xWrappedObject->changeState( nNewState );
447 return;
448 }
449 // end wrapping related part ====================
450
451 ::osl::ResettableMutexGuard aGuard( m_aMutex );
452
453 if ( m_bDisposed )
454 throw lang::DisposedException(); // TODO
455
456 if ( m_nObjectState == -1 )
457 throw embed::WrongStateException( "The object has no persistence!",
458 static_cast< ::cppu::OWeakObject* >(this) );
459
460 // in case the object is already in requested state
461 if ( m_nObjectState == nNewState )
462 return;
463
464#ifdef _WIN32
465 if ( m_pOleComponent )
466 {
467 if ( m_nTargetState != -1 )
468 {
469 // means that the object is currently trying to reach the target state
470 throw embed::StateChangeInProgressException( OUString(),
471 uno::Reference< uno::XInterface >(),
473 }
474
475 TargetStateControl_Impl aControl( m_nTargetState, nNewState );
476
477 // TODO: additional verbs can be a problem, since nobody knows how the object
478 // will behave after activation
479
480 sal_Int32 nOldState = m_nObjectState;
481 aGuard.clear();
482 StateChangeNotification_Impl( true, nOldState, nNewState );
483 aGuard.reset();
484
485 try
486 {
487 if ( nNewState == embed::EmbedStates::LOADED )
488 {
489 // This means just closing of the current object
490 // If component can not be closed the object stays in loaded state
491 // and it holds reference to "incomplete" component
492 // If the object is switched to running state later
493 // the component will become "complete"
494
495 // the loaded state must be set before, because of notifications!
496 m_nObjectState = nNewState;
497
498 {
500 m_pOleComponent->CloseObject();
501 }
502
503 aGuard.clear();
504 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
505 aGuard.reset();
506 }
507 else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
508 {
509 if ( m_nObjectState == embed::EmbedStates::LOADED )
510 {
511 // if the target object is in loaded state and a different state is specified
512 // as a new one the object first must be switched to running state.
513
514 // the component can exist already in nonrunning state
515 // it can be created during loading to detect type of object
516 CreateOleComponentAndLoad_Impl( m_pOleComponent );
517
518 SwitchComponentToRunningState_Impl();
519 m_nObjectState = embed::EmbedStates::RUNNING;
520 aGuard.clear();
521 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
522 aGuard.reset();
523
525 {
526 aGuard.clear();
527 try {
529 m_bHasSizeToSet = false;
530 }
531 catch( const uno::Exception& ) {}
532 aGuard.reset();
533 }
534
535 if ( m_nObjectState == nNewState )
536 return;
537 }
538
539 // so now the object is either switched from Active to Running state or viceversa
540 // the notification about object state change will be done asynchronously
541 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
542 {
543 // execute OPEN verb, if object does not reach active state it is an object's problem
544 aGuard.clear();
545 m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
546 aGuard.reset();
547
548 // some objects do not allow to set the size even in running state
550 {
551 aGuard.clear();
552 try {
554 m_bHasSizeToSet = false;
555 }
556 catch( uno::Exception& ) {}
557 aGuard.reset();
558 }
559
560 m_nObjectState = nNewState;
561 }
562 else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
563 {
564 aGuard.clear();
565 m_pOleComponent->CloseObject();
566 m_pOleComponent->RunObject(); // Should not fail, the object already was active
567 aGuard.reset();
568 m_nObjectState = nNewState;
569 }
570 else
571 {
572 throw embed::UnreachableStateException();
573 }
574 }
575 else
576 throw embed::UnreachableStateException();
577 }
578 catch( uno::Exception& )
579 {
580 aGuard.clear();
581 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
582 throw;
583 }
584 }
585 else
586#endif
587 {
588 throw embed::UnreachableStateException();
589 }
590}
591
592
593uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
594{
595 // begin wrapping related part ====================
596 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
597 if ( xWrappedObject.is() )
598 {
599 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
600 return xWrappedObject->getReachableStates();
601 }
602 // end wrapping related part ====================
603
604 ::osl::MutexGuard aGuard( m_aMutex );
605 if ( m_bDisposed )
606 throw lang::DisposedException(); // TODO
607
608 if ( m_nObjectState == -1 )
609 throw embed::WrongStateException( "The object has no persistence!",
610 static_cast< ::cppu::OWeakObject* >(this) );
611
612#ifdef _WIN32
613 if ( m_pOleComponent )
614 {
615 if ( m_nObjectState == embed::EmbedStates::LOADED )
616 {
617 // the list of supported verbs can be retrieved only when object is in running state
618 throw embed::NeedsRunningStateException(); // TODO:
619 }
620
621 // the list of states can only be guessed based on standard verbs,
622 // since there is no way to detect what additional verbs do
623 return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
624 }
625 else
626#endif
627 {
628 return uno::Sequence< sal_Int32 >();
629 }
630}
631
632
634{
635 // begin wrapping related part ====================
636 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
637 if ( xWrappedObject.is() )
638 {
639 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
640 return xWrappedObject->getCurrentState();
641 }
642 // end wrapping related part ====================
643
644 ::osl::MutexGuard aGuard( m_aMutex );
645 if ( m_bDisposed )
646 throw lang::DisposedException(); // TODO
647
648 if ( m_nObjectState == -1 )
649 throw embed::WrongStateException( "The object has no persistence!",
650 static_cast< ::cppu::OWeakObject* >(this) );
651
652 // TODO: Shouldn't we ask object? ( I guess no )
653 return m_nObjectState;
654}
655
656namespace
657{
658 bool lcl_CopyStream(const uno::Reference<io::XInputStream>& xIn, const uno::Reference<io::XOutputStream>& xOut, sal_Int32 nMaxCopy = SAL_MAX_INT32)
659 {
660 if (nMaxCopy <= 0)
661 return false;
662
663 const sal_Int32 nChunkSize = 4096;
664 uno::Sequence< sal_Int8 > aData(nChunkSize);
665 sal_Int32 nTotalRead = 0;
666 sal_Int32 nRead;
667 do
668 {
669 if (nTotalRead + aData.getLength() > nMaxCopy)
670 {
671 aData.realloc(nMaxCopy - nTotalRead);
672 }
673 nRead = xIn->readBytes(aData, aData.getLength());
674 nTotalRead += nRead;
675 xOut->writeBytes(aData);
676 } while (nRead == nChunkSize && nTotalRead <= nMaxCopy);
677 return nTotalRead != 0;
678 }
679
680 uno::Reference < io::XStream > lcl_GetExtractedStream( OUString& rUrl,
681 const css::uno::Reference< css::uno::XComponentContext >& xContext,
682 const css::uno::Reference< css::io::XStream >& xObjectStream )
683 {
684 uno::Reference <io::XTempFile> xNativeTempFile(
685 io::TempFile::create(xContext),
686 uno::UNO_SET_THROW);
687 uno::Reference < io::XStream > xStream(xNativeTempFile);
688
689 uno::Sequence< uno::Any > aArgs{ uno::Any(xObjectStream),
690 uno::Any(true) }; // do not create copy
691 uno::Reference< container::XNameContainer > xNameContainer(
692 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
693 "com.sun.star.embed.OLESimpleStorage",
694 aArgs, xContext ), uno::UNO_QUERY_THROW );
695
696 //various stream names that can contain the real document contents for
697 //this object in a straightforward direct way
698 static const std::u16string_view aStreamNames[] =
699 {
700 u"CONTENTS",
701 u"Package",
702 u"EmbeddedOdf",
703 u"WordDocument",
704 u"Workbook",
705 u"PowerPoint Document"
706 };
707
708 bool bCopied = false;
709 for (size_t i = 0; i < std::size(aStreamNames) && !bCopied; ++i)
710 {
711 uno::Reference<io::XStream> xEmbeddedFile;
712 try
713 {
714 xNameContainer->getByName(OUString(aStreamNames[i])) >>= xEmbeddedFile;
715 }
716 catch (const container::NoSuchElementException&)
717 {
718 // ignore
719 }
720 bCopied = xEmbeddedFile.is() && lcl_CopyStream(xEmbeddedFile->getInputStream(), xStream->getOutputStream());
721 }
722
723 if (!bCopied)
724 {
725 uno::Reference< io::XStream > xOle10Native;
726 try
727 {
728 xNameContainer->getByName("\1Ole10Native") >>= xOle10Native;
729 }
730 catch (container::NoSuchElementException const&)
731 {
732 // ignore
733 }
734 if (xOle10Native.is())
735 {
736 const uno::Reference<io::XInputStream> xIn = xOle10Native->getInputStream();
737 xIn->skipBytes(4); //size of the entire stream minus 4 bytes
738 xIn->skipBytes(2); //word that represent the directory type
739 uno::Sequence< sal_Int8 > aData(1);
740 sal_Int32 nRead;
741 do
742 {
743 nRead = xIn->readBytes(aData, 1);
744 } while (nRead == 1 && aData[0] != 0); // file name plus extension of the attachment null terminated
745 do
746 {
747 nRead = xIn->readBytes(aData, 1);
748 } while (nRead == 1 && aData[0] != 0); // Fully Qualified File name with extension
749 xIn->skipBytes(1); //single byte
750 xIn->skipBytes(1); //single byte
751 xIn->skipBytes(2); //Word that represent the directory type
752 xIn->skipBytes(4); //len of string
753 do
754 {
755 nRead = xIn->readBytes(aData, 1);
756 } while (nRead == 1 && aData[0] != 0); // Actual string representing the file path
757 uno::Sequence< sal_Int8 > aLenData(4);
758 xIn->readBytes(aLenData, 4); //len of attachment
759 sal_uInt32 nLen = static_cast<sal_uInt32>(
760 (aLenData[0] & 0xFF) |
761 ((aLenData[1] & 0xFF) << 8) |
762 ((aLenData[2] & 0xFF) << 16) |
763 ((aLenData[3] & 0xFF) << 24));
764
765 bCopied = lcl_CopyStream(xIn, xStream->getOutputStream(), nLen);
766 }
767 }
768
769 uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
770 if (xSeekableStor.is())
771 xSeekableStor->seek(0);
772
773 if (!bCopied)
774 bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
775
776 if (bCopied)
777 {
778 xNativeTempFile->setRemoveFile(false);
779 rUrl = xNativeTempFile->getUri();
780
781 xNativeTempFile.clear();
782
783 uno::Reference < ucb::XSimpleFileAccess3 > xSimpleFileAccess(
784 ucb::SimpleFileAccess::create( xContext ) );
785
786 xSimpleFileAccess->setReadOnly(rUrl, true);
787 }
788 else
789 {
790 xNativeTempFile->setRemoveFile(true);
791 }
792
793 return xStream;
794 }
795
796 //Dump the objects content to a tempfile, just the "CONTENTS" stream if
797 //there is one for non-compound documents, otherwise the whole content.
798 //On success a file is returned which must be removed by the caller
799 OUString lcl_ExtractObject(const css::uno::Reference< css::uno::XComponentContext >& xContext,
800 const css::uno::Reference< css::io::XStream >& xObjectStream)
801 {
802 OUString sUrl;
803
804 // the solution is only active for Unix systems
805#ifndef _WIN32
806 lcl_GetExtractedStream(sUrl, xContext, xObjectStream);
807#else
808 (void) xContext;
809 (void) xObjectStream;
810#endif
811 return sUrl;
812 }
813
814 uno::Reference < io::XStream > lcl_ExtractObjectStream( const css::uno::Reference< css::uno::XComponentContext >& xContext,
815 const css::uno::Reference< css::io::XStream >& xObjectStream )
816 {
817 OUString sUrl;
818 return lcl_GetExtractedStream( sUrl, xContext, xObjectStream );
819 }
820}
821
822
823void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
824{
825 // begin wrapping related part ====================
826 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
827 if ( xWrappedObject.is() )
828 {
829 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
830 xWrappedObject->doVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN); // open content in the window not in-place
831 return;
832 }
833 // end wrapping related part ====================
834
835 ::osl::ResettableMutexGuard aGuard( m_aMutex );
836 if ( m_bDisposed )
837 throw lang::DisposedException(); // TODO
838
839 if ( m_nObjectState == -1 )
840 throw embed::WrongStateException( "The object has no persistence!",
841 static_cast< ::cppu::OWeakObject* >(this) );
842
843#ifdef _WIN32
844 if ( m_pOleComponent )
845 {
846 sal_Int32 nOldState = m_nObjectState;
847
848 // TODO/LATER detect target state here and do a notification
849 // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
850 if ( m_nObjectState == embed::EmbedStates::LOADED )
851 {
852 // if the target object is in loaded state
853 // it must be switched to running state to execute verb
854 aGuard.clear();
855 changeState( embed::EmbedStates::RUNNING );
856 aGuard.reset();
857 }
858
859 try {
860 if ( !m_pOleComponent )
861 throw uno::RuntimeException("Null reference to OLE component");
862
863 // ==== the STAMPIT related solution =============================
864 m_aVerbExecutionController.StartControlExecution();
865
866
867 m_pOleComponent->ExecuteVerb( nVerbID );
868 m_pOleComponent->SetHostName( m_aContainerName );
869
870 // ==== the STAMPIT related solution =============================
871 bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
872
873 // this workaround is implemented for STAMPIT object
874 // if object was modified during verb execution it is saved here
875 if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
876 SaveObject_Impl();
877
878 }
879 catch( uno::Exception& )
880 {
881 // ==== the STAMPIT related solution =============================
882 m_aVerbExecutionController.EndControlExecution_WasModified();
883
884
885 aGuard.clear();
886 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
887 throw;
888 }
889
890 }
891 else
892#endif
893 {
894 if ( nVerbID != -9 )
895 {
896
897 throw embed::UnreachableStateException();
898 }
899
900 // the workaround verb to show the object in case no server is available
901
902 // if it is possible, the object will be converted to OOo format
903 if ( !m_bTriedConversion )
904 {
905 m_bTriedConversion = true;
907 {
908 changeState( embed::EmbedStates::ACTIVE );
909 return;
910 }
911 }
912
913 if ( !m_xOwnView.is() && m_xObjectStream.is() && m_aFilterName != "Text" )
914 {
915 try {
916 uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
917 if ( xSeekable.is() )
918 xSeekable->seek( 0 );
919
920 m_xOwnView = new OwnView_Impl( m_xContext, m_xObjectStream->getInputStream() );
921 }
922 catch( uno::RuntimeException& )
923 {
924 throw;
925 }
926 catch (uno::Exception const&)
927 {
928 TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::doVerb: -9 fallback path:");
929 }
930 }
931
932 // it may be the OLE Storage, try to extract stream
933 if ( !m_xOwnView.is() && m_xObjectStream.is() && m_aFilterName == "Text" )
934 {
935 uno::Reference< io::XStream > xStream = lcl_ExtractObjectStream( m_xContext, m_xObjectStream );
936
937 if ( TryToConvertToOOo( xStream ) )
938 {
939 changeState( embed::EmbedStates::ACTIVE );
940 return;
941 }
942 }
943
944 if (!m_xOwnView.is() || !m_xOwnView->Open())
945 {
946 //Make a RO copy and see if the OS can find something to at
947 //least display the content for us
948 if (m_aTempDumpURL.isEmpty())
949 m_aTempDumpURL = lcl_ExtractObject(m_xContext, m_xObjectStream);
950
951 if (m_aTempDumpURL.isEmpty())
952 throw embed::UnreachableStateException();
953
954 uno::Reference< css::system::XSystemShellExecute > xSystemShellExecute(
955 css::system::SystemShellExecute::create( m_xContext ) );
956 xSystemShellExecute->execute(m_aTempDumpURL, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY);
957
958 }
959
960 }
961}
962
963
964uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
965{
966 // begin wrapping related part ====================
967 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
968 if ( xWrappedObject.is() )
969 {
970 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
971 return xWrappedObject->getSupportedVerbs();
972 }
973 // end wrapping related part ====================
974
975 ::osl::MutexGuard aGuard( m_aMutex );
976 if ( m_bDisposed )
977 throw lang::DisposedException(); // TODO
978
979 if ( m_nObjectState == -1 )
980 throw embed::WrongStateException( "The object has no persistence!",
981 static_cast< ::cppu::OWeakObject* >(this) );
982#ifdef _WIN32
983 if ( m_pOleComponent )
984 {
985 // registry could be used in this case
986 // if ( m_nObjectState == embed::EmbedStates::LOADED )
987 // {
988 // // the list of supported verbs can be retrieved only when object is in running state
989 // throw embed::NeedsRunningStateException(); // TODO:
990 // }
991
992 return m_pOleComponent->GetVerbList();
993 }
994 else
995#endif
996 {
997 // tdf#140079 Claim support for the OleEmbeddedObject::doVerb -9 fallback.
998 // So in SfxViewFrame::GetState_Impl in case SID_OBJECT hasVerbs is not
999 // empty, so that the doVerb attempt with -9 fallback is attempted
1000 uno::Sequence<embed::VerbDescriptor> aRet(1);
1001 aRet.getArray()[0].VerbID = -9;
1002 return aRet;
1003 }
1004}
1005
1006
1008 const uno::Reference< embed::XEmbeddedClient >& xClient )
1009{
1010 // begin wrapping related part ====================
1011 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1012 if ( xWrappedObject.is() )
1013 {
1014 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1015 xWrappedObject->setClientSite( xClient );
1016 return;
1017 }
1018 // end wrapping related part ====================
1019
1020 ::osl::MutexGuard aGuard( m_aMutex );
1021 if ( m_bDisposed )
1022 throw lang::DisposedException(); // TODO
1023
1024 if ( m_xClientSite != xClient)
1025 {
1026 if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
1027 throw embed::WrongStateException(
1028 "The client site can not be set currently!",
1029 static_cast< ::cppu::OWeakObject* >(this) );
1030
1031 m_xClientSite = xClient;
1032 }
1033}
1034
1035
1036uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
1037{
1038 // begin wrapping related part ====================
1039 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1040 if ( xWrappedObject.is() )
1041 {
1042 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1043 return xWrappedObject->getClientSite();
1044 }
1045 // end wrapping related part ====================
1046
1047 ::osl::MutexGuard aGuard( m_aMutex );
1048 if ( m_bDisposed )
1049 throw lang::DisposedException(); // TODO
1050
1051 if ( m_nObjectState == -1 )
1052 throw embed::WrongStateException( "The object has no persistence!",
1053 static_cast< ::cppu::OWeakObject* >(this) );
1054
1055 return m_xClientSite;
1056}
1057
1058
1060{
1061 // begin wrapping related part ====================
1062 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1063 if ( xWrappedObject.is() )
1064 {
1065 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1066 xWrappedObject->update();
1067 return;
1068 }
1069 // end wrapping related part ====================
1070
1071 ::osl::MutexGuard aGuard( m_aMutex );
1072 if ( m_bDisposed )
1073 throw lang::DisposedException(); // TODO
1074
1075 if ( m_nObjectState == -1 )
1076 throw embed::WrongStateException( "The object has no persistence!",
1077 static_cast< ::cppu::OWeakObject* >(this) );
1078
1079 if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
1080 {
1081 // TODO: update view representation
1082 }
1083 else
1084 {
1085 // the object must be up to date
1086 SAL_WARN_IF( m_nUpdateMode != embed::EmbedUpdateModes::ALWAYS_UPDATE, "embeddedobj.ole", "Unknown update mode!" );
1087 }
1088}
1089
1090
1091void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
1092{
1093 // begin wrapping related part ====================
1094 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1095 if ( xWrappedObject.is() )
1096 {
1097 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1098 xWrappedObject->setUpdateMode( nMode );
1099 return;
1100 }
1101 // end wrapping related part ====================
1102
1103 ::osl::MutexGuard aGuard( m_aMutex );
1104 if ( m_bDisposed )
1105 throw lang::DisposedException(); // TODO
1106
1107 if ( m_nObjectState == -1 )
1108 throw embed::WrongStateException( "The object has no persistence!",
1109 static_cast< ::cppu::OWeakObject* >(this) );
1110
1111 OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
1112 || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
1113 "Unknown update mode!" );
1114 m_nUpdateMode = nMode;
1115}
1116
1117
1118sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
1119 nAspect
1120)
1121{
1122 // begin wrapping related part ====================
1123 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1124 if ( xWrappedObject.is() )
1125 {
1126 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1127 return xWrappedObject->getStatus( nAspect );
1128 }
1129 // end wrapping related part ====================
1130
1131 ::osl::MutexGuard aGuard( m_aMutex );
1132 if ( m_bDisposed )
1133 throw lang::DisposedException(); // TODO
1134
1135 if ( m_nObjectState == -1 )
1136 throw embed::WrongStateException( "The object must be in running state!",
1137 static_cast< ::cppu::OWeakObject* >(this) );
1138
1139 sal_Int64 nResult = 0;
1140
1141#ifdef _WIN32
1142 if ( m_bGotStatus && m_nStatusAspect == nAspect )
1143 nResult = m_nStatus;
1144 else if ( m_pOleComponent )
1145 {
1146
1147 m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
1148 m_nStatusAspect = nAspect;
1149 m_bGotStatus = true;
1150 nResult = m_nStatus;
1151 }
1152#endif
1153
1154 // this implementation needs size to be provided after object loading/creating to work in optimal way
1155 return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
1156}
1157
1158
1159void SAL_CALL OleEmbeddedObject::setContainerName( const OUString& sName )
1160{
1161 // begin wrapping related part ====================
1162 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1163 if ( xWrappedObject.is() )
1164 {
1165 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1166 xWrappedObject->setContainerName( sName );
1167 return;
1168 }
1169 // end wrapping related part ====================
1170
1171 ::osl::MutexGuard aGuard( m_aMutex );
1172 if ( m_bDisposed )
1173 throw lang::DisposedException(); // TODO
1174
1176}
1177
1178
1179/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
css::uno::Reference< css::embed::XEmbeddedClient > m_xClientSite
Definition: oleembobj.hxx:141
OUString m_aContainerName
Definition: oleembobj.hxx:143
virtual void SAL_CALL doVerb(sal_Int32 nVerbID) override
Definition: oleembed.cxx:823
virtual css::uno::Sequence< css::embed::VerbDescriptor > SAL_CALL getSupportedVerbs() override
Definition: oleembed.cxx:964
rtl::Reference< OwnView_Impl > m_xOwnView
Definition: oleembobj.hxx:187
bool TryToConvertToOOo(const css::uno::Reference< css::io::XStream > &xStream)
Definition: oleembed.cxx:247
css::uno::Reference< css::embed::XStorage > m_xParentStorage
Definition: oleembobj.hxx:180
virtual void SAL_CALL update() override
Definition: oleembed.cxx:1059
css::uno::Reference< css::uno::XInterface > m_xParent
Definition: oleembobj.hxx:205
sal_Int64 m_nAspectToSet
Definition: oleembobj.hxx:169
::osl::Mutex m_aMutex
Definition: oleembobj.hxx:123
virtual css::uno::Reference< css::embed::XEmbeddedClient > SAL_CALL getClientSite() override
Definition: oleembed.cxx:1036
OUString m_aTempDumpURL
Definition: oleembobj.hxx:194
std::unique_ptr<::comphelper::OMultiTypeInterfaceContainerHelper2 > m_pInterfaceContainer
Definition: oleembobj.hxx:127
OUString m_aEntryName
Definition: oleembobj.hxx:179
sal_Int64 m_nStatusAspect
Definition: oleembobj.hxx:176
virtual void SAL_CALL close(sal_Bool DeliverOwnership) override
Definition: olemisc.cxx:431
virtual sal_Int64 SAL_CALL getStatus(sal_Int64 nAspect) override
Definition: oleembed.cxx:1118
virtual sal_Int32 SAL_CALL getCurrentState() override
Definition: oleembed.cxx:633
rtl::Reference< OleComponent > m_pOleComponent
Definition: oleembobj.hxx:125
void MoveListeners()
Definition: oleembed.cxx:122
sal_Int32 m_nTargetState
Definition: oleembobj.hxx:133
OUString MoveToTemporarySubstream()
Definition: oleembed.cxx:227
virtual css::uno::Sequence< sal_Int32 > SAL_CALL getReachableStates() override
Definition: oleembed.cxx:593
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: oleembobj.hxx:136
VerbExecutionController m_aVerbExecutionController
Definition: oleembobj.hxx:198
css::uno::Reference< css::io::XStream > m_xObjectStream
Definition: oleembobj.hxx:181
void GetRidOfComponent()
Definition: olemisc.cxx:224
sal_Int64 m_nStatus
Definition: oleembobj.hxx:175
css::uno::Reference< css::embed::XStorage > CreateTemporarySubstorage(OUString &o_aStorageName)
Definition: oleembed.cxx:203
sal_Int32 m_nObjectState
Definition: oleembobj.hxx:132
css::awt::Size m_aSizeToSet
Definition: oleembobj.hxx:168
css::uno::Reference< css::embed::XEmbeddedObject > m_xWrappedObject
Definition: oleembobj.hxx:201
sal_Int32 m_nUpdateMode
Definition: oleembobj.hxx:134
virtual void SAL_CALL setContainerName(const OUString &sName) override
Definition: oleembed.cxx:1159
virtual void SAL_CALL setUpdateMode(sal_Int32 nMode) override
Definition: oleembed.cxx:1091
OUString m_aFilterName
Definition: oleembobj.hxx:203
virtual void SAL_CALL setClientSite(const css::uno::Reference< css::embed::XEmbeddedClient > &xClient) override
Definition: oleembed.cxx:1007
virtual void SAL_CALL changeState(sal_Int32 nNewState) override
Definition: oleembed.cxx:439
static OUString GetFilterNameFromExtentionAndInStream(const css::uno::Reference< css::uno::XComponentContext > &xContext, std::u16string_view aNameWithExtention, const css::uno::Reference< css::io::XInputStream > &xInputStream)
Definition: ownview.cxx:175
OUString GetFactoryNameByMediaType(const OUString &aMediaType)
css::uno::XInterface * next()
#define TOOLS_WARN_EXCEPTION(area, stream)
float u
OUString sName
Sequence< PropertyValue > aArguments
OUString aName
Sequence< sal_Int8 > aSeq
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
constexpr OUStringLiteral aData
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
Any SAL_CALL getCaughtException()
int i
Object Value
Reference< XModel > xModel