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