nss: upgrade to release 3.73
[LibreOffice.git] / embeddedobj / source / msole / oleembed.cxx
blobce360817f25c65182f2cd8ab2a964bb53d8d5ae6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <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>
49 #include <cppuhelper/exc_hlp.hxx>
50 #include <cppuhelper/interfacecontainer.h>
51 #include <comphelper/mimeconfighelper.hxx>
52 #include <sal/log.hxx>
53 #include <tools/diagnose_ex.h>
56 #include <targetstatecontrol.hxx>
58 #include "ownview.hxx"
60 #if defined(_WIN32)
61 #include "olecomponent.hxx"
62 #endif
64 using namespace ::com::sun::star;
66 #ifdef _WIN32
68 void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
70 if ( !m_pOleComponent )
72 throw embed::UnreachableStateException();
74 try
76 m_pOleComponent->RunObject();
78 catch( const embed::UnreachableStateException& )
80 GetRidOfComponent();
81 throw;
83 catch( const embed::WrongStateException& )
85 GetRidOfComponent();
86 throw;
91 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl(
92 const uno::Sequence< embed::VerbDescriptor >& aVerbList )
94 uno::Sequence< sal_Int32 > aStates(2);
95 aStates[0] = embed::EmbedStates::LOADED;
96 aStates[1] = embed::EmbedStates::RUNNING;
97 for ( embed::VerbDescriptor const & vd : aVerbList )
98 if ( vd.VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
100 aStates.realloc(3);
101 aStates[2] = embed::EmbedStates::ACTIVE;
104 return aStates;
108 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState )
110 SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "Loaded object is switched to running state without verbs using!" );
112 // actually there will be only one verb
113 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
115 uno::Sequence< sal_Int32 > aVerbs( 1 );
116 aVerbs[0] = embed::EmbedVerbs::MS_OLEVERB_OPEN;
119 return uno::Sequence< sal_Int32 >();
121 #endif
123 void OleEmbeddedObject::MoveListeners()
125 if ( !m_pInterfaceContainer )
126 return;
128 // move state change listeners
130 ::cppu::OInterfaceContainerHelper* pStateChangeContainer =
131 m_pInterfaceContainer->getContainer( cppu::UnoType<embed::XStateChangeListener>::get());
132 if ( pStateChangeContainer != nullptr )
134 if ( m_xWrappedObject.is() )
136 ::cppu::OInterfaceIteratorHelper pIterator( *pStateChangeContainer );
137 while ( pIterator.hasMoreElements() )
141 m_xWrappedObject->addStateChangeListener( static_cast<embed::XStateChangeListener*>(pIterator.next()) );
143 catch( const uno::RuntimeException& )
145 pIterator.remove();
152 // move event listeners
154 ::cppu::OInterfaceContainerHelper* pEventContainer =
155 m_pInterfaceContainer->getContainer( cppu::UnoType<document::XEventListener>::get());
156 if ( pEventContainer != nullptr )
158 if ( m_xWrappedObject.is() )
160 ::cppu::OInterfaceIteratorHelper pIterator( *pEventContainer );
161 while ( pIterator.hasMoreElements() )
165 m_xWrappedObject->addEventListener( static_cast<document::XEventListener*>(pIterator.next()) );
167 catch( const uno::RuntimeException& )
169 pIterator.remove();
176 // move close listeners
178 ::cppu::OInterfaceContainerHelper* pCloseContainer =
179 m_pInterfaceContainer->getContainer( cppu::UnoType<util::XCloseListener>::get());
180 if ( pCloseContainer != nullptr )
182 if ( m_xWrappedObject.is() )
184 ::cppu::OInterfaceIteratorHelper pIterator( *pCloseContainer );
185 while ( pIterator.hasMoreElements() )
189 m_xWrappedObject->addCloseListener( static_cast<util::XCloseListener*>(pIterator.next()) );
191 catch( const uno::RuntimeException& )
193 pIterator.remove();
200 m_pInterfaceContainer.reset();
204 uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( OUString& o_aStorageName )
206 uno::Reference< embed::XStorage > xResult;
208 for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ )
210 OUString aName = OUString::number( nInd ) + "TMPSTOR" + m_aEntryName;
211 if ( !m_xParentStorage->hasByName( aName ) )
213 xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE );
214 o_aStorageName = aName;
218 if ( !xResult.is() )
220 o_aStorageName.clear();
221 throw uno::RuntimeException();
224 return xResult;
228 OUString OleEmbeddedObject::MoveToTemporarySubstream()
230 OUString aResult;
231 for ( sal_Int32 nInd = 0; nInd < 32000 && aResult.isEmpty(); nInd++ )
233 OUString aName = OUString::number( nInd ) + "TMPSTREAM" + m_aEntryName;
234 if ( !m_xParentStorage->hasByName( aName ) )
236 m_xParentStorage->renameElement( m_aEntryName, aName );
237 aResult = aName;
241 if ( aResult.isEmpty() )
242 throw uno::RuntimeException();
244 return aResult;
248 bool OleEmbeddedObject::TryToConvertToOOo( const uno::Reference< io::XStream >& xStream )
250 bool bResult = false;
252 OUString aStorageName;
253 OUString aTmpStreamName;
254 sal_Int32 nStep = 0;
256 if ( m_pOleComponent || m_bReadOnly )
257 return false;
261 changeState( embed::EmbedStates::LOADED );
263 // the stream must be seekable
264 uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY_THROW );
265 xSeekable->seek( 0 );
266 m_aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xContext, OUString(), xStream->getInputStream() );
268 if ( !m_aFilterName.isEmpty()
269 && ( m_aFilterName == "Calc MS Excel 2007 XML" || m_aFilterName == "Impress MS PowerPoint 2007 XML" || m_aFilterName == "MS Word 2007 XML"
270 || m_aFilterName == "MS Excel 97 Vorlage/Template" || m_aFilterName == "MS Word 97 Vorlage" ) )
272 uno::Reference< container::XNameAccess > xFilterFactory(
273 m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", m_xContext),
274 uno::UNO_QUERY_THROW );
276 OUString aDocServiceName;
277 uno::Any aFilterAnyData = xFilterFactory->getByName( m_aFilterName );
278 uno::Sequence< beans::PropertyValue > aFilterData;
279 if ( aFilterAnyData >>= aFilterData )
281 for ( beans::PropertyValue const & prop : std::as_const(aFilterData) )
282 if ( prop.Name == "DocumentService" )
283 prop.Value >>= aDocServiceName;
286 if ( !aDocServiceName.isEmpty() )
288 // create the model
289 uno::Sequence< uno::Any > aArguments(1);
290 aArguments[0] <<= beans::NamedValue( "EmbeddedObject", uno::makeAny( true ));
292 uno::Reference< util::XCloseable > xDocument( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( aDocServiceName, aArguments, m_xContext ), uno::UNO_QUERY_THROW );
293 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
294 uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW );
296 // let the model behave as embedded one
297 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW );
298 uno::Sequence< beans::PropertyValue > aSeq( 1 );
299 aSeq[0].Name = "SetEmbedded";
300 aSeq[0].Value <<= true;
301 xModel->attachResource( OUString(), aSeq );
303 // load the model from the stream
304 uno::Sequence< beans::PropertyValue > aArgs( 5 );
305 aArgs[0].Name = "HierarchicalDocumentName";
306 aArgs[0].Value <<= m_aEntryName;
307 aArgs[1].Name = "ReadOnly";
308 aArgs[1].Value <<= true;
309 aArgs[2].Name = "FilterName";
310 aArgs[2].Value <<= m_aFilterName;
311 aArgs[3].Name = "URL";
312 aArgs[3].Value <<= OUString( "private:stream" );
313 aArgs[4].Name = "InputStream";
314 aArgs[4].Value <<= xStream->getInputStream();
316 xSeekable->seek( 0 );
317 xLoadable->load( aArgs );
319 // the model is successfully loaded, create a new storage and store the model to the storage
320 uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName );
321 xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() );
322 xDocument->close( true );
323 uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW );
324 OUString aMediaType;
325 xStorProps->getPropertyValue("MediaType") >>= aMediaType;
326 xTmpStorage->dispose();
328 // look for the related embedded object factory
329 ::comphelper::MimeConfigurationHelper aConfigHelper( m_xContext );
330 OUString aEmbedFactory;
331 if ( !aMediaType.isEmpty() )
332 aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType );
334 if ( aEmbedFactory.isEmpty() )
335 throw uno::RuntimeException();
337 uno::Reference< uno::XInterface > xFact = m_xContext->getServiceManager()->createInstanceWithContext( aEmbedFactory, m_xContext );
339 uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW );
341 // now the object should be adjusted to become the wrapper
342 nStep = 1;
343 uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW );
344 xComp->dispose();
345 m_xObjectStream.clear();
346 m_nObjectState = -1;
348 nStep = 2;
349 aTmpStreamName = MoveToTemporarySubstream();
351 nStep = 3;
352 m_xParentStorage->renameElement( aStorageName, m_aEntryName );
354 nStep = 4;
355 m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW );
357 // remember parent document name to show in the title bar
358 m_xWrappedObject->setContainerName( m_aContainerName );
360 bResult = true; // the change is no more revertable
363 m_xParentStorage->removeElement( aTmpStreamName );
365 catch( const uno::Exception& )
367 // the success of the removing is not so important
372 catch( const uno::Exception& )
374 // repair the object if necessary
375 switch( nStep )
377 case 4:
378 case 3:
379 if ( !aTmpStreamName.isEmpty() && aTmpStreamName != m_aEntryName )
382 if ( m_xParentStorage->hasByName( m_aEntryName ) )
383 m_xParentStorage->removeElement( m_aEntryName );
384 m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName );
386 catch ( const uno::Exception& ex )
388 css::uno::Any anyEx = cppu::getCaughtException();
389 try {
390 close( true );
391 } catch( const uno::Exception& ) {}
393 m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without committing!
394 throw css::lang::WrappedTargetRuntimeException( ex.Message,
395 nullptr, anyEx ); // the repairing is not possible
397 [[fallthrough]];
398 case 2:
401 m_xObjectStream = m_xParentStorage->openStreamElement( m_aEntryName, m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
402 m_nObjectState = embed::EmbedStates::LOADED;
404 catch( const uno::Exception& ex )
406 css::uno::Any anyEx = cppu::getCaughtException();
407 try {
408 close( true );
409 } catch( const uno::Exception& ) {}
411 throw css::lang::WrappedTargetRuntimeException( ex.Message,
412 nullptr, anyEx ); // the repairing is not possible
414 [[fallthrough]];
416 case 1:
417 case 0:
418 if ( !aStorageName.isEmpty() )
419 try {
420 m_xParentStorage->removeElement( aStorageName );
421 } catch( const uno::Exception& ) { SAL_WARN( "embeddedobj.ole", "Can not remove temporary storage!" ); }
422 break;
426 if ( bResult )
428 // the conversion was done successfully, now the additional initializations should happen
430 MoveListeners();
431 m_xWrappedObject->setClientSite( m_xClientSite );
432 if ( m_xParent.is() )
434 uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY );
435 if ( xChild.is() )
436 xChild->setParent( m_xParent );
441 return bResult;
445 void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState )
447 // begin wrapping related part ====================
448 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
449 if ( xWrappedObject.is() )
451 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
452 xWrappedObject->changeState( nNewState );
453 return;
455 // end wrapping related part ====================
457 ::osl::ResettableMutexGuard aGuard( m_aMutex );
459 if ( m_bDisposed )
460 throw lang::DisposedException(); // TODO
462 if ( m_nObjectState == -1 )
463 throw embed::WrongStateException( "The object has no persistence!",
464 static_cast< ::cppu::OWeakObject* >(this) );
466 // in case the object is already in requested state
467 if ( m_nObjectState == nNewState )
468 return;
470 #ifdef _WIN32
471 if ( m_pOleComponent )
473 if ( m_nTargetState != -1 )
475 // means that the object is currently trying to reach the target state
476 throw embed::StateChangeInProgressException( OUString(),
477 uno::Reference< uno::XInterface >(),
478 m_nTargetState );
481 TargetStateControl_Impl aControl( m_nTargetState, nNewState );
483 // TODO: additional verbs can be a problem, since nobody knows how the object
484 // will behave after activation
486 sal_Int32 nOldState = m_nObjectState;
487 aGuard.clear();
488 StateChangeNotification_Impl( true, nOldState, nNewState );
489 aGuard.reset();
493 if ( nNewState == embed::EmbedStates::LOADED )
495 // This means just closing of the current object
496 // If component can not be closed the object stays in loaded state
497 // and it holds reference to "incomplete" component
498 // If the object is switched to running state later
499 // the component will become "complete"
501 // the loaded state must be set before, because of notifications!
502 m_nObjectState = nNewState;
505 VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
506 m_pOleComponent->CloseObject();
509 aGuard.clear();
510 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
511 aGuard.reset();
513 else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
515 if ( m_nObjectState == embed::EmbedStates::LOADED )
517 // if the target object is in loaded state and a different state is specified
518 // as a new one the object first must be switched to running state.
520 // the component can exist already in nonrunning state
521 // it can be created during loading to detect type of object
522 CreateOleComponentAndLoad_Impl( m_pOleComponent );
524 SwitchComponentToRunningState_Impl();
525 m_nObjectState = embed::EmbedStates::RUNNING;
526 aGuard.clear();
527 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
528 aGuard.reset();
530 if ( m_pOleComponent && m_bHasSizeToSet )
532 aGuard.clear();
533 try {
534 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
535 m_bHasSizeToSet = false;
537 catch( const uno::Exception& ) {}
538 aGuard.reset();
541 if ( m_nObjectState == nNewState )
542 return;
545 // so now the object is either switched from Active to Running state or viceversa
546 // the notification about object state change will be done asynchronously
547 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
549 // execute OPEN verb, if object does not reach active state it is an object's problem
550 aGuard.clear();
551 m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
552 aGuard.reset();
554 // some objects do not allow to set the size even in running state
555 if ( m_pOleComponent && m_bHasSizeToSet )
557 aGuard.clear();
558 try {
559 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
560 m_bHasSizeToSet = false;
562 catch( uno::Exception& ) {}
563 aGuard.reset();
566 m_nObjectState = nNewState;
568 else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
570 aGuard.clear();
571 m_pOleComponent->CloseObject();
572 m_pOleComponent->RunObject(); // Should not fail, the object already was active
573 aGuard.reset();
574 m_nObjectState = nNewState;
576 else
578 throw embed::UnreachableStateException();
581 else
582 throw embed::UnreachableStateException();
584 catch( uno::Exception& )
586 aGuard.clear();
587 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
588 throw;
591 else
592 #endif
594 throw embed::UnreachableStateException();
599 uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
601 // begin wrapping related part ====================
602 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
603 if ( xWrappedObject.is() )
605 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
606 return xWrappedObject->getReachableStates();
608 // end wrapping related part ====================
610 ::osl::MutexGuard aGuard( m_aMutex );
611 if ( m_bDisposed )
612 throw lang::DisposedException(); // TODO
614 if ( m_nObjectState == -1 )
615 throw embed::WrongStateException( "The object has no persistence!",
616 static_cast< ::cppu::OWeakObject* >(this) );
618 #ifdef _WIN32
619 if ( m_pOleComponent )
621 if ( m_nObjectState == embed::EmbedStates::LOADED )
623 // the list of supported verbs can be retrieved only when object is in running state
624 throw embed::NeedsRunningStateException(); // TODO:
627 // the list of states can only be guessed based on standard verbs,
628 // since there is no way to detect what additional verbs do
629 return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
631 else
632 #endif
634 return uno::Sequence< sal_Int32 >();
639 sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState()
641 // begin wrapping related part ====================
642 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
643 if ( xWrappedObject.is() )
645 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
646 return xWrappedObject->getCurrentState();
648 // end wrapping related part ====================
650 ::osl::MutexGuard aGuard( m_aMutex );
651 if ( m_bDisposed )
652 throw lang::DisposedException(); // TODO
654 if ( m_nObjectState == -1 )
655 throw embed::WrongStateException( "The object has no persistence!",
656 static_cast< ::cppu::OWeakObject* >(this) );
658 // TODO: Shouldn't we ask object? ( I guess no )
659 return m_nObjectState;
662 namespace
664 bool lcl_CopyStream(const uno::Reference<io::XInputStream>& xIn, const uno::Reference<io::XOutputStream>& xOut, sal_Int32 nMaxCopy = SAL_MAX_INT32)
666 if (nMaxCopy <= 0)
667 return false;
669 const sal_Int32 nChunkSize = 4096;
670 uno::Sequence< sal_Int8 > aData(nChunkSize);
671 sal_Int32 nTotalRead = 0;
672 sal_Int32 nRead;
675 if (nTotalRead + aData.getLength() > nMaxCopy)
677 aData.realloc(nMaxCopy - nTotalRead);
679 nRead = xIn->readBytes(aData, aData.getLength());
680 nTotalRead += nRead;
681 xOut->writeBytes(aData);
682 } while (nRead == nChunkSize && nTotalRead <= nMaxCopy);
683 return nTotalRead != 0;
686 uno::Reference < io::XStream > lcl_GetExtractedStream( OUString& rUrl,
687 const css::uno::Reference< css::uno::XComponentContext >& xContext,
688 const css::uno::Reference< css::io::XStream >& xObjectStream )
690 uno::Reference <beans::XPropertySet> xNativeTempFile(
691 io::TempFile::create(xContext),
692 uno::UNO_QUERY_THROW);
693 uno::Reference < io::XStream > xStream(xNativeTempFile, uno::UNO_QUERY_THROW);
695 uno::Sequence< uno::Any > aArgs( 2 );
696 aArgs[0] <<= xObjectStream;
697 aArgs[1] <<= true; // do not create copy
698 uno::Reference< container::XNameContainer > xNameContainer(
699 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
700 "com.sun.star.embed.OLESimpleStorage",
701 aArgs, xContext ), uno::UNO_QUERY_THROW );
703 //various stream names that can contain the real document contents for
704 //this object in a straightforward direct way
705 static const std::u16string_view aStreamNames[] =
707 u"CONTENTS",
708 u"Package",
709 u"EmbeddedOdf",
710 u"WordDocument",
711 u"Workbook",
712 u"PowerPoint Document"
715 bool bCopied = false;
716 for (size_t i = 0; i < SAL_N_ELEMENTS(aStreamNames) && !bCopied; ++i)
718 uno::Reference<io::XStream> xEmbeddedFile;
721 xNameContainer->getByName(aStreamNames[i]) >>= xEmbeddedFile;
723 catch (const container::NoSuchElementException&)
725 // ignore
727 bCopied = xEmbeddedFile.is() && lcl_CopyStream(xEmbeddedFile->getInputStream(), xStream->getOutputStream());
730 if (!bCopied)
732 uno::Reference< io::XStream > xOle10Native;
735 xNameContainer->getByName("\1Ole10Native") >>= xOle10Native;
737 catch (container::NoSuchElementException const&)
739 // ignore
741 if (xOle10Native.is())
743 const uno::Reference<io::XInputStream> xIn = xOle10Native->getInputStream();
744 xIn->skipBytes(4); //size of the entire stream minus 4 bytes
745 xIn->skipBytes(2); //word that represent the directory type
746 uno::Sequence< sal_Int8 > aData(1);
747 sal_Int32 nRead;
750 nRead = xIn->readBytes(aData, 1);
751 } while (nRead == 1 && aData[0] != 0); // file name plus extension of the attachment null terminated
754 nRead = xIn->readBytes(aData, 1);
755 } while (nRead == 1 && aData[0] != 0); // Fully Qualified File name with extension
756 xIn->skipBytes(1); //single byte
757 xIn->skipBytes(1); //single byte
758 xIn->skipBytes(2); //Word that represent the directory type
759 xIn->skipBytes(4); //len of string
762 nRead = xIn->readBytes(aData, 1);
763 } while (nRead == 1 && aData[0] != 0); // Actual string representing the file path
764 uno::Sequence< sal_Int8 > aLenData(4);
765 xIn->readBytes(aLenData, 4); //len of attachment
766 sal_uInt32 nLen = static_cast<sal_uInt32>(
767 (aLenData[0] & 0xFF) |
768 ((aLenData[1] & 0xFF) << 8) |
769 ((aLenData[2] & 0xFF) << 16) |
770 ((aLenData[3] & 0xFF) << 24));
772 bCopied = lcl_CopyStream(xIn, xStream->getOutputStream(), nLen);
776 uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
777 if (xSeekableStor.is())
778 xSeekableStor->seek(0);
780 if (!bCopied)
781 bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
783 if (bCopied)
785 xNativeTempFile->setPropertyValue("RemoveFile",
786 uno::makeAny(false));
787 uno::Any aUrl = xNativeTempFile->getPropertyValue("Uri");
788 aUrl >>= rUrl;
790 xNativeTempFile.clear();
792 uno::Reference < ucb::XSimpleFileAccess3 > xSimpleFileAccess(
793 ucb::SimpleFileAccess::create( xContext ) );
795 xSimpleFileAccess->setReadOnly(rUrl, true);
797 else
799 xNativeTempFile->setPropertyValue("RemoveFile",
800 uno::makeAny(true));
803 return xStream;
806 //Dump the objects content to a tempfile, just the "CONTENTS" stream if
807 //there is one for non-compound documents, otherwise the whole content.
808 //On success a file is returned which must be removed by the caller
809 OUString lcl_ExtractObject(const css::uno::Reference< css::uno::XComponentContext >& xContext,
810 const css::uno::Reference< css::io::XStream >& xObjectStream)
812 OUString sUrl;
814 // the solution is only active for Unix systems
815 #ifndef _WIN32
816 lcl_GetExtractedStream(sUrl, xContext, xObjectStream);
817 #else
818 (void) xContext;
819 (void) xObjectStream;
820 #endif
821 return sUrl;
824 uno::Reference < io::XStream > lcl_ExtractObjectStream( const css::uno::Reference< css::uno::XComponentContext >& xContext,
825 const css::uno::Reference< css::io::XStream >& xObjectStream )
827 OUString sUrl;
828 return lcl_GetExtractedStream( sUrl, xContext, xObjectStream );
833 void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
835 // begin wrapping related part ====================
836 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
837 if ( xWrappedObject.is() )
839 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
840 xWrappedObject->doVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN); // open content in the window not in-place
841 return;
843 // end wrapping related part ====================
845 ::osl::ResettableMutexGuard aGuard( m_aMutex );
846 if ( m_bDisposed )
847 throw lang::DisposedException(); // TODO
849 if ( m_nObjectState == -1 )
850 throw embed::WrongStateException( "The object has no persistence!",
851 static_cast< ::cppu::OWeakObject* >(this) );
853 #ifdef _WIN32
854 if ( m_pOleComponent )
856 sal_Int32 nOldState = m_nObjectState;
858 // TODO/LATER detect target state here and do a notification
859 // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
860 if ( m_nObjectState == embed::EmbedStates::LOADED )
862 // if the target object is in loaded state
863 // it must be switched to running state to execute verb
864 aGuard.clear();
865 changeState( embed::EmbedStates::RUNNING );
866 aGuard.reset();
869 try {
870 if ( !m_pOleComponent )
871 throw uno::RuntimeException();
873 // ==== the STAMPIT related solution =============================
874 m_aVerbExecutionController.StartControlExecution();
877 m_pOleComponent->ExecuteVerb( nVerbID );
878 m_pOleComponent->SetHostName( OUString(), m_aContainerName );
880 // ==== the STAMPIT related solution =============================
881 bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
883 // this workaround is implemented for STAMPIT object
884 // if object was modified during verb execution it is saved here
885 if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
886 SaveObject_Impl();
889 catch( uno::Exception& )
891 // ==== the STAMPIT related solution =============================
892 m_aVerbExecutionController.EndControlExecution_WasModified();
895 aGuard.clear();
896 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
897 throw;
901 else
902 #endif
904 if ( nVerbID != -9 )
907 throw embed::UnreachableStateException();
910 // the workaround verb to show the object in case no server is available
912 // if it is possible, the object will be converted to OOo format
913 if ( !m_bTriedConversion )
915 m_bTriedConversion = true;
916 if ( TryToConvertToOOo( m_xObjectStream ) )
918 changeState( embed::EmbedStates::ACTIVE );
919 return;
923 if ( !m_xOwnView.is() && m_xObjectStream.is() && m_aFilterName != "Text" )
925 try {
926 uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
927 if ( xSeekable.is() )
928 xSeekable->seek( 0 );
930 m_xOwnView = new OwnView_Impl( m_xContext, m_xObjectStream->getInputStream() );
932 catch( uno::RuntimeException& )
934 throw;
936 catch (uno::Exception const&)
938 TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::doVerb: -9 fallback path:");
942 // it may be the OLE Storage, try to extract stream
943 if ( !m_xOwnView.is() && m_xObjectStream.is() && m_aFilterName == "Text" )
945 uno::Reference< io::XStream > xStream = lcl_ExtractObjectStream( m_xContext, m_xObjectStream );
947 if ( TryToConvertToOOo( xStream ) )
949 changeState( embed::EmbedStates::ACTIVE );
950 return;
954 if (!m_xOwnView.is() || !m_xOwnView->Open())
956 //Make a RO copy and see if the OS can find something to at
957 //least display the content for us
958 if (m_aTempDumpURL.isEmpty())
959 m_aTempDumpURL = lcl_ExtractObject(m_xContext, m_xObjectStream);
961 if (m_aTempDumpURL.isEmpty())
962 throw embed::UnreachableStateException();
964 uno::Reference< css::system::XSystemShellExecute > xSystemShellExecute(
965 css::system::SystemShellExecute::create( m_xContext ) );
966 xSystemShellExecute->execute(m_aTempDumpURL, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY);
974 uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
976 // begin wrapping related part ====================
977 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
978 if ( xWrappedObject.is() )
980 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
981 return xWrappedObject->getSupportedVerbs();
983 // end wrapping related part ====================
985 ::osl::MutexGuard aGuard( m_aMutex );
986 if ( m_bDisposed )
987 throw lang::DisposedException(); // TODO
989 if ( m_nObjectState == -1 )
990 throw embed::WrongStateException( "The object has no persistence!",
991 static_cast< ::cppu::OWeakObject* >(this) );
992 #ifdef _WIN32
993 if ( m_pOleComponent )
995 // registry could be used in this case
996 // if ( m_nObjectState == embed::EmbedStates::LOADED )
997 // {
998 // // the list of supported verbs can be retrieved only when object is in running state
999 // throw embed::NeedsRunningStateException(); // TODO:
1000 // }
1002 return m_pOleComponent->GetVerbList();
1004 else
1005 #endif
1007 // tdf#140079 Claim support for the OleEmbeddedObject::doVerb -9 fallback.
1008 // So in SfxViewFrame::GetState_Impl in case SID_OBJECT hasVerbs is not
1009 // empty, so that the doVerb attempt with -9 fallback is attempted
1010 uno::Sequence<embed::VerbDescriptor> aRet(1);
1011 aRet[0].VerbID = -9;
1012 return aRet;
1017 void SAL_CALL OleEmbeddedObject::setClientSite(
1018 const uno::Reference< embed::XEmbeddedClient >& xClient )
1020 // begin wrapping related part ====================
1021 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1022 if ( xWrappedObject.is() )
1024 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1025 xWrappedObject->setClientSite( xClient );
1026 return;
1028 // end wrapping related part ====================
1030 ::osl::MutexGuard aGuard( m_aMutex );
1031 if ( m_bDisposed )
1032 throw lang::DisposedException(); // TODO
1034 if ( m_xClientSite != xClient)
1036 if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
1037 throw embed::WrongStateException(
1038 "The client site can not be set currently!",
1039 static_cast< ::cppu::OWeakObject* >(this) );
1041 m_xClientSite = xClient;
1046 uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
1048 // begin wrapping related part ====================
1049 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1050 if ( xWrappedObject.is() )
1052 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1053 return xWrappedObject->getClientSite();
1055 // end wrapping related part ====================
1057 ::osl::MutexGuard aGuard( m_aMutex );
1058 if ( m_bDisposed )
1059 throw lang::DisposedException(); // TODO
1061 if ( m_nObjectState == -1 )
1062 throw embed::WrongStateException( "The object has no persistence!",
1063 static_cast< ::cppu::OWeakObject* >(this) );
1065 return m_xClientSite;
1069 void SAL_CALL OleEmbeddedObject::update()
1071 // begin wrapping related part ====================
1072 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1073 if ( xWrappedObject.is() )
1075 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1076 xWrappedObject->update();
1077 return;
1079 // end wrapping related part ====================
1081 ::osl::MutexGuard aGuard( m_aMutex );
1082 if ( m_bDisposed )
1083 throw lang::DisposedException(); // TODO
1085 if ( m_nObjectState == -1 )
1086 throw embed::WrongStateException( "The object has no persistence!",
1087 static_cast< ::cppu::OWeakObject* >(this) );
1089 if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
1091 // TODO: update view representation
1093 else
1095 // the object must be up to date
1096 SAL_WARN_IF( m_nUpdateMode != embed::EmbedUpdateModes::ALWAYS_UPDATE, "embeddedobj.ole", "Unknown update mode!" );
1101 void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
1103 // begin wrapping related part ====================
1104 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1105 if ( xWrappedObject.is() )
1107 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1108 xWrappedObject->setUpdateMode( nMode );
1109 return;
1111 // end wrapping related part ====================
1113 ::osl::MutexGuard aGuard( m_aMutex );
1114 if ( m_bDisposed )
1115 throw lang::DisposedException(); // TODO
1117 if ( m_nObjectState == -1 )
1118 throw embed::WrongStateException( "The object has no persistence!",
1119 static_cast< ::cppu::OWeakObject* >(this) );
1121 OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
1122 || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
1123 "Unknown update mode!" );
1124 m_nUpdateMode = nMode;
1128 sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
1129 nAspect
1132 // begin wrapping related part ====================
1133 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1134 if ( xWrappedObject.is() )
1136 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1137 return xWrappedObject->getStatus( nAspect );
1139 // end wrapping related part ====================
1141 ::osl::MutexGuard aGuard( m_aMutex );
1142 if ( m_bDisposed )
1143 throw lang::DisposedException(); // TODO
1145 if ( m_nObjectState == -1 )
1146 throw embed::WrongStateException( "The object must be in running state!",
1147 static_cast< ::cppu::OWeakObject* >(this) );
1149 sal_Int64 nResult = 0;
1151 #ifdef _WIN32
1152 if ( m_bGotStatus && m_nStatusAspect == nAspect )
1153 nResult = m_nStatus;
1154 else if ( m_pOleComponent )
1157 m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
1158 m_nStatusAspect = nAspect;
1159 m_bGotStatus = true;
1160 nResult = m_nStatus;
1162 #endif
1164 // this implementation needs size to be provided after object loading/creating to work in optimal way
1165 return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
1169 void SAL_CALL OleEmbeddedObject::setContainerName( const OUString& sName )
1171 // begin wrapping related part ====================
1172 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1173 if ( xWrappedObject.is() )
1175 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1176 xWrappedObject->setContainerName( sName );
1177 return;
1179 // end wrapping related part ====================
1181 ::osl::MutexGuard aGuard( m_aMutex );
1182 if ( m_bDisposed )
1183 throw lang::DisposedException(); // TODO
1185 m_aContainerName = sName;
1189 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */