build fix
[LibreOffice.git] / embeddedobj / source / msole / oleembed.cxx
blob7fdf68d36bf338ba751fbb23de13237637057279
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 <oleembobj.hxx>
21 #include <com/sun/star/embed/EmbedStates.hpp>
22 #include <com/sun/star/embed/EmbedVerbs.hpp>
23 #include <com/sun/star/embed/EntryInitModes.hpp>
24 #include <com/sun/star/embed/XStorage.hpp>
25 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
27 #include <com/sun/star/embed/Aspects.hpp>
28 #include <com/sun/star/embed/NeedsRunningStateException.hpp>
29 #include <com/sun/star/embed/StateChangeInProgressException.hpp>
30 #include <com/sun/star/embed/EmbedMisc.hpp>
31 #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
32 #include <com/sun/star/io/TempFile.hpp>
33 #include <com/sun/star/io/XSeekable.hpp>
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <com/sun/star/beans/NamedValue.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/frame/XLoadable.hpp>
38 #include <com/sun/star/document/XStorageBasedDocument.hpp>
39 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
40 #include <com/sun/star/container/XNameAccess.hpp>
41 #include <com/sun/star/container/XNameContainer.hpp>
42 #include <com/sun/star/system/SystemShellExecute.hpp>
43 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
45 #include <cppuhelper/interfacecontainer.h>
46 #include <comphelper/processfactory.hxx>
47 #include <comphelper/mimeconfighelper.hxx>
48 #include <comphelper/storagehelper.hxx>
51 #include <targetstatecontrol.hxx>
53 #include "ownview.hxx"
55 #if defined(_WIN32)
56 #include <olecomponent.hxx>
57 #endif
59 using namespace ::com::sun::star;
61 #ifdef _WIN32
63 void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
65 if ( m_pOleComponent )
67 try
69 m_pOleComponent->RunObject();
71 catch( const embed::UnreachableStateException& )
73 GetRidOfComponent();
74 throw;
76 catch( const embed::WrongStateException& )
78 GetRidOfComponent();
79 throw;
82 else
84 throw embed::UnreachableStateException();
89 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl(
90 const uno::Sequence< embed::VerbDescriptor >& aVerbList )
92 uno::Sequence< sal_Int32 > aStates(2);
93 aStates[0] = embed::EmbedStates::LOADED;
94 aStates[1] = embed::EmbedStates::RUNNING;
95 for ( sal_Int32 nInd = 0; nInd < aVerbList.getLength(); nInd++ )
96 if ( aVerbList[nInd].VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
98 aStates.realloc(3);
99 aStates[2] = embed::EmbedStates::ACTIVE;
102 return aStates;
106 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState )
108 SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "Loaded object is switched to running state without verbs using!" );
110 // actually there will be only one verb
111 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
113 uno::Sequence< sal_Int32 > aVerbs( 1 );
114 aVerbs[0] = embed::EmbedVerbs::MS_OLEVERB_OPEN;
117 return uno::Sequence< sal_Int32 >();
119 #endif
121 void OleEmbeddedObject::MoveListeners()
123 if ( m_pInterfaceContainer )
125 // move state change listeners
127 ::cppu::OInterfaceContainerHelper* pStateChangeContainer =
128 m_pInterfaceContainer->getContainer( cppu::UnoType<embed::XStateChangeListener>::get());
129 if ( pStateChangeContainer != nullptr )
131 uno::Reference< embed::XStateChangeBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
132 if ( xWrappedObject.is() )
134 ::cppu::OInterfaceIteratorHelper pIterator( *pStateChangeContainer );
135 while ( pIterator.hasMoreElements() )
139 xWrappedObject->addStateChangeListener( static_cast<embed::XStateChangeListener*>(pIterator.next()) );
141 catch( const uno::RuntimeException& )
143 pIterator.remove();
150 // move event listeners
152 ::cppu::OInterfaceContainerHelper* pEventContainer =
153 m_pInterfaceContainer->getContainer( cppu::UnoType<document::XEventListener>::get());
154 if ( pEventContainer != nullptr )
156 uno::Reference< document::XEventBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
157 if ( xWrappedObject.is() )
159 ::cppu::OInterfaceIteratorHelper pIterator( *pEventContainer );
160 while ( pIterator.hasMoreElements() )
164 xWrappedObject->addEventListener( static_cast<document::XEventListener*>(pIterator.next()) );
166 catch( const uno::RuntimeException& )
168 pIterator.remove();
175 // move close listeners
177 ::cppu::OInterfaceContainerHelper* pCloseContainer =
178 m_pInterfaceContainer->getContainer( cppu::UnoType<util::XCloseListener>::get());
179 if ( pCloseContainer != nullptr )
181 uno::Reference< util::XCloseBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
182 if ( xWrappedObject.is() )
184 ::cppu::OInterfaceIteratorHelper pIterator( *pCloseContainer );
185 while ( pIterator.hasMoreElements() )
189 xWrappedObject->addCloseListener( static_cast<util::XCloseListener*>(pIterator.next()) );
191 catch( const uno::RuntimeException& )
193 pIterator.remove();
200 delete m_pInterfaceContainer;
201 m_pInterfaceContainer = nullptr;
206 uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( OUString& o_aStorageName )
208 uno::Reference< embed::XStorage > xResult;
210 for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ )
212 OUString aName = OUString::number( nInd ) + "TMPSTOR" + m_aEntryName;
213 if ( !m_xParentStorage->hasByName( aName ) )
215 xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE );
216 o_aStorageName = aName;
220 if ( !xResult.is() )
222 o_aStorageName.clear();
223 throw uno::RuntimeException();
226 return xResult;
230 OUString OleEmbeddedObject::MoveToTemporarySubstream()
232 OUString aResult;
233 for ( sal_Int32 nInd = 0; nInd < 32000 && aResult.isEmpty(); nInd++ )
235 OUString aName = OUString::number( nInd ) + "TMPSTREAM" + m_aEntryName;
236 if ( !m_xParentStorage->hasByName( aName ) )
238 m_xParentStorage->renameElement( m_aEntryName, aName );
239 aResult = aName;
243 if ( aResult.isEmpty() )
244 throw uno::RuntimeException();
246 return aResult;
250 bool OleEmbeddedObject::TryToConvertToOOo( const uno::Reference< io::XStream >& xStream )
252 bool bResult = false;
254 OUString aStorageName;
255 OUString aTmpStreamName;
256 sal_Int32 nStep = 0;
258 if ( m_pOleComponent || m_bReadOnly )
259 return false;
263 changeState( embed::EmbedStates::LOADED );
265 // the stream must be seekable
266 uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY_THROW );
267 xSeekable->seek( 0 );
268 m_aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xFactory, OUString(), xStream->getInputStream() );
270 if ( !m_aFilterName.isEmpty()
271 && ( m_aFilterName == "Calc MS Excel 2007 XML" || m_aFilterName == "Impress MS PowerPoint 2007 XML" || m_aFilterName == "MS Word 2007 XML"
272 || m_aFilterName == "MS Excel 97 Vorlage/Template" || m_aFilterName == "MS Word 97 Vorlage" ) )
274 uno::Reference< container::XNameAccess > xFilterFactory(
275 m_xFactory->createInstance("com.sun.star.document.FilterFactory"),
276 uno::UNO_QUERY_THROW );
278 OUString aDocServiceName;
279 uno::Any aFilterAnyData = xFilterFactory->getByName( m_aFilterName );
280 uno::Sequence< beans::PropertyValue > aFilterData;
281 if ( aFilterAnyData >>= aFilterData )
283 for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
284 if ( aFilterData[nInd].Name == "DocumentService" )
285 aFilterData[nInd].Value >>= aDocServiceName;
288 if ( !aDocServiceName.isEmpty() )
290 // create the model
291 uno::Sequence< uno::Any > aArguments(1);
292 aArguments[0] <<= beans::NamedValue( OUString( "EmbeddedObject" ), uno::makeAny( true ));
294 uno::Reference< util::XCloseable > xDocument( m_xFactory->createInstanceWithArguments( aDocServiceName, aArguments ), uno::UNO_QUERY_THROW );
295 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
296 uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW );
298 // let the model behave as embedded one
299 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW );
300 uno::Sequence< beans::PropertyValue > aSeq( 1 );
301 aSeq[0].Name = "SetEmbedded";
302 aSeq[0].Value <<= true;
303 xModel->attachResource( OUString(), aSeq );
305 // load the model from the stream
306 uno::Sequence< beans::PropertyValue > aArgs( 5 );
307 aArgs[0].Name = "HierarchicalDocumentName";
308 aArgs[0].Value <<= m_aEntryName;
309 aArgs[1].Name = "ReadOnly";
310 aArgs[1].Value <<= true;
311 aArgs[2].Name = "FilterName";
312 aArgs[2].Value <<= m_aFilterName;
313 aArgs[3].Name = "URL";
314 aArgs[3].Value <<= OUString( "private:stream" );
315 aArgs[4].Name = "InputStream";
316 aArgs[4].Value <<= xStream->getInputStream();
318 xSeekable->seek( 0 );
319 xLoadable->load( aArgs );
321 // the model is successfully loaded, create a new storage and store the model to the storage
322 uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName );
323 xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() );
324 xDocument->close( true );
325 uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW );
326 OUString aMediaType;
327 xStorProps->getPropertyValue("MediaType") >>= aMediaType;
328 xTmpStorage->dispose();
330 // look for the related embedded object factory
331 ::comphelper::MimeConfigurationHelper aConfigHelper( comphelper::getComponentContext(m_xFactory) );
332 OUString aEmbedFactory;
333 if ( !aMediaType.isEmpty() )
334 aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType );
336 if ( aEmbedFactory.isEmpty() )
337 throw uno::RuntimeException();
339 uno::Reference< uno::XInterface > xFact = m_xFactory->createInstance( aEmbedFactory );
341 uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW );
343 // now the object should be adjusted to become the wrapper
344 nStep = 1;
345 uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW );
346 xComp->dispose();
347 m_xObjectStream.clear();
348 m_nObjectState = -1;
350 nStep = 2;
351 aTmpStreamName = MoveToTemporarySubstream();
353 nStep = 3;
354 m_xParentStorage->renameElement( aStorageName, m_aEntryName );
356 nStep = 4;
357 m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW );
359 // remember parent document name to show in the title bar
360 m_xWrappedObject->setContainerName( m_aContainerName );
362 bResult = true; // the change is no more revertable
365 m_xParentStorage->removeElement( aTmpStreamName );
367 catch( const uno::Exception& )
369 // the success of the removing is not so important
374 catch( const uno::Exception& )
376 // repair the object if necessary
377 switch( nStep )
379 case 4:
380 case 3:
381 if ( !aTmpStreamName.isEmpty() && aTmpStreamName != m_aEntryName )
384 if ( m_xParentStorage->hasByName( m_aEntryName ) )
385 m_xParentStorage->removeElement( m_aEntryName );
386 m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName );
388 catch ( const uno::Exception& )
390 try {
391 close( true );
392 } catch( const uno::Exception& ) {}
394 m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without committing!
395 throw uno::RuntimeException(); // the repairing is not possible
397 SAL_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& )
406 try {
407 close( true );
408 } catch( const uno::Exception& ) {}
410 throw uno::RuntimeException(); // the repairing is not possible
412 SAL_FALLTHROUGH;
414 case 1:
415 case 0:
416 if ( !aStorageName.isEmpty() )
417 try {
418 m_xParentStorage->removeElement( aStorageName );
419 } catch( const uno::Exception& ) { SAL_WARN( "embeddedobj.ole", "Can not remove temporary storage!" ); }
420 break;
424 if ( bResult )
426 // the conversion was done successfully, now the additional initializations should happen
428 MoveListeners();
429 m_xWrappedObject->setClientSite( m_xClientSite );
430 if ( m_xParent.is() )
432 uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY );
433 if ( xChild.is() )
434 xChild->setParent( m_xParent );
439 return bResult;
443 void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState )
444 throw ( embed::UnreachableStateException,
445 embed::WrongStateException,
446 uno::Exception,
447 uno::RuntimeException, std::exception )
449 // begin wrapping related part ====================
450 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
451 if ( xWrappedObject.is() )
453 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
454 xWrappedObject->changeState( nNewState );
455 return;
457 // end wrapping related part ====================
459 ::osl::ResettableMutexGuard aGuard( m_aMutex );
461 if ( m_bDisposed )
462 throw lang::DisposedException(); // TODO
464 if ( m_nObjectState == -1 )
465 throw embed::WrongStateException( "The object has no persistence!",
466 static_cast< ::cppu::OWeakObject* >(this) );
468 // in case the object is already in requested state
469 if ( m_nObjectState == nNewState )
470 return;
472 #ifdef _WIN32
473 if ( m_pOleComponent )
475 if ( m_nTargetState != -1 )
477 // means that the object is currently trying to reach the target state
478 throw embed::StateChangeInProgressException( OUString(),
479 uno::Reference< uno::XInterface >(),
480 m_nTargetState );
483 TargetStateControl_Impl aControl( m_nTargetState, nNewState );
485 // TODO: additional verbs can be a problem, since nobody knows how the object
486 // will behave after activation
488 sal_Int32 nOldState = m_nObjectState;
489 aGuard.clear();
490 StateChangeNotification_Impl( true, nOldState, nNewState );
491 aGuard.reset();
495 if ( nNewState == embed::EmbedStates::LOADED )
497 // This means just closing of the current object
498 // If component can not be closed the object stays in loaded state
499 // and it holds reference to "incomplete" component
500 // If the object is switched to running state later
501 // the component will become "complete"
503 // the loaded state must be set before, because of notifications!
504 m_nObjectState = nNewState;
507 VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
508 m_pOleComponent->CloseObject();
511 aGuard.clear();
512 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
513 aGuard.reset();
515 else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
517 if ( m_nObjectState == embed::EmbedStates::LOADED )
519 // if the target object is in loaded state and a different state is specified
520 // as a new one the object first must be switched to running state.
522 // the component can exist already in nonrunning state
523 // it can be created during loading to detect type of object
524 CreateOleComponentAndLoad_Impl( m_pOleComponent );
526 SwitchComponentToRunningState_Impl();
527 m_nObjectState = embed::EmbedStates::RUNNING;
528 aGuard.clear();
529 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
530 aGuard.reset();
532 if ( m_pOleComponent && m_bHasSizeToSet )
534 aGuard.clear();
535 try {
536 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
537 m_bHasSizeToSet = false;
539 catch( const uno::Exception& ) {}
540 aGuard.reset();
543 if ( m_nObjectState == nNewState )
544 return;
547 // so now the object is either switched from Active to Running state or vise versa
548 // the notification about object state change will be done asynchronously
549 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
551 // execute OPEN verb, if object does not reach active state it is an object's problem
552 aGuard.clear();
553 m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
554 aGuard.reset();
556 // some objects do not allow to set the size even in running state
557 if ( m_pOleComponent && m_bHasSizeToSet )
559 aGuard.clear();
560 try {
561 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
562 m_bHasSizeToSet = false;
564 catch( uno::Exception& ) {}
565 aGuard.reset();
568 m_nObjectState = nNewState;
570 else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
572 aGuard.clear();
573 m_pOleComponent->CloseObject();
574 m_pOleComponent->RunObject(); // Should not fail, the object already was active
575 aGuard.reset();
576 m_nObjectState = nNewState;
578 else
580 throw embed::UnreachableStateException();
583 else
584 throw embed::UnreachableStateException();
586 catch( uno::Exception& )
588 aGuard.clear();
589 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
590 throw;
593 else
594 #endif
596 throw embed::UnreachableStateException();
601 uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
602 throw ( embed::WrongStateException,
603 uno::RuntimeException, std::exception )
605 // begin wrapping related part ====================
606 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
607 if ( xWrappedObject.is() )
609 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
610 return xWrappedObject->getReachableStates();
612 // end wrapping related part ====================
614 ::osl::MutexGuard aGuard( m_aMutex );
615 if ( m_bDisposed )
616 throw lang::DisposedException(); // TODO
618 if ( m_nObjectState == -1 )
619 throw embed::WrongStateException( "The object has no persistence!",
620 static_cast< ::cppu::OWeakObject* >(this) );
622 #ifdef _WIN32
623 if ( m_pOleComponent )
625 if ( m_nObjectState == embed::EmbedStates::LOADED )
627 // the list of supported verbs can be retrieved only when object is in running state
628 throw embed::NeedsRunningStateException(); // TODO:
631 // the list of states can only be guessed based on standard verbs,
632 // since there is no way to detect what additional verbs do
633 return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
635 else
636 #endif
638 return uno::Sequence< sal_Int32 >();
643 sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState()
644 throw ( embed::WrongStateException,
645 uno::RuntimeException, std::exception )
647 // begin wrapping related part ====================
648 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
649 if ( xWrappedObject.is() )
651 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
652 return xWrappedObject->getCurrentState();
654 // end wrapping related part ====================
656 ::osl::MutexGuard aGuard( m_aMutex );
657 if ( m_bDisposed )
658 throw lang::DisposedException(); // TODO
660 if ( m_nObjectState == -1 )
661 throw embed::WrongStateException( "The object has no persistence!",
662 static_cast< ::cppu::OWeakObject* >(this) );
664 // TODO: Shouldn't we ask object? ( I guess no )
665 return m_nObjectState;
668 namespace
670 bool lcl_CopyStream(const uno::Reference<io::XInputStream>& xIn, const uno::Reference<io::XOutputStream>& xOut, sal_Int32 nMaxCopy = SAL_MAX_INT32)
672 if (nMaxCopy <= 0)
673 return false;
675 const sal_Int32 nChunkSize = 4096;
676 uno::Sequence< sal_Int8 > aData(nChunkSize);
677 sal_Int32 nTotalRead = 0;
678 sal_Int32 nRead;
681 if (nTotalRead + aData.getLength() > nMaxCopy)
683 aData.realloc(nMaxCopy - nTotalRead);
685 nRead = xIn->readBytes(aData, aData.getLength());
686 nTotalRead += nRead;
687 xOut->writeBytes(aData);
688 } while (nRead == nChunkSize && nTotalRead <= nMaxCopy);
689 return nTotalRead != 0;
692 uno::Reference < io::XStream > lcl_GetExtractedStream( OUString& rUrl,
693 const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory,
694 const css::uno::Reference< css::io::XStream >& xObjectStream )
696 uno::Reference <beans::XPropertySet> xNativeTempFile(
697 io::TempFile::create(comphelper::getComponentContext(xFactory)),
698 uno::UNO_QUERY_THROW);
699 uno::Reference < io::XStream > xStream(xNativeTempFile, uno::UNO_QUERY_THROW);
701 uno::Sequence< uno::Any > aArgs( 2 );
702 aArgs[0] <<= xObjectStream;
703 aArgs[1] <<= true; // do not create copy
704 uno::Reference< container::XNameContainer > xNameContainer(
705 xFactory->createInstanceWithArguments(
706 "com.sun.star.embed.OLESimpleStorage",
707 aArgs ), uno::UNO_QUERY_THROW );
709 //various stream names that can contain the real document contents for
710 //this object in a straightforward direct way
711 static const OUStringLiteral aStreamNames[] =
713 OUStringLiteral("CONTENTS"),
714 OUStringLiteral("Package"),
715 OUStringLiteral("EmbeddedOdf"),
716 OUStringLiteral("WordDocument"),
717 OUStringLiteral("Workbook"),
718 OUStringLiteral("PowerPoint Document")
721 bool bCopied = false;
722 for (size_t i = 0; i < SAL_N_ELEMENTS(aStreamNames) && !bCopied; ++i)
724 uno::Reference<io::XStream> xEmbeddedFile;
727 xNameContainer->getByName(aStreamNames[i]) >>= xEmbeddedFile;
729 catch (const container::NoSuchElementException&)
731 // ignore
733 bCopied = xEmbeddedFile.is() && lcl_CopyStream(xEmbeddedFile->getInputStream(), xStream->getOutputStream());
736 if (!bCopied)
738 uno::Reference< io::XStream > xOle10Native;
741 xNameContainer->getByName("\1Ole10Native") >>= xOle10Native;
743 catch (container::NoSuchElementException const&)
745 // ignore
747 if (xOle10Native.is())
749 const uno::Reference<io::XInputStream> xIn = xOle10Native->getInputStream();
750 xIn->skipBytes(4); //size of the entire stream minus 4 bytes
751 xIn->skipBytes(2); //word that represent the directory type
752 uno::Sequence< sal_Int8 > aData(1);
753 sal_Int32 nRead;
756 nRead = xIn->readBytes(aData, 1);
757 } while (nRead == 1 && aData[0] != 0); // file name plus extension of the attachment null terminated
760 nRead = xIn->readBytes(aData, 1);
761 } while (nRead == 1 && aData[0] != 0); // Fully Qualified File name with extension
762 xIn->skipBytes(1); //single byte
763 xIn->skipBytes(1); //single byte
764 xIn->skipBytes(2); //Word that represent the directory type
765 xIn->skipBytes(4); //len of string
768 nRead = xIn->readBytes(aData, 1);
769 } while (nRead == 1 && aData[0] != 0); // Actual string representing the file path
770 uno::Sequence< sal_Int8 > aLenData(4);
771 xIn->readBytes(aLenData, 4); //len of attachment
772 sal_uInt32 nLen = static_cast<sal_uInt32>(
773 (aLenData[0] & 0xFF) |
774 ((aLenData[1] & 0xFF) << 8) |
775 ((aLenData[2] & 0xFF) << 16) |
776 ((aLenData[3] & 0xFF) << 24));
778 bCopied = lcl_CopyStream(xIn, xStream->getOutputStream(), nLen);
782 uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
783 if (xSeekableStor.is())
784 xSeekableStor->seek(0);
786 if (!bCopied)
787 bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
789 if (bCopied)
791 xNativeTempFile->setPropertyValue("RemoveFile",
792 uno::makeAny(false));
793 uno::Any aUrl = xNativeTempFile->getPropertyValue("Uri");
794 aUrl >>= rUrl;
796 xNativeTempFile.clear();
798 uno::Reference < ucb::XSimpleFileAccess3 > xSimpleFileAccess(
799 ucb::SimpleFileAccess::create( comphelper::getComponentContext(xFactory) ) );
801 xSimpleFileAccess->setReadOnly(rUrl, true);
803 else
805 xNativeTempFile->setPropertyValue("RemoveFile",
806 uno::makeAny(true));
809 return xStream;
812 //Dump the objects content to a tempfile, just the "CONTENTS" stream if
813 //there is one for non-compound documents, otherwise the whole content.
814 //On success a file is returned which must be removed by the caller
815 OUString lcl_ExtractObject(const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory,
816 const css::uno::Reference< css::io::XStream >& xObjectStream)
818 OUString sUrl;
820 // the solution is only active for Unix systems
821 #ifndef _WIN32
822 lcl_GetExtractedStream(sUrl, xFactory, xObjectStream);
823 #else
824 (void) xFactory;
825 (void) xObjectStream;
826 #endif
827 return sUrl;
830 uno::Reference < io::XStream > lcl_ExtractObjectStream( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory,
831 const css::uno::Reference< css::io::XStream >& xObjectStream )
833 OUString sUrl;
834 return lcl_GetExtractedStream( sUrl, xFactory, xObjectStream );
839 void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
840 throw ( lang::IllegalArgumentException,
841 embed::WrongStateException,
842 embed::UnreachableStateException,
843 uno::Exception,
844 uno::RuntimeException, std::exception )
846 // begin wrapping related part ====================
847 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
848 if ( xWrappedObject.is() )
850 // open content in the window not in-place
851 nVerbID = embed::EmbedVerbs::MS_OLEVERB_OPEN;
853 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
854 xWrappedObject->doVerb( nVerbID );
855 return;
857 // end wrapping related part ====================
859 ::osl::ResettableMutexGuard aGuard( m_aMutex );
860 if ( m_bDisposed )
861 throw lang::DisposedException(); // TODO
863 if ( m_nObjectState == -1 )
864 throw embed::WrongStateException( "The object has no persistence!",
865 static_cast< ::cppu::OWeakObject* >(this) );
867 #ifdef _WIN32
868 if ( m_pOleComponent )
870 sal_Int32 nOldState = m_nObjectState;
872 // TODO/LATER detect target state here and do a notification
873 // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
874 if ( m_nObjectState == embed::EmbedStates::LOADED )
876 // if the target object is in loaded state
877 // it must be switched to running state to execute verb
878 aGuard.clear();
879 changeState( embed::EmbedStates::RUNNING );
880 aGuard.reset();
883 try {
884 if ( !m_pOleComponent )
885 throw uno::RuntimeException();
887 // ==== the STAMPIT related solution =============================
888 m_aVerbExecutionController.StartControlExecution();
891 m_pOleComponent->ExecuteVerb( nVerbID );
892 m_pOleComponent->SetHostName( OUString(), m_aContainerName );
894 // ==== the STAMPIT related solution =============================
895 bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
897 // this workaround is implemented for STAMPIT object
898 // if object was modified during verb execution it is saved here
899 if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
900 SaveObject_Impl();
903 catch( uno::Exception& )
905 // ==== the STAMPIT related solution =============================
906 m_aVerbExecutionController.EndControlExecution_WasModified();
909 aGuard.clear();
910 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
911 throw;
915 else
916 #endif
918 if ( nVerbID == -9 )
920 // the workaround verb to show the object in case no server is available
922 // if it is possible, the object will be converted to OOo format
923 if ( !m_bTriedConversion )
925 m_bTriedConversion = true;
926 if ( TryToConvertToOOo( m_xObjectStream ) )
928 changeState( embed::EmbedStates::ACTIVE );
929 return;
933 if ( !m_pOwnView && m_xObjectStream.is() && m_aFilterName != "Text" )
935 try {
936 uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
937 if ( xSeekable.is() )
938 xSeekable->seek( 0 );
940 m_pOwnView = new OwnView_Impl( m_xFactory, m_xObjectStream->getInputStream() );
941 m_pOwnView->acquire();
943 catch( uno::RuntimeException& )
945 throw;
947 catch (uno::Exception const& e)
949 SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::doVerb: "
950 "-9 fallback path: exception caught: " << e.Message);
954 // it may be the OLE Storage, try to extract stream
955 if ( !m_pOwnView && m_xObjectStream.is() && m_aFilterName == "Text" )
957 uno::Reference< io::XStream > xStream = lcl_ExtractObjectStream( m_xFactory, m_xObjectStream );
959 if ( TryToConvertToOOo( xStream ) )
961 changeState( embed::EmbedStates::ACTIVE );
962 return;
966 if (!m_pOwnView || !m_pOwnView->Open())
968 //Make a RO copy and see if the OS can find something to at
969 //least display the content for us
970 if (m_aTempDumpURL.isEmpty())
971 m_aTempDumpURL = lcl_ExtractObject(m_xFactory, m_xObjectStream);
973 if (!m_aTempDumpURL.isEmpty())
975 uno::Reference< css::system::XSystemShellExecute > xSystemShellExecute(
976 css::system::SystemShellExecute::create(comphelper::getComponentContext(m_xFactory)) );
977 xSystemShellExecute->execute(m_aTempDumpURL, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY);
979 else
980 throw embed::UnreachableStateException();
983 else
986 throw embed::UnreachableStateException();
992 uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
993 throw ( embed::WrongStateException,
994 uno::RuntimeException, std::exception )
996 // begin wrapping related part ====================
997 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
998 if ( xWrappedObject.is() )
1000 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1001 return xWrappedObject->getSupportedVerbs();
1003 // end wrapping related part ====================
1005 ::osl::MutexGuard aGuard( m_aMutex );
1006 if ( m_bDisposed )
1007 throw lang::DisposedException(); // TODO
1009 if ( m_nObjectState == -1 )
1010 throw embed::WrongStateException( "The object has no persistence!",
1011 static_cast< ::cppu::OWeakObject* >(this) );
1012 #ifdef _WIN32
1013 if ( m_pOleComponent )
1015 // registry could be used in this case
1016 // if ( m_nObjectState == embed::EmbedStates::LOADED )
1017 // {
1018 // // the list of supported verbs can be retrieved only when object is in running state
1019 // throw embed::NeedsRunningStateException(); // TODO:
1020 // }
1022 return m_pOleComponent->GetVerbList();
1024 else
1025 #endif
1027 return uno::Sequence< embed::VerbDescriptor >();
1032 void SAL_CALL OleEmbeddedObject::setClientSite(
1033 const uno::Reference< embed::XEmbeddedClient >& xClient )
1034 throw ( embed::WrongStateException,
1035 uno::RuntimeException, std::exception )
1037 // begin wrapping related part ====================
1038 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1039 if ( xWrappedObject.is() )
1041 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1042 xWrappedObject->setClientSite( xClient );
1043 return;
1045 // end wrapping related part ====================
1047 ::osl::MutexGuard aGuard( m_aMutex );
1048 if ( m_bDisposed )
1049 throw lang::DisposedException(); // TODO
1051 if ( m_xClientSite != xClient)
1053 if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
1054 throw embed::WrongStateException(
1055 "The client site can not be set currently!",
1056 static_cast< ::cppu::OWeakObject* >(this) );
1058 m_xClientSite = xClient;
1063 uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
1064 throw ( embed::WrongStateException,
1065 uno::RuntimeException, std::exception )
1067 // begin wrapping related part ====================
1068 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1069 if ( xWrappedObject.is() )
1071 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1072 return xWrappedObject->getClientSite();
1074 // end wrapping related part ====================
1076 ::osl::MutexGuard aGuard( m_aMutex );
1077 if ( m_bDisposed )
1078 throw lang::DisposedException(); // TODO
1080 if ( m_nObjectState == -1 )
1081 throw embed::WrongStateException( "The object has no persistence!",
1082 static_cast< ::cppu::OWeakObject* >(this) );
1084 return m_xClientSite;
1088 void SAL_CALL OleEmbeddedObject::update()
1089 throw ( embed::WrongStateException,
1090 uno::Exception,
1091 uno::RuntimeException, std::exception )
1093 // begin wrapping related part ====================
1094 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1095 if ( xWrappedObject.is() )
1097 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1098 xWrappedObject->update();
1099 return;
1101 // end wrapping related part ====================
1103 ::osl::MutexGuard aGuard( m_aMutex );
1104 if ( m_bDisposed )
1105 throw lang::DisposedException(); // TODO
1107 if ( m_nObjectState == -1 )
1108 throw embed::WrongStateException( "The object has no persistence!",
1109 static_cast< ::cppu::OWeakObject* >(this) );
1111 if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
1113 // TODO: update view representation
1115 else
1117 // the object must be up to date
1118 SAL_WARN_IF( m_nUpdateMode != embed::EmbedUpdateModes::ALWAYS_UPDATE, "embeddedobj.ole", "Unknown update mode!" );
1123 void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
1124 throw ( embed::WrongStateException,
1125 uno::RuntimeException, std::exception )
1127 // begin wrapping related part ====================
1128 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1129 if ( xWrappedObject.is() )
1131 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1132 xWrappedObject->setUpdateMode( nMode );
1133 return;
1135 // end wrapping related part ====================
1137 ::osl::MutexGuard aGuard( m_aMutex );
1138 if ( m_bDisposed )
1139 throw lang::DisposedException(); // TODO
1141 if ( m_nObjectState == -1 )
1142 throw embed::WrongStateException( "The object has no persistence!",
1143 static_cast< ::cppu::OWeakObject* >(this) );
1145 OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
1146 || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
1147 "Unknown update mode!\n" );
1148 m_nUpdateMode = nMode;
1152 sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
1153 nAspect
1155 throw ( embed::WrongStateException,
1156 uno::RuntimeException, std::exception )
1158 // begin wrapping related part ====================
1159 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1160 if ( xWrappedObject.is() )
1162 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1163 return xWrappedObject->getStatus( nAspect );
1165 // end wrapping related part ====================
1167 ::osl::MutexGuard aGuard( m_aMutex );
1168 if ( m_bDisposed )
1169 throw lang::DisposedException(); // TODO
1171 if ( m_nObjectState == -1 )
1172 throw embed::WrongStateException( "The object must be in running state!",
1173 static_cast< ::cppu::OWeakObject* >(this) );
1175 sal_Int64 nResult = 0;
1177 #ifdef _WIN32
1178 if ( m_bGotStatus && m_nStatusAspect == nAspect )
1179 nResult = m_nStatus;
1180 else if ( m_pOleComponent )
1183 m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
1184 m_nStatusAspect = nAspect;
1185 m_bGotStatus = true;
1186 nResult = m_nStatus;
1188 #endif
1190 // this implementation needs size to be provided after object loading/creating to work in optimal way
1191 return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
1195 void SAL_CALL OleEmbeddedObject::setContainerName( const OUString& sName )
1196 throw ( uno::RuntimeException, std::exception )
1198 // begin wrapping related part ====================
1199 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1200 if ( xWrappedObject.is() )
1202 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1203 xWrappedObject->setContainerName( sName );
1204 return;
1206 // end wrapping related part ====================
1208 ::osl::MutexGuard aGuard( m_aMutex );
1209 if ( m_bDisposed )
1210 throw lang::DisposedException(); // TODO
1212 m_aContainerName = sName;
1216 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */