1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <comphelper/multicontainer2.hxx>
51 #include <comphelper/mimeconfighelper.hxx>
52 #include <comphelper/propertyvalue.hxx>
53 #include <sal/log.hxx>
54 #include <comphelper/diagnose_ex.hxx>
57 #include <targetstatecontrol.hxx>
59 #include "ownview.hxx"
62 #include "olecomponent.hxx"
65 using namespace ::com::sun::star
;
69 void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
71 if ( !m_pOleComponent
)
73 throw embed::UnreachableStateException();
77 m_pOleComponent
->RunObject();
79 catch( const embed::UnreachableStateException
& )
84 catch( const embed::WrongStateException
& )
92 uno::Sequence
< sal_Int32
> OleEmbeddedObject::GetReachableStatesList_Impl(
93 const uno::Sequence
< embed::VerbDescriptor
>& aVerbList
)
95 uno::Sequence
< sal_Int32
> aStates
{ embed::EmbedStates::LOADED
, embed::EmbedStates::RUNNING
};
96 for ( embed::VerbDescriptor
const & vd
: aVerbList
)
97 if ( vd
.VerbID
== embed::EmbedVerbs::MS_OLEVERB_OPEN
)
100 aStates
.getArray()[2] = embed::EmbedStates::ACTIVE
;
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 return { embed::EmbedVerbs::MS_OLEVERB_OPEN
};
118 return uno::Sequence
< sal_Int32
>();
122 void OleEmbeddedObject::MoveListeners()
124 if ( !m_pInterfaceContainer
)
127 // move state change listeners
129 comphelper::OInterfaceContainerHelper2
* pStateChangeContainer
=
130 m_pInterfaceContainer
->getContainer( cppu::UnoType
<embed::XStateChangeListener
>::get());
131 if ( pStateChangeContainer
!= nullptr )
133 if ( m_xWrappedObject
.is() )
135 comphelper::OInterfaceIteratorHelper2
pIterator( *pStateChangeContainer
);
136 while ( pIterator
.hasMoreElements() )
140 m_xWrappedObject
->addStateChangeListener( static_cast<embed::XStateChangeListener
*>(pIterator
.next()) );
142 catch( const uno::RuntimeException
& )
151 // move event listeners
153 comphelper::OInterfaceContainerHelper2
* pEventContainer
=
154 m_pInterfaceContainer
->getContainer( cppu::UnoType
<document::XEventListener
>::get());
155 if ( pEventContainer
!= nullptr )
157 if ( m_xWrappedObject
.is() )
159 comphelper::OInterfaceIteratorHelper2
pIterator( *pEventContainer
);
160 while ( pIterator
.hasMoreElements() )
164 m_xWrappedObject
->addEventListener( static_cast<document::XEventListener
*>(pIterator
.next()) );
166 catch( const uno::RuntimeException
& )
175 // move close listeners
177 comphelper::OInterfaceContainerHelper2
* pCloseContainer
=
178 m_pInterfaceContainer
->getContainer( cppu::UnoType
<util::XCloseListener
>::get());
179 if ( pCloseContainer
!= nullptr )
181 if ( m_xWrappedObject
.is() )
183 comphelper::OInterfaceIteratorHelper2
pIterator( *pCloseContainer
);
184 while ( pIterator
.hasMoreElements() )
188 m_xWrappedObject
->addCloseListener( static_cast<util::XCloseListener
*>(pIterator
.next()) );
190 catch( const uno::RuntimeException
& )
199 m_pInterfaceContainer
.reset();
203 uno::Reference
< embed::XStorage
> OleEmbeddedObject::CreateTemporarySubstorage( OUString
& o_aStorageName
)
205 uno::Reference
< embed::XStorage
> xResult
;
207 for ( sal_Int32 nInd
= 0; nInd
< 32000 && !xResult
.is(); nInd
++ )
209 OUString aName
= OUString::number( nInd
) + "TMPSTOR" + m_aEntryName
;
210 if ( !m_xParentStorage
->hasByName( aName
) )
212 xResult
= m_xParentStorage
->openStorageElement( aName
, embed::ElementModes::READWRITE
);
213 o_aStorageName
= aName
;
219 o_aStorageName
.clear();
220 throw uno::RuntimeException("Failed to create temporary storage for OLE embed object");
227 OUString
OleEmbeddedObject::MoveToTemporarySubstream()
230 for ( sal_Int32 nInd
= 0; nInd
< 32000 && aResult
.isEmpty(); nInd
++ )
232 OUString aName
= OUString::number( nInd
) + "TMPSTREAM" + m_aEntryName
;
233 if ( !m_xParentStorage
->hasByName( aName
) )
235 m_xParentStorage
->renameElement( m_aEntryName
, aName
);
240 if ( aResult
.isEmpty() )
241 throw uno::RuntimeException("Failed to rename temporary storage for OLE embed object");
247 bool OleEmbeddedObject::TryToConvertToOOo( const uno::Reference
< io::XStream
>& xStream
)
249 bool bResult
= false;
251 OUString aStorageName
;
252 OUString aTmpStreamName
;
255 if ( m_pOleComponent
|| m_bReadOnly
)
260 changeState( embed::EmbedStates::LOADED
);
262 // the stream must be seekable
263 uno::Reference
< io::XSeekable
> xSeekable( xStream
, uno::UNO_QUERY_THROW
);
264 xSeekable
->seek( 0 );
265 m_aFilterName
= OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xContext
, std::u16string_view(), xStream
->getInputStream() );
267 if ( !m_aFilterName
.isEmpty()
268 && ( m_aFilterName
== "Calc MS Excel 2007 XML" || m_aFilterName
== "Impress MS PowerPoint 2007 XML" || m_aFilterName
== "MS Word 2007 XML"
269 || m_aFilterName
== "MS Excel 97 Vorlage/Template" || m_aFilterName
== "MS Word 97 Vorlage" ) )
271 uno::Reference
< container::XNameAccess
> xFilterFactory(
272 m_xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", m_xContext
),
273 uno::UNO_QUERY_THROW
);
275 OUString aDocServiceName
;
276 uno::Any aFilterAnyData
= xFilterFactory
->getByName( m_aFilterName
);
277 uno::Sequence
< beans::PropertyValue
> aFilterData
;
278 if ( aFilterAnyData
>>= aFilterData
)
280 for ( beans::PropertyValue
const & prop
: std::as_const(aFilterData
) )
281 if ( prop
.Name
== "DocumentService" )
282 prop
.Value
>>= aDocServiceName
;
285 if ( !aDocServiceName
.isEmpty() )
288 uno::Sequence
< uno::Any
> aArguments
{ uno::Any(
289 beans::NamedValue( "EmbeddedObject", uno::Any( true ))) };
291 uno::Reference
< util::XCloseable
> xDocument( m_xContext
->getServiceManager()->createInstanceWithArgumentsAndContext( aDocServiceName
, aArguments
, m_xContext
), uno::UNO_QUERY_THROW
);
292 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY_THROW
);
293 uno::Reference
< document::XStorageBasedDocument
> xStorDoc( xDocument
, uno::UNO_QUERY_THROW
);
295 // let the model behave as embedded one
296 uno::Reference
< frame::XModel
> xModel( xDocument
, uno::UNO_QUERY_THROW
);
297 uno::Sequence
< beans::PropertyValue
> aSeq
{ comphelper::makePropertyValue(
298 "SetEmbedded", true) };
299 xModel
->attachResource( OUString(), aSeq
);
301 // load the model from the stream
302 uno::Sequence
< beans::PropertyValue
> aArgs
{
303 comphelper::makePropertyValue("HierarchicalDocumentName", m_aEntryName
),
304 comphelper::makePropertyValue("ReadOnly", true),
305 comphelper::makePropertyValue("FilterName", m_aFilterName
),
306 comphelper::makePropertyValue("URL", OUString( "private:stream" )),
307 comphelper::makePropertyValue("InputStream", xStream
->getInputStream())
310 xSeekable
->seek( 0 );
311 xLoadable
->load( aArgs
);
313 // the model is successfully loaded, create a new storage and store the model to the storage
314 uno::Reference
< embed::XStorage
> xTmpStorage
= CreateTemporarySubstorage( aStorageName
);
315 xStorDoc
->storeToStorage( xTmpStorage
, uno::Sequence
< beans::PropertyValue
>() );
316 xDocument
->close( true );
317 uno::Reference
< beans::XPropertySet
> xStorProps( xTmpStorage
, uno::UNO_QUERY_THROW
);
319 xStorProps
->getPropertyValue("MediaType") >>= aMediaType
;
320 xTmpStorage
->dispose();
322 // look for the related embedded object factory
323 ::comphelper::MimeConfigurationHelper
aConfigHelper( m_xContext
);
324 OUString aEmbedFactory
;
325 if ( !aMediaType
.isEmpty() )
326 aEmbedFactory
= aConfigHelper
.GetFactoryNameByMediaType( aMediaType
);
328 if ( aEmbedFactory
.isEmpty() )
329 throw uno::RuntimeException("Failed to get OLE embedded object factory");
331 uno::Reference
< uno::XInterface
> xFact
= m_xContext
->getServiceManager()->createInstanceWithContext( aEmbedFactory
, m_xContext
);
333 uno::Reference
< embed::XEmbedObjectCreator
> xEmbCreator( xFact
, uno::UNO_QUERY_THROW
);
335 // now the object should be adjusted to become the wrapper
337 uno::Reference
< lang::XComponent
> xComp( m_xObjectStream
, uno::UNO_QUERY_THROW
);
339 m_xObjectStream
.clear();
343 aTmpStreamName
= MoveToTemporarySubstream();
346 m_xParentStorage
->renameElement( aStorageName
, m_aEntryName
);
349 m_xWrappedObject
.set( xEmbCreator
->createInstanceInitFromEntry( m_xParentStorage
, m_aEntryName
, uno::Sequence
< beans::PropertyValue
>(), uno::Sequence
< beans::PropertyValue
>() ), uno::UNO_QUERY_THROW
);
351 // remember parent document name to show in the title bar
352 m_xWrappedObject
->setContainerName( m_aContainerName
);
354 bResult
= true; // the change is no more revertable
357 m_xParentStorage
->removeElement( aTmpStreamName
);
359 catch( const uno::Exception
& )
361 // the success of the removing is not so important
366 catch( const uno::Exception
& )
368 // repair the object if necessary
373 if ( !aTmpStreamName
.isEmpty() && aTmpStreamName
!= m_aEntryName
)
376 if ( m_xParentStorage
->hasByName( m_aEntryName
) )
377 m_xParentStorage
->removeElement( m_aEntryName
);
378 m_xParentStorage
->renameElement( aTmpStreamName
, m_aEntryName
);
380 catch ( const uno::Exception
& ex
)
382 css::uno::Any anyEx
= cppu::getCaughtException();
385 } catch( const uno::Exception
& ) {}
387 m_xParentStorage
->dispose(); // ??? the storage has information loss, it should be closed without committing!
388 throw css::lang::WrappedTargetRuntimeException( ex
.Message
,
389 nullptr, anyEx
); // the repairing is not possible
395 m_xObjectStream
= m_xParentStorage
->openStreamElement( m_aEntryName
, m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
);
396 m_nObjectState
= embed::EmbedStates::LOADED
;
398 catch( const uno::Exception
& ex
)
400 css::uno::Any anyEx
= cppu::getCaughtException();
403 } catch( const uno::Exception
& ) {}
405 throw css::lang::WrappedTargetRuntimeException( ex
.Message
,
406 nullptr, anyEx
); // the repairing is not possible
412 if ( !aStorageName
.isEmpty() )
414 m_xParentStorage
->removeElement( aStorageName
);
415 } catch( const uno::Exception
& ) { SAL_WARN( "embeddedobj.ole", "Can not remove temporary storage!" ); }
422 // the conversion was done successfully, now the additional initializations should happen
425 m_xWrappedObject
->setClientSite( m_xClientSite
);
426 if ( m_xParent
.is() )
428 uno::Reference
< container::XChild
> xChild( m_xWrappedObject
, uno::UNO_QUERY
);
430 xChild
->setParent( m_xParent
);
439 void SAL_CALL
OleEmbeddedObject::changeState( sal_Int32 nNewState
)
441 // begin wrapping related part ====================
442 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
443 if ( xWrappedObject
.is() )
445 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
446 xWrappedObject
->changeState( nNewState
);
449 // end wrapping related part ====================
451 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
454 throw lang::DisposedException(); // TODO
456 if ( m_nObjectState
== -1 )
457 throw embed::WrongStateException( "The object has no persistence!",
458 static_cast< ::cppu::OWeakObject
* >(this) );
460 // in case the object is already in requested state
461 if ( m_nObjectState
== nNewState
)
465 if ( m_pOleComponent
)
467 if ( m_nTargetState
!= -1 )
469 // means that the object is currently trying to reach the target state
470 throw embed::StateChangeInProgressException( OUString(),
471 uno::Reference
< uno::XInterface
>(),
475 TargetStateControl_Impl
aControl( m_nTargetState
, nNewState
);
477 // TODO: additional verbs can be a problem, since nobody knows how the object
478 // will behave after activation
480 sal_Int32 nOldState
= m_nObjectState
;
482 StateChangeNotification_Impl( true, nOldState
, nNewState
);
487 if ( nNewState
== embed::EmbedStates::LOADED
)
489 // This means just closing of the current object
490 // If component can not be closed the object stays in loaded state
491 // and it holds reference to "incomplete" component
492 // If the object is switched to running state later
493 // the component will become "complete"
495 // the loaded state must be set before, because of notifications!
496 m_nObjectState
= nNewState
;
499 VerbExecutionControllerGuard
aVerbGuard( m_aVerbExecutionController
);
500 m_pOleComponent
->CloseObject();
504 StateChangeNotification_Impl( false, nOldState
, m_nObjectState
);
507 else if ( nNewState
== embed::EmbedStates::RUNNING
|| nNewState
== embed::EmbedStates::ACTIVE
)
509 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
511 // if the target object is in loaded state and a different state is specified
512 // as a new one the object first must be switched to running state.
514 // the component can exist already in nonrunning state
515 // it can be created during loading to detect type of object
516 CreateOleComponentAndLoad_Impl( m_pOleComponent
);
518 SwitchComponentToRunningState_Impl();
519 m_nObjectState
= embed::EmbedStates::RUNNING
;
521 StateChangeNotification_Impl( false, nOldState
, m_nObjectState
);
524 if ( m_pOleComponent
&& m_bHasSizeToSet
)
528 m_pOleComponent
->SetExtent( m_aSizeToSet
, m_nAspectToSet
);
529 m_bHasSizeToSet
= false;
531 catch( const uno::Exception
& ) {}
535 if ( m_nObjectState
== nNewState
)
539 // so now the object is either switched from Active to Running state or viceversa
540 // the notification about object state change will be done asynchronously
541 if ( m_nObjectState
== embed::EmbedStates::RUNNING
&& nNewState
== embed::EmbedStates::ACTIVE
)
543 // execute OPEN verb, if object does not reach active state it is an object's problem
545 m_pOleComponent
->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN
);
548 // some objects do not allow to set the size even in running state
549 if ( m_pOleComponent
&& m_bHasSizeToSet
)
553 m_pOleComponent
->SetExtent( m_aSizeToSet
, m_nAspectToSet
);
554 m_bHasSizeToSet
= false;
556 catch( uno::Exception
& ) {}
560 m_nObjectState
= nNewState
;
562 else if ( m_nObjectState
== embed::EmbedStates::ACTIVE
&& nNewState
== embed::EmbedStates::RUNNING
)
565 m_pOleComponent
->CloseObject();
566 m_pOleComponent
->RunObject(); // Should not fail, the object already was active
568 m_nObjectState
= nNewState
;
572 throw embed::UnreachableStateException();
576 throw embed::UnreachableStateException();
578 catch( uno::Exception
& )
581 StateChangeNotification_Impl( false, nOldState
, m_nObjectState
);
588 throw embed::UnreachableStateException();
593 uno::Sequence
< sal_Int32
> SAL_CALL
OleEmbeddedObject::getReachableStates()
595 // begin wrapping related part ====================
596 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
597 if ( xWrappedObject
.is() )
599 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
600 return xWrappedObject
->getReachableStates();
602 // end wrapping related part ====================
604 ::osl::MutexGuard
aGuard( m_aMutex
);
606 throw lang::DisposedException(); // TODO
608 if ( m_nObjectState
== -1 )
609 throw embed::WrongStateException( "The object has no persistence!",
610 static_cast< ::cppu::OWeakObject
* >(this) );
613 if ( m_pOleComponent
)
615 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
617 // the list of supported verbs can be retrieved only when object is in running state
618 throw embed::NeedsRunningStateException(); // TODO:
621 // the list of states can only be guessed based on standard verbs,
622 // since there is no way to detect what additional verbs do
623 return GetReachableStatesList_Impl( m_pOleComponent
->GetVerbList() );
628 return uno::Sequence
< sal_Int32
>();
633 sal_Int32 SAL_CALL
OleEmbeddedObject::getCurrentState()
635 // begin wrapping related part ====================
636 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
637 if ( xWrappedObject
.is() )
639 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
640 return xWrappedObject
->getCurrentState();
642 // end wrapping related part ====================
644 ::osl::MutexGuard
aGuard( m_aMutex
);
646 throw lang::DisposedException(); // TODO
648 if ( m_nObjectState
== -1 )
649 throw embed::WrongStateException( "The object has no persistence!",
650 static_cast< ::cppu::OWeakObject
* >(this) );
652 // TODO: Shouldn't we ask object? ( I guess no )
653 return m_nObjectState
;
658 bool lcl_CopyStream(const uno::Reference
<io::XInputStream
>& xIn
, const uno::Reference
<io::XOutputStream
>& xOut
, sal_Int32 nMaxCopy
= SAL_MAX_INT32
)
663 const sal_Int32 nChunkSize
= 4096;
664 uno::Sequence
< sal_Int8
> aData(nChunkSize
);
665 sal_Int32 nTotalRead
= 0;
669 if (nTotalRead
+ aData
.getLength() > nMaxCopy
)
671 aData
.realloc(nMaxCopy
- nTotalRead
);
673 nRead
= xIn
->readBytes(aData
, aData
.getLength());
675 xOut
->writeBytes(aData
);
676 } while (nRead
== nChunkSize
&& nTotalRead
<= nMaxCopy
);
677 return nTotalRead
!= 0;
680 uno::Reference
< io::XStream
> lcl_GetExtractedStream( OUString
& rUrl
,
681 const css::uno::Reference
< css::uno::XComponentContext
>& xContext
,
682 const css::uno::Reference
< css::io::XStream
>& xObjectStream
)
684 uno::Reference
<io::XTempFile
> xNativeTempFile(
685 io::TempFile::create(xContext
),
687 uno::Reference
< io::XStream
> xStream(xNativeTempFile
);
689 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xObjectStream
),
690 uno::Any(true) }; // do not create copy
691 uno::Reference
< container::XNameContainer
> xNameContainer(
692 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
693 "com.sun.star.embed.OLESimpleStorage",
694 aArgs
, xContext
), uno::UNO_QUERY_THROW
);
696 //various stream names that can contain the real document contents for
697 //this object in a straightforward direct way
698 static const std::u16string_view aStreamNames
[] =
705 u
"PowerPoint Document"
708 bool bCopied
= false;
709 for (size_t i
= 0; i
< std::size(aStreamNames
) && !bCopied
; ++i
)
711 uno::Reference
<io::XStream
> xEmbeddedFile
;
714 xNameContainer
->getByName(OUString(aStreamNames
[i
])) >>= xEmbeddedFile
;
716 catch (const container::NoSuchElementException
&)
720 bCopied
= xEmbeddedFile
.is() && lcl_CopyStream(xEmbeddedFile
->getInputStream(), xStream
->getOutputStream());
725 uno::Reference
< io::XStream
> xOle10Native
;
728 xNameContainer
->getByName("\1Ole10Native") >>= xOle10Native
;
730 catch (container::NoSuchElementException
const&)
734 if (xOle10Native
.is())
736 const uno::Reference
<io::XInputStream
> xIn
= xOle10Native
->getInputStream();
737 xIn
->skipBytes(4); //size of the entire stream minus 4 bytes
738 xIn
->skipBytes(2); //word that represent the directory type
739 uno::Sequence
< sal_Int8
> aData(1);
743 nRead
= xIn
->readBytes(aData
, 1);
744 } while (nRead
== 1 && aData
[0] != 0); // file name plus extension of the attachment null terminated
747 nRead
= xIn
->readBytes(aData
, 1);
748 } while (nRead
== 1 && aData
[0] != 0); // Fully Qualified File name with extension
749 xIn
->skipBytes(1); //single byte
750 xIn
->skipBytes(1); //single byte
751 xIn
->skipBytes(2); //Word that represent the directory type
752 xIn
->skipBytes(4); //len of string
755 nRead
= xIn
->readBytes(aData
, 1);
756 } while (nRead
== 1 && aData
[0] != 0); // Actual string representing the file path
757 uno::Sequence
< sal_Int8
> aLenData(4);
758 xIn
->readBytes(aLenData
, 4); //len of attachment
759 sal_uInt32 nLen
= static_cast<sal_uInt32
>(
760 (aLenData
[0] & 0xFF) |
761 ((aLenData
[1] & 0xFF) << 8) |
762 ((aLenData
[2] & 0xFF) << 16) |
763 ((aLenData
[3] & 0xFF) << 24));
765 bCopied
= lcl_CopyStream(xIn
, xStream
->getOutputStream(), nLen
);
769 uno::Reference
< io::XSeekable
> xSeekableStor(xObjectStream
, uno::UNO_QUERY
);
770 if (xSeekableStor
.is())
771 xSeekableStor
->seek(0);
774 bCopied
= lcl_CopyStream(xObjectStream
->getInputStream(), xStream
->getOutputStream());
778 xNativeTempFile
->setRemoveFile(false);
779 rUrl
= xNativeTempFile
->getUri();
781 xNativeTempFile
.clear();
783 uno::Reference
< ucb::XSimpleFileAccess3
> xSimpleFileAccess(
784 ucb::SimpleFileAccess::create( xContext
) );
786 xSimpleFileAccess
->setReadOnly(rUrl
, true);
790 xNativeTempFile
->setRemoveFile(true);
796 //Dump the objects content to a tempfile, just the "CONTENTS" stream if
797 //there is one for non-compound documents, otherwise the whole content.
798 //On success a file is returned which must be removed by the caller
799 OUString
lcl_ExtractObject(const css::uno::Reference
< css::uno::XComponentContext
>& xContext
,
800 const css::uno::Reference
< css::io::XStream
>& xObjectStream
)
804 // the solution is only active for Unix systems
806 lcl_GetExtractedStream(sUrl
, xContext
, xObjectStream
);
809 (void) xObjectStream
;
814 uno::Reference
< io::XStream
> lcl_ExtractObjectStream( const css::uno::Reference
< css::uno::XComponentContext
>& xContext
,
815 const css::uno::Reference
< css::io::XStream
>& xObjectStream
)
818 return lcl_GetExtractedStream( sUrl
, xContext
, xObjectStream
);
823 void SAL_CALL
OleEmbeddedObject::doVerb( sal_Int32 nVerbID
)
825 // begin wrapping related part ====================
826 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
827 if ( xWrappedObject
.is() )
829 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
830 xWrappedObject
->doVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN
); // open content in the window not in-place
833 // end wrapping related part ====================
835 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
837 throw lang::DisposedException(); // TODO
839 if ( m_nObjectState
== -1 )
840 throw embed::WrongStateException( "The object has no persistence!",
841 static_cast< ::cppu::OWeakObject
* >(this) );
844 if ( m_pOleComponent
)
846 sal_Int32 nOldState
= m_nObjectState
;
848 // TODO/LATER detect target state here and do a notification
849 // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
850 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
852 // if the target object is in loaded state
853 // it must be switched to running state to execute verb
855 changeState( embed::EmbedStates::RUNNING
);
860 if ( !m_pOleComponent
)
861 throw uno::RuntimeException("Null reference to OLE component");
863 // ==== the STAMPIT related solution =============================
864 m_aVerbExecutionController
.StartControlExecution();
867 m_pOleComponent
->ExecuteVerb( nVerbID
);
868 m_pOleComponent
->SetHostName( m_aContainerName
);
870 // ==== the STAMPIT related solution =============================
871 bool bModifiedOnExecution
= m_aVerbExecutionController
.EndControlExecution_WasModified();
873 // this workaround is implemented for STAMPIT object
874 // if object was modified during verb execution it is saved here
875 if ( bModifiedOnExecution
&& m_pOleComponent
->IsDirty() )
879 catch( uno::Exception
& )
881 // ==== the STAMPIT related solution =============================
882 m_aVerbExecutionController
.EndControlExecution_WasModified();
886 StateChangeNotification_Impl( false, nOldState
, m_nObjectState
);
897 throw embed::UnreachableStateException();
900 // the workaround verb to show the object in case no server is available
902 // if it is possible, the object will be converted to OOo format
903 if ( !m_bTriedConversion
)
905 m_bTriedConversion
= true;
906 if ( TryToConvertToOOo( m_xObjectStream
) )
908 changeState( embed::EmbedStates::ACTIVE
);
913 if ( !m_xOwnView
.is() && m_xObjectStream
.is() && m_aFilterName
!= "Text" )
916 uno::Reference
< io::XSeekable
> xSeekable( m_xObjectStream
, uno::UNO_QUERY
);
917 if ( xSeekable
.is() )
918 xSeekable
->seek( 0 );
920 m_xOwnView
= new OwnView_Impl( m_xContext
, m_xObjectStream
->getInputStream() );
922 catch( uno::RuntimeException
& )
926 catch (uno::Exception
const&)
928 TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::doVerb: -9 fallback path:");
932 // it may be the OLE Storage, try to extract stream
933 if ( !m_xOwnView
.is() && m_xObjectStream
.is() && m_aFilterName
== "Text" )
935 uno::Reference
< io::XStream
> xStream
= lcl_ExtractObjectStream( m_xContext
, m_xObjectStream
);
937 if ( TryToConvertToOOo( xStream
) )
939 changeState( embed::EmbedStates::ACTIVE
);
944 if (!m_xOwnView
.is() || !m_xOwnView
->Open())
946 //Make a RO copy and see if the OS can find something to at
947 //least display the content for us
948 if (m_aTempDumpURL
.isEmpty())
949 m_aTempDumpURL
= lcl_ExtractObject(m_xContext
, m_xObjectStream
);
951 if (m_aTempDumpURL
.isEmpty())
952 throw embed::UnreachableStateException();
954 uno::Reference
< css::system::XSystemShellExecute
> xSystemShellExecute(
955 css::system::SystemShellExecute::create( m_xContext
) );
956 xSystemShellExecute
->execute(m_aTempDumpURL
, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY
);
964 uno::Sequence
< embed::VerbDescriptor
> SAL_CALL
OleEmbeddedObject::getSupportedVerbs()
966 // begin wrapping related part ====================
967 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
968 if ( xWrappedObject
.is() )
970 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
971 return xWrappedObject
->getSupportedVerbs();
973 // end wrapping related part ====================
975 ::osl::MutexGuard
aGuard( m_aMutex
);
977 throw lang::DisposedException(); // TODO
979 if ( m_nObjectState
== -1 )
980 throw embed::WrongStateException( "The object has no persistence!",
981 static_cast< ::cppu::OWeakObject
* >(this) );
983 if ( m_pOleComponent
)
985 // registry could be used in this case
986 // if ( m_nObjectState == embed::EmbedStates::LOADED )
988 // // the list of supported verbs can be retrieved only when object is in running state
989 // throw embed::NeedsRunningStateException(); // TODO:
992 return m_pOleComponent
->GetVerbList();
997 // tdf#140079 Claim support for the OleEmbeddedObject::doVerb -9 fallback.
998 // So in SfxViewFrame::GetState_Impl in case SID_OBJECT hasVerbs is not
999 // empty, so that the doVerb attempt with -9 fallback is attempted
1000 uno::Sequence
<embed::VerbDescriptor
> aRet(1);
1001 aRet
.getArray()[0].VerbID
= -9;
1007 void SAL_CALL
OleEmbeddedObject::setClientSite(
1008 const uno::Reference
< embed::XEmbeddedClient
>& xClient
)
1010 // begin wrapping related part ====================
1011 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
1012 if ( xWrappedObject
.is() )
1014 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1015 xWrappedObject
->setClientSite( xClient
);
1018 // end wrapping related part ====================
1020 ::osl::MutexGuard
aGuard( m_aMutex
);
1022 throw lang::DisposedException(); // TODO
1024 if ( m_xClientSite
!= xClient
)
1026 if ( m_nObjectState
!= embed::EmbedStates::LOADED
&& m_nObjectState
!= embed::EmbedStates::RUNNING
)
1027 throw embed::WrongStateException(
1028 "The client site can not be set currently!",
1029 static_cast< ::cppu::OWeakObject
* >(this) );
1031 m_xClientSite
= xClient
;
1036 uno::Reference
< embed::XEmbeddedClient
> SAL_CALL
OleEmbeddedObject::getClientSite()
1038 // begin wrapping related part ====================
1039 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
1040 if ( xWrappedObject
.is() )
1042 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1043 return xWrappedObject
->getClientSite();
1045 // end wrapping related part ====================
1047 ::osl::MutexGuard
aGuard( m_aMutex
);
1049 throw lang::DisposedException(); // TODO
1051 if ( m_nObjectState
== -1 )
1052 throw embed::WrongStateException( "The object has no persistence!",
1053 static_cast< ::cppu::OWeakObject
* >(this) );
1055 return m_xClientSite
;
1059 void SAL_CALL
OleEmbeddedObject::update()
1061 // begin wrapping related part ====================
1062 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
1063 if ( xWrappedObject
.is() )
1065 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1066 xWrappedObject
->update();
1069 // end wrapping related part ====================
1071 ::osl::MutexGuard
aGuard( m_aMutex
);
1073 throw lang::DisposedException(); // TODO
1075 if ( m_nObjectState
== -1 )
1076 throw embed::WrongStateException( "The object has no persistence!",
1077 static_cast< ::cppu::OWeakObject
* >(this) );
1079 if ( m_nUpdateMode
== embed::EmbedUpdateModes::EXPLICIT_UPDATE
)
1081 // TODO: update view representation
1085 // the object must be up to date
1086 SAL_WARN_IF( m_nUpdateMode
!= embed::EmbedUpdateModes::ALWAYS_UPDATE
, "embeddedobj.ole", "Unknown update mode!" );
1091 void SAL_CALL
OleEmbeddedObject::setUpdateMode( sal_Int32 nMode
)
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
->setUpdateMode( nMode
);
1101 // end wrapping related part ====================
1103 ::osl::MutexGuard
aGuard( m_aMutex
);
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 OSL_ENSURE( nMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
1112 || nMode
== embed::EmbedUpdateModes::EXPLICIT_UPDATE
,
1113 "Unknown update mode!" );
1114 m_nUpdateMode
= nMode
;
1118 sal_Int64 SAL_CALL
OleEmbeddedObject::getStatus( sal_Int64
1122 // begin wrapping related part ====================
1123 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
1124 if ( xWrappedObject
.is() )
1126 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1127 return xWrappedObject
->getStatus( nAspect
);
1129 // end wrapping related part ====================
1131 ::osl::MutexGuard
aGuard( m_aMutex
);
1133 throw lang::DisposedException(); // TODO
1135 if ( m_nObjectState
== -1 )
1136 throw embed::WrongStateException( "The object must be in running state!",
1137 static_cast< ::cppu::OWeakObject
* >(this) );
1139 sal_Int64 nResult
= 0;
1142 if ( m_bGotStatus
&& m_nStatusAspect
== nAspect
)
1143 nResult
= m_nStatus
;
1144 else if ( m_pOleComponent
)
1147 m_nStatus
= m_pOleComponent
->GetMiscStatus( nAspect
);
1148 m_nStatusAspect
= nAspect
;
1149 m_bGotStatus
= true;
1150 nResult
= m_nStatus
;
1154 // this implementation needs size to be provided after object loading/creating to work in optimal way
1155 return ( nResult
| embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD
);
1159 void SAL_CALL
OleEmbeddedObject::setContainerName( const OUString
& sName
)
1161 // begin wrapping related part ====================
1162 uno::Reference
< embed::XEmbeddedObject
> xWrappedObject
= m_xWrappedObject
;
1163 if ( xWrappedObject
.is() )
1165 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1166 xWrappedObject
->setContainerName( sName
);
1169 // end wrapping related part ====================
1171 ::osl::MutexGuard
aGuard( m_aMutex
);
1173 throw lang::DisposedException(); // TODO
1175 m_aContainerName
= sName
;
1179 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */