Bump version to 6.4.7.2.M8
[LibreOffice.git] / embeddedobj / source / msole / oleembed.cxx
blobc84b0e72d07397274924b2196b1ce5e6093c525b
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/UnreachableStateException.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/NeedsRunningStateException.hpp>
28 #include <com/sun/star/embed/StateChangeInProgressException.hpp>
29 #include <com/sun/star/embed/EmbedMisc.hpp>
30 #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
31 #include <com/sun/star/io/TempFile.hpp>
32 #include <com/sun/star/io/XSeekable.hpp>
33 #include <com/sun/star/lang/DisposedException.hpp>
34 #include <com/sun/star/lang/WrappedTargetRuntimeException.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/exc_hlp.hxx>
46 #include <cppuhelper/interfacecontainer.h>
47 #include <comphelper/processfactory.hxx>
48 #include <comphelper/mimeconfighelper.hxx>
49 #include <sal/log.hxx>
50 #include <tools/diagnose_ex.h>
53 #include <targetstatecontrol.hxx>
55 #include "ownview.hxx"
57 #if defined(_WIN32)
58 #include "olecomponent.hxx"
59 #endif
61 using namespace ::com::sun::star;
63 #ifdef _WIN32
65 void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
67 if ( !m_pOleComponent )
69 throw embed::UnreachableStateException();
71 try
73 m_pOleComponent->RunObject();
75 catch( const embed::UnreachableStateException& )
77 GetRidOfComponent();
78 throw;
80 catch( const embed::WrongStateException& )
82 GetRidOfComponent();
83 throw;
88 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl(
89 const uno::Sequence< embed::VerbDescriptor >& aVerbList )
91 uno::Sequence< sal_Int32 > aStates(2);
92 aStates[0] = embed::EmbedStates::LOADED;
93 aStates[1] = embed::EmbedStates::RUNNING;
94 for ( sal_Int32 nInd = 0; nInd < aVerbList.getLength(); nInd++ )
95 if ( aVerbList[nInd].VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
97 aStates.realloc(3);
98 aStates[2] = embed::EmbedStates::ACTIVE;
101 return aStates;
105 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState )
107 SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "Loaded object is switched to running state without verbs using!" );
109 // actually there will be only one verb
110 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
112 uno::Sequence< sal_Int32 > aVerbs( 1 );
113 aVerbs[0] = embed::EmbedVerbs::MS_OLEVERB_OPEN;
116 return uno::Sequence< sal_Int32 >();
118 #endif
120 void OleEmbeddedObject::MoveListeners()
122 if ( m_pInterfaceContainer )
124 // move state change listeners
126 ::cppu::OInterfaceContainerHelper* pStateChangeContainer =
127 m_pInterfaceContainer->getContainer( cppu::UnoType<embed::XStateChangeListener>::get());
128 if ( pStateChangeContainer != nullptr )
130 if ( m_xWrappedObject.is() )
132 ::cppu::OInterfaceIteratorHelper pIterator( *pStateChangeContainer );
133 while ( pIterator.hasMoreElements() )
137 m_xWrappedObject->addStateChangeListener( static_cast<embed::XStateChangeListener*>(pIterator.next()) );
139 catch( const uno::RuntimeException& )
141 pIterator.remove();
148 // move event listeners
150 ::cppu::OInterfaceContainerHelper* pEventContainer =
151 m_pInterfaceContainer->getContainer( cppu::UnoType<document::XEventListener>::get());
152 if ( pEventContainer != nullptr )
154 if ( m_xWrappedObject.is() )
156 ::cppu::OInterfaceIteratorHelper pIterator( *pEventContainer );
157 while ( pIterator.hasMoreElements() )
161 m_xWrappedObject->addEventListener( static_cast<document::XEventListener*>(pIterator.next()) );
163 catch( const uno::RuntimeException& )
165 pIterator.remove();
172 // move close listeners
174 ::cppu::OInterfaceContainerHelper* pCloseContainer =
175 m_pInterfaceContainer->getContainer( cppu::UnoType<util::XCloseListener>::get());
176 if ( pCloseContainer != nullptr )
178 if ( m_xWrappedObject.is() )
180 ::cppu::OInterfaceIteratorHelper pIterator( *pCloseContainer );
181 while ( pIterator.hasMoreElements() )
185 m_xWrappedObject->addCloseListener( static_cast<util::XCloseListener*>(pIterator.next()) );
187 catch( const uno::RuntimeException& )
189 pIterator.remove();
196 m_pInterfaceContainer.reset();
201 uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( OUString& o_aStorageName )
203 uno::Reference< embed::XStorage > xResult;
205 for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ )
207 OUString aName = OUString::number( nInd ) + "TMPSTOR" + m_aEntryName;
208 if ( !m_xParentStorage->hasByName( aName ) )
210 xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE );
211 o_aStorageName = aName;
215 if ( !xResult.is() )
217 o_aStorageName.clear();
218 throw uno::RuntimeException();
221 return xResult;
225 OUString OleEmbeddedObject::MoveToTemporarySubstream()
227 OUString aResult;
228 for ( sal_Int32 nInd = 0; nInd < 32000 && aResult.isEmpty(); nInd++ )
230 OUString aName = OUString::number( nInd ) + "TMPSTREAM" + m_aEntryName;
231 if ( !m_xParentStorage->hasByName( aName ) )
233 m_xParentStorage->renameElement( m_aEntryName, aName );
234 aResult = aName;
238 if ( aResult.isEmpty() )
239 throw uno::RuntimeException();
241 return aResult;
245 bool OleEmbeddedObject::TryToConvertToOOo( const uno::Reference< io::XStream >& xStream )
247 bool bResult = false;
249 OUString aStorageName;
250 OUString aTmpStreamName;
251 sal_Int32 nStep = 0;
253 if ( m_pOleComponent || m_bReadOnly )
254 return false;
258 changeState( embed::EmbedStates::LOADED );
260 // the stream must be seekable
261 uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY_THROW );
262 xSeekable->seek( 0 );
263 m_aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xFactory, OUString(), xStream->getInputStream() );
265 if ( !m_aFilterName.isEmpty()
266 && ( m_aFilterName == "Calc MS Excel 2007 XML" || m_aFilterName == "Impress MS PowerPoint 2007 XML" || m_aFilterName == "MS Word 2007 XML"
267 || m_aFilterName == "MS Excel 97 Vorlage/Template" || m_aFilterName == "MS Word 97 Vorlage" ) )
269 uno::Reference< container::XNameAccess > xFilterFactory(
270 m_xFactory->createInstance("com.sun.star.document.FilterFactory"),
271 uno::UNO_QUERY_THROW );
273 OUString aDocServiceName;
274 uno::Any aFilterAnyData = xFilterFactory->getByName( m_aFilterName );
275 uno::Sequence< beans::PropertyValue > aFilterData;
276 if ( aFilterAnyData >>= aFilterData )
278 for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
279 if ( aFilterData[nInd].Name == "DocumentService" )
280 aFilterData[nInd].Value >>= aDocServiceName;
283 if ( !aDocServiceName.isEmpty() )
285 // create the model
286 uno::Sequence< uno::Any > aArguments(1);
287 aArguments[0] <<= beans::NamedValue( "EmbeddedObject", uno::makeAny( true ));
289 uno::Reference< util::XCloseable > xDocument( m_xFactory->createInstanceWithArguments( aDocServiceName, aArguments ), uno::UNO_QUERY_THROW );
290 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
291 uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW );
293 // let the model behave as embedded one
294 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW );
295 uno::Sequence< beans::PropertyValue > aSeq( 1 );
296 aSeq[0].Name = "SetEmbedded";
297 aSeq[0].Value <<= true;
298 xModel->attachResource( OUString(), aSeq );
300 // load the model from the stream
301 uno::Sequence< beans::PropertyValue > aArgs( 5 );
302 aArgs[0].Name = "HierarchicalDocumentName";
303 aArgs[0].Value <<= m_aEntryName;
304 aArgs[1].Name = "ReadOnly";
305 aArgs[1].Value <<= true;
306 aArgs[2].Name = "FilterName";
307 aArgs[2].Value <<= m_aFilterName;
308 aArgs[3].Name = "URL";
309 aArgs[3].Value <<= OUString( "private:stream" );
310 aArgs[4].Name = "InputStream";
311 aArgs[4].Value <<= xStream->getInputStream();
313 xSeekable->seek( 0 );
314 xLoadable->load( aArgs );
316 // the model is successfully loaded, create a new storage and store the model to the storage
317 uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName );
318 xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() );
319 xDocument->close( true );
320 uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW );
321 OUString aMediaType;
322 xStorProps->getPropertyValue("MediaType") >>= aMediaType;
323 xTmpStorage->dispose();
325 // look for the related embedded object factory
326 ::comphelper::MimeConfigurationHelper aConfigHelper( comphelper::getComponentContext(m_xFactory) );
327 OUString aEmbedFactory;
328 if ( !aMediaType.isEmpty() )
329 aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType );
331 if ( aEmbedFactory.isEmpty() )
332 throw uno::RuntimeException();
334 uno::Reference< uno::XInterface > xFact = m_xFactory->createInstance( aEmbedFactory );
336 uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW );
338 // now the object should be adjusted to become the wrapper
339 nStep = 1;
340 uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW );
341 xComp->dispose();
342 m_xObjectStream.clear();
343 m_nObjectState = -1;
345 nStep = 2;
346 aTmpStreamName = MoveToTemporarySubstream();
348 nStep = 3;
349 m_xParentStorage->renameElement( aStorageName, m_aEntryName );
351 nStep = 4;
352 m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW );
354 // remember parent document name to show in the title bar
355 m_xWrappedObject->setContainerName( m_aContainerName );
357 bResult = true; // the change is no more revertable
360 m_xParentStorage->removeElement( aTmpStreamName );
362 catch( const uno::Exception& )
364 // the success of the removing is not so important
369 catch( const uno::Exception& )
371 // repair the object if necessary
372 switch( nStep )
374 case 4:
375 case 3:
376 if ( !aTmpStreamName.isEmpty() && aTmpStreamName != m_aEntryName )
379 if ( m_xParentStorage->hasByName( m_aEntryName ) )
380 m_xParentStorage->removeElement( m_aEntryName );
381 m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName );
383 catch ( const uno::Exception& ex )
385 css::uno::Any anyEx = cppu::getCaughtException();
386 try {
387 close( true );
388 } catch( const uno::Exception& ) {}
390 m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without committing!
391 throw css::lang::WrappedTargetRuntimeException( ex.Message,
392 nullptr, anyEx ); // the repairing is not possible
394 [[fallthrough]];
395 case 2:
398 m_xObjectStream = m_xParentStorage->openStreamElement( m_aEntryName, m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
399 m_nObjectState = embed::EmbedStates::LOADED;
401 catch( const uno::Exception& ex )
403 css::uno::Any anyEx = cppu::getCaughtException();
404 try {
405 close( true );
406 } catch( const uno::Exception& ) {}
408 throw css::lang::WrappedTargetRuntimeException( ex.Message,
409 nullptr, anyEx ); // the repairing is not possible
411 [[fallthrough]];
413 case 1:
414 case 0:
415 if ( !aStorageName.isEmpty() )
416 try {
417 m_xParentStorage->removeElement( aStorageName );
418 } catch( const uno::Exception& ) { SAL_WARN( "embeddedobj.ole", "Can not remove temporary storage!" ); }
419 break;
423 if ( bResult )
425 // the conversion was done successfully, now the additional initializations should happen
427 MoveListeners();
428 m_xWrappedObject->setClientSite( m_xClientSite );
429 if ( m_xParent.is() )
431 uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY );
432 if ( xChild.is() )
433 xChild->setParent( m_xParent );
438 return bResult;
442 void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState )
444 // begin wrapping related part ====================
445 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
446 if ( xWrappedObject.is() )
448 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
449 xWrappedObject->changeState( nNewState );
450 return;
452 // end wrapping related part ====================
454 ::osl::ResettableMutexGuard aGuard( m_aMutex );
456 if ( m_bDisposed )
457 throw lang::DisposedException(); // TODO
459 if ( m_nObjectState == -1 )
460 throw embed::WrongStateException( "The object has no persistence!",
461 static_cast< ::cppu::OWeakObject* >(this) );
463 // in case the object is already in requested state
464 if ( m_nObjectState == nNewState )
465 return;
467 #ifdef _WIN32
468 if ( m_pOleComponent )
470 if ( m_nTargetState != -1 )
472 // means that the object is currently trying to reach the target state
473 throw embed::StateChangeInProgressException( OUString(),
474 uno::Reference< uno::XInterface >(),
475 m_nTargetState );
478 TargetStateControl_Impl aControl( m_nTargetState, nNewState );
480 // TODO: additional verbs can be a problem, since nobody knows how the object
481 // will behave after activation
483 sal_Int32 nOldState = m_nObjectState;
484 aGuard.clear();
485 StateChangeNotification_Impl( true, nOldState, nNewState );
486 aGuard.reset();
490 if ( nNewState == embed::EmbedStates::LOADED )
492 // This means just closing of the current object
493 // If component can not be closed the object stays in loaded state
494 // and it holds reference to "incomplete" component
495 // If the object is switched to running state later
496 // the component will become "complete"
498 // the loaded state must be set before, because of notifications!
499 m_nObjectState = nNewState;
502 VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
503 m_pOleComponent->CloseObject();
506 aGuard.clear();
507 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
508 aGuard.reset();
510 else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
512 if ( m_nObjectState == embed::EmbedStates::LOADED )
514 // if the target object is in loaded state and a different state is specified
515 // as a new one the object first must be switched to running state.
517 // the component can exist already in nonrunning state
518 // it can be created during loading to detect type of object
519 CreateOleComponentAndLoad_Impl( m_pOleComponent );
521 SwitchComponentToRunningState_Impl();
522 m_nObjectState = embed::EmbedStates::RUNNING;
523 aGuard.clear();
524 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
525 aGuard.reset();
527 if ( m_pOleComponent && m_bHasSizeToSet )
529 aGuard.clear();
530 try {
531 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
532 m_bHasSizeToSet = false;
534 catch( const uno::Exception& ) {}
535 aGuard.reset();
538 if ( m_nObjectState == nNewState )
539 return;
542 // so now the object is either switched from Active to Running state or viceversa
543 // the notification about object state change will be done asynchronously
544 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
546 // execute OPEN verb, if object does not reach active state it is an object's problem
547 aGuard.clear();
548 m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
549 aGuard.reset();
551 // some objects do not allow to set the size even in running state
552 if ( m_pOleComponent && m_bHasSizeToSet )
554 aGuard.clear();
555 try {
556 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
557 m_bHasSizeToSet = false;
559 catch( uno::Exception& ) {}
560 aGuard.reset();
563 m_nObjectState = nNewState;
565 else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
567 aGuard.clear();
568 m_pOleComponent->CloseObject();
569 m_pOleComponent->RunObject(); // Should not fail, the object already was active
570 aGuard.reset();
571 m_nObjectState = nNewState;
573 else
575 throw embed::UnreachableStateException();
578 else
579 throw embed::UnreachableStateException();
581 catch( uno::Exception& )
583 aGuard.clear();
584 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
585 throw;
588 else
589 #endif
591 throw embed::UnreachableStateException();
596 uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
598 // begin wrapping related part ====================
599 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
600 if ( xWrappedObject.is() )
602 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
603 return xWrappedObject->getReachableStates();
605 // end wrapping related part ====================
607 ::osl::MutexGuard aGuard( m_aMutex );
608 if ( m_bDisposed )
609 throw lang::DisposedException(); // TODO
611 if ( m_nObjectState == -1 )
612 throw embed::WrongStateException( "The object has no persistence!",
613 static_cast< ::cppu::OWeakObject* >(this) );
615 #ifdef _WIN32
616 if ( m_pOleComponent )
618 if ( m_nObjectState == embed::EmbedStates::LOADED )
620 // the list of supported verbs can be retrieved only when object is in running state
621 throw embed::NeedsRunningStateException(); // TODO:
624 // the list of states can only be guessed based on standard verbs,
625 // since there is no way to detect what additional verbs do
626 return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
628 else
629 #endif
631 return uno::Sequence< sal_Int32 >();
636 sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState()
638 // begin wrapping related part ====================
639 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
640 if ( xWrappedObject.is() )
642 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
643 return xWrappedObject->getCurrentState();
645 // end wrapping related part ====================
647 ::osl::MutexGuard aGuard( m_aMutex );
648 if ( m_bDisposed )
649 throw lang::DisposedException(); // TODO
651 if ( m_nObjectState == -1 )
652 throw embed::WrongStateException( "The object has no persistence!",
653 static_cast< ::cppu::OWeakObject* >(this) );
655 // TODO: Shouldn't we ask object? ( I guess no )
656 return m_nObjectState;
659 namespace
661 bool lcl_CopyStream(const uno::Reference<io::XInputStream>& xIn, const uno::Reference<io::XOutputStream>& xOut, sal_Int32 nMaxCopy = SAL_MAX_INT32)
663 if (nMaxCopy <= 0)
664 return false;
666 const sal_Int32 nChunkSize = 4096;
667 uno::Sequence< sal_Int8 > aData(nChunkSize);
668 sal_Int32 nTotalRead = 0;
669 sal_Int32 nRead;
672 if (nTotalRead + aData.getLength() > nMaxCopy)
674 aData.realloc(nMaxCopy - nTotalRead);
676 nRead = xIn->readBytes(aData, aData.getLength());
677 nTotalRead += nRead;
678 xOut->writeBytes(aData);
679 } while (nRead == nChunkSize && nTotalRead <= nMaxCopy);
680 return nTotalRead != 0;
683 uno::Reference < io::XStream > lcl_GetExtractedStream( OUString& rUrl,
684 const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory,
685 const css::uno::Reference< css::io::XStream >& xObjectStream )
687 uno::Reference <beans::XPropertySet> xNativeTempFile(
688 io::TempFile::create(comphelper::getComponentContext(xFactory)),
689 uno::UNO_QUERY_THROW);
690 uno::Reference < io::XStream > xStream(xNativeTempFile, uno::UNO_QUERY_THROW);
692 uno::Sequence< uno::Any > aArgs( 2 );
693 aArgs[0] <<= xObjectStream;
694 aArgs[1] <<= true; // do not create copy
695 uno::Reference< container::XNameContainer > xNameContainer(
696 xFactory->createInstanceWithArguments(
697 "com.sun.star.embed.OLESimpleStorage",
698 aArgs ), uno::UNO_QUERY_THROW );
700 //various stream names that can contain the real document contents for
701 //this object in a straightforward direct way
702 static const OUStringLiteral aStreamNames[] =
704 "CONTENTS",
705 "Package",
706 "EmbeddedOdf",
707 "WordDocument",
708 "Workbook",
709 "PowerPoint Document"
712 bool bCopied = false;
713 for (size_t i = 0; i < SAL_N_ELEMENTS(aStreamNames) && !bCopied; ++i)
715 uno::Reference<io::XStream> xEmbeddedFile;
718 xNameContainer->getByName(aStreamNames[i]) >>= xEmbeddedFile;
720 catch (const container::NoSuchElementException&)
722 // ignore
724 bCopied = xEmbeddedFile.is() && lcl_CopyStream(xEmbeddedFile->getInputStream(), xStream->getOutputStream());
727 if (!bCopied)
729 uno::Reference< io::XStream > xOle10Native;
732 xNameContainer->getByName("\1Ole10Native") >>= xOle10Native;
734 catch (container::NoSuchElementException const&)
736 // ignore
738 if (xOle10Native.is())
740 const uno::Reference<io::XInputStream> xIn = xOle10Native->getInputStream();
741 xIn->skipBytes(4); //size of the entire stream minus 4 bytes
742 xIn->skipBytes(2); //word that represent the directory type
743 uno::Sequence< sal_Int8 > aData(1);
744 sal_Int32 nRead;
747 nRead = xIn->readBytes(aData, 1);
748 } while (nRead == 1 && aData[0] != 0); // file name plus extension of the attachment null terminated
751 nRead = xIn->readBytes(aData, 1);
752 } while (nRead == 1 && aData[0] != 0); // Fully Qualified File name with extension
753 xIn->skipBytes(1); //single byte
754 xIn->skipBytes(1); //single byte
755 xIn->skipBytes(2); //Word that represent the directory type
756 xIn->skipBytes(4); //len of string
759 nRead = xIn->readBytes(aData, 1);
760 } while (nRead == 1 && aData[0] != 0); // Actual string representing the file path
761 uno::Sequence< sal_Int8 > aLenData(4);
762 xIn->readBytes(aLenData, 4); //len of attachment
763 sal_uInt32 nLen = static_cast<sal_uInt32>(
764 (aLenData[0] & 0xFF) |
765 ((aLenData[1] & 0xFF) << 8) |
766 ((aLenData[2] & 0xFF) << 16) |
767 ((aLenData[3] & 0xFF) << 24));
769 bCopied = lcl_CopyStream(xIn, xStream->getOutputStream(), nLen);
773 uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
774 if (xSeekableStor.is())
775 xSeekableStor->seek(0);
777 if (!bCopied)
778 bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
780 if (bCopied)
782 xNativeTempFile->setPropertyValue("RemoveFile",
783 uno::makeAny(false));
784 uno::Any aUrl = xNativeTempFile->getPropertyValue("Uri");
785 aUrl >>= rUrl;
787 xNativeTempFile.clear();
789 uno::Reference < ucb::XSimpleFileAccess3 > xSimpleFileAccess(
790 ucb::SimpleFileAccess::create( comphelper::getComponentContext(xFactory) ) );
792 xSimpleFileAccess->setReadOnly(rUrl, true);
794 else
796 xNativeTempFile->setPropertyValue("RemoveFile",
797 uno::makeAny(true));
800 return xStream;
803 //Dump the objects content to a tempfile, just the "CONTENTS" stream if
804 //there is one for non-compound documents, otherwise the whole content.
805 //On success a file is returned which must be removed by the caller
806 OUString lcl_ExtractObject(const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory,
807 const css::uno::Reference< css::io::XStream >& xObjectStream)
809 OUString sUrl;
811 // the solution is only active for Unix systems
812 #ifndef _WIN32
813 lcl_GetExtractedStream(sUrl, xFactory, xObjectStream);
814 #else
815 (void) xFactory;
816 (void) xObjectStream;
817 #endif
818 return sUrl;
821 uno::Reference < io::XStream > lcl_ExtractObjectStream( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory,
822 const css::uno::Reference< css::io::XStream >& xObjectStream )
824 OUString sUrl;
825 return lcl_GetExtractedStream( sUrl, xFactory, xObjectStream );
830 void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
832 // begin wrapping related part ====================
833 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
834 if ( xWrappedObject.is() )
836 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
837 xWrappedObject->doVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN); // open content in the window not in-place
838 return;
840 // end wrapping related part ====================
842 ::osl::ResettableMutexGuard aGuard( m_aMutex );
843 if ( m_bDisposed )
844 throw lang::DisposedException(); // TODO
846 if ( m_nObjectState == -1 )
847 throw embed::WrongStateException( "The object has no persistence!",
848 static_cast< ::cppu::OWeakObject* >(this) );
850 #ifdef _WIN32
851 if ( m_pOleComponent )
853 sal_Int32 nOldState = m_nObjectState;
855 // TODO/LATER detect target state here and do a notification
856 // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
857 if ( m_nObjectState == embed::EmbedStates::LOADED )
859 // if the target object is in loaded state
860 // it must be switched to running state to execute verb
861 aGuard.clear();
862 changeState( embed::EmbedStates::RUNNING );
863 aGuard.reset();
866 try {
867 if ( !m_pOleComponent )
868 throw uno::RuntimeException();
870 // ==== the STAMPIT related solution =============================
871 m_aVerbExecutionController.StartControlExecution();
874 m_pOleComponent->ExecuteVerb( nVerbID );
875 m_pOleComponent->SetHostName( OUString(), m_aContainerName );
877 // ==== the STAMPIT related solution =============================
878 bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
880 // this workaround is implemented for STAMPIT object
881 // if object was modified during verb execution it is saved here
882 if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
883 SaveObject_Impl();
886 catch( uno::Exception& )
888 // ==== the STAMPIT related solution =============================
889 m_aVerbExecutionController.EndControlExecution_WasModified();
892 aGuard.clear();
893 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
894 throw;
898 else
899 #endif
901 if ( nVerbID != -9 )
904 throw embed::UnreachableStateException();
907 // the workaround verb to show the object in case no server is available
909 // if it is possible, the object will be converted to OOo format
910 if ( !m_bTriedConversion )
912 m_bTriedConversion = true;
913 if ( TryToConvertToOOo( m_xObjectStream ) )
915 changeState( embed::EmbedStates::ACTIVE );
916 return;
920 if ( !m_xOwnView.is() && m_xObjectStream.is() && m_aFilterName != "Text" )
922 try {
923 uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
924 if ( xSeekable.is() )
925 xSeekable->seek( 0 );
927 m_xOwnView = new OwnView_Impl( m_xFactory, m_xObjectStream->getInputStream() );
929 catch( uno::RuntimeException& )
931 throw;
933 catch (uno::Exception const&)
935 TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::doVerb: -9 fallback path:");
939 // it may be the OLE Storage, try to extract stream
940 if ( !m_xOwnView.is() && m_xObjectStream.is() && m_aFilterName == "Text" )
942 uno::Reference< io::XStream > xStream = lcl_ExtractObjectStream( m_xFactory, m_xObjectStream );
944 if ( TryToConvertToOOo( xStream ) )
946 changeState( embed::EmbedStates::ACTIVE );
947 return;
951 if (!m_xOwnView.is() || !m_xOwnView->Open())
953 //Make a RO copy and see if the OS can find something to at
954 //least display the content for us
955 if (m_aTempDumpURL.isEmpty())
956 m_aTempDumpURL = lcl_ExtractObject(m_xFactory, m_xObjectStream);
958 if (m_aTempDumpURL.isEmpty())
959 throw embed::UnreachableStateException();
961 uno::Reference< css::system::XSystemShellExecute > xSystemShellExecute(
962 css::system::SystemShellExecute::create(comphelper::getComponentContext(m_xFactory)) );
963 xSystemShellExecute->execute(m_aTempDumpURL, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY);
971 uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
973 // begin wrapping related part ====================
974 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
975 if ( xWrappedObject.is() )
977 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
978 return xWrappedObject->getSupportedVerbs();
980 // end wrapping related part ====================
982 ::osl::MutexGuard aGuard( m_aMutex );
983 if ( m_bDisposed )
984 throw lang::DisposedException(); // TODO
986 if ( m_nObjectState == -1 )
987 throw embed::WrongStateException( "The object has no persistence!",
988 static_cast< ::cppu::OWeakObject* >(this) );
989 #ifdef _WIN32
990 if ( m_pOleComponent )
992 // registry could be used in this case
993 // if ( m_nObjectState == embed::EmbedStates::LOADED )
994 // {
995 // // the list of supported verbs can be retrieved only when object is in running state
996 // throw embed::NeedsRunningStateException(); // TODO:
997 // }
999 return m_pOleComponent->GetVerbList();
1001 else
1002 #endif
1004 return uno::Sequence< embed::VerbDescriptor >();
1009 void SAL_CALL OleEmbeddedObject::setClientSite(
1010 const uno::Reference< embed::XEmbeddedClient >& xClient )
1012 // begin wrapping related part ====================
1013 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1014 if ( xWrappedObject.is() )
1016 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1017 xWrappedObject->setClientSite( xClient );
1018 return;
1020 // end wrapping related part ====================
1022 ::osl::MutexGuard aGuard( m_aMutex );
1023 if ( m_bDisposed )
1024 throw lang::DisposedException(); // TODO
1026 if ( m_xClientSite != xClient)
1028 if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
1029 throw embed::WrongStateException(
1030 "The client site can not be set currently!",
1031 static_cast< ::cppu::OWeakObject* >(this) );
1033 m_xClientSite = xClient;
1038 uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
1040 // begin wrapping related part ====================
1041 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1042 if ( xWrappedObject.is() )
1044 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1045 return xWrappedObject->getClientSite();
1047 // end wrapping related part ====================
1049 ::osl::MutexGuard aGuard( m_aMutex );
1050 if ( m_bDisposed )
1051 throw lang::DisposedException(); // TODO
1053 if ( m_nObjectState == -1 )
1054 throw embed::WrongStateException( "The object has no persistence!",
1055 static_cast< ::cppu::OWeakObject* >(this) );
1057 return m_xClientSite;
1061 void SAL_CALL OleEmbeddedObject::update()
1063 // begin wrapping related part ====================
1064 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1065 if ( xWrappedObject.is() )
1067 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1068 xWrappedObject->update();
1069 return;
1071 // end wrapping related part ====================
1073 ::osl::MutexGuard aGuard( m_aMutex );
1074 if ( m_bDisposed )
1075 throw lang::DisposedException(); // TODO
1077 if ( m_nObjectState == -1 )
1078 throw embed::WrongStateException( "The object has no persistence!",
1079 static_cast< ::cppu::OWeakObject* >(this) );
1081 if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
1083 // TODO: update view representation
1085 else
1087 // the object must be up to date
1088 SAL_WARN_IF( m_nUpdateMode != embed::EmbedUpdateModes::ALWAYS_UPDATE, "embeddedobj.ole", "Unknown update mode!" );
1093 void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
1095 // begin wrapping related part ====================
1096 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1097 if ( xWrappedObject.is() )
1099 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1100 xWrappedObject->setUpdateMode( nMode );
1101 return;
1103 // end wrapping related part ====================
1105 ::osl::MutexGuard aGuard( m_aMutex );
1106 if ( m_bDisposed )
1107 throw lang::DisposedException(); // TODO
1109 if ( m_nObjectState == -1 )
1110 throw embed::WrongStateException( "The object has no persistence!",
1111 static_cast< ::cppu::OWeakObject* >(this) );
1113 OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
1114 || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
1115 "Unknown update mode!" );
1116 m_nUpdateMode = nMode;
1120 sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
1121 nAspect
1124 // begin wrapping related part ====================
1125 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1126 if ( xWrappedObject.is() )
1128 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1129 return xWrappedObject->getStatus( nAspect );
1131 // end wrapping related part ====================
1133 ::osl::MutexGuard aGuard( m_aMutex );
1134 if ( m_bDisposed )
1135 throw lang::DisposedException(); // TODO
1137 if ( m_nObjectState == -1 )
1138 throw embed::WrongStateException( "The object must be in running state!",
1139 static_cast< ::cppu::OWeakObject* >(this) );
1141 sal_Int64 nResult = 0;
1143 #ifdef _WIN32
1144 if ( m_bGotStatus && m_nStatusAspect == nAspect )
1145 nResult = m_nStatus;
1146 else if ( m_pOleComponent )
1149 m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
1150 m_nStatusAspect = nAspect;
1151 m_bGotStatus = true;
1152 nResult = m_nStatus;
1154 #endif
1156 // this implementation needs size to be provided after object loading/creating to work in optimal way
1157 return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
1161 void SAL_CALL OleEmbeddedObject::setContainerName( const OUString& sName )
1163 // begin wrapping related part ====================
1164 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1165 if ( xWrappedObject.is() )
1167 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1168 xWrappedObject->setContainerName( sName );
1169 return;
1171 // end wrapping related part ====================
1173 ::osl::MutexGuard aGuard( m_aMutex );
1174 if ( m_bDisposed )
1175 throw lang::DisposedException(); // TODO
1177 m_aContainerName = sName;
1181 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */