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 <commonembobj.hxx>
21 #include <com/sun/star/embed/Aspects.hpp>
22 #include <com/sun/star/document/XStorageBasedDocument.hpp>
23 #include <com/sun/star/embed/EmbedStates.hpp>
24 #include <com/sun/star/embed/EntryInitModes.hpp>
25 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
26 #include <com/sun/star/embed/WrongStateException.hpp>
27 #include <com/sun/star/embed/XStorage.hpp>
28 #include <com/sun/star/embed/XOptimizedStorage.hpp>
29 #include <com/sun/star/embed/ElementModes.hpp>
30 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
31 #include <com/sun/star/embed/StorageFactory.hpp>
32 #include <com/sun/star/io/IOException.hpp>
33 #include <com/sun/star/io/TempFile.hpp>
34 #include <com/sun/star/frame/XModel.hpp>
35 #include <com/sun/star/frame/XStorable.hpp>
36 #include <com/sun/star/frame/XLoadable.hpp>
37 #include <com/sun/star/frame/XModule.hpp>
38 #include <com/sun/star/lang/NoSupportException.hpp>
39 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include <com/sun/star/util/XModifiable.hpp>
43 #include <com/sun/star/container/XNameAccess.hpp>
44 #include <com/sun/star/container/XChild.hpp>
45 #include <com/sun/star/util/XCloseable.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/beans/IllegalTypeException.hpp>
48 #include <com/sun/star/chart2/XChartDocument.hpp>
50 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
52 #include <comphelper/fileformat.h>
53 #include <comphelper/storagehelper.hxx>
54 #include <comphelper/mimeconfighelper.hxx>
55 #include <comphelper/namedvaluecollection.hxx>
56 #include <comphelper/propertyvalue.hxx>
57 #include <comphelper/configuration.hxx>
58 #include <tools/urlobj.hxx>
59 #include <unotools/mediadescriptor.hxx>
60 #include <unotools/securityoptions.hxx>
62 #include <comphelper/diagnose_ex.hxx>
63 #include <sal/log.hxx>
64 #include "persistence.hxx"
66 using namespace ::com::sun::star
;
69 uno::Sequence
< beans::PropertyValue
> GetValuableArgs_Impl( const uno::Sequence
< beans::PropertyValue
>& aMedDescr
,
70 bool bCanUseDocumentBaseURL
)
72 uno::Sequence
< beans::PropertyValue
> aResult
;
73 sal_Int32 nResLen
= 0;
75 for ( beans::PropertyValue
const & prop
: aMedDescr
)
77 if ( prop
.Name
== "ComponentData" || prop
.Name
== "DocumentTitle"
78 || prop
.Name
== "InteractionHandler" || prop
.Name
== "JumpMark"
79 // || prop.Name == "Password" // makes no sense for embedded objects
80 || prop
.Name
== "Preview" || prop
.Name
== "ReadOnly"
81 || prop
.Name
== "StartPresentation" || prop
.Name
== "RepairPackage"
82 || prop
.Name
== "StatusIndicator" || prop
.Name
== "ViewData"
83 || prop
.Name
== "ViewId" || prop
.Name
== "MacroExecutionMode"
84 || prop
.Name
== "UpdateDocMode" || prop
.Name
== "Referer"
85 || (prop
.Name
== "DocumentBaseURL" && bCanUseDocumentBaseURL
) )
87 aResult
.realloc( ++nResLen
);
88 aResult
.getArray()[nResLen
-1] = prop
;
96 static uno::Sequence
< beans::PropertyValue
> addAsTemplate( const uno::Sequence
< beans::PropertyValue
>& aOrig
)
98 bool bAsTemplateSet
= false;
99 sal_Int32 nLength
= aOrig
.getLength();
100 uno::Sequence
< beans::PropertyValue
> aResult( aOrig
);
102 for ( sal_Int32 nInd
= 0; nInd
< nLength
; nInd
++ )
104 if ( aResult
[nInd
].Name
== "AsTemplate" )
106 aResult
.getArray()[nInd
].Value
<<= true;
107 bAsTemplateSet
= true;
111 if ( !bAsTemplateSet
)
113 aResult
.realloc( nLength
+ 1 );
114 auto pResult
= aResult
.getArray();
115 pResult
[nLength
].Name
= "AsTemplate";
116 pResult
[nLength
].Value
<<= true;
123 static uno::Reference
< io::XInputStream
> createTempInpStreamFromStor(
124 const uno::Reference
< embed::XStorage
>& xStorage
,
125 const uno::Reference
< uno::XComponentContext
>& xContext
)
127 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "The storage can not be empty!" );
129 uno::Reference
< io::XInputStream
> xResult
;
131 uno::Reference
< io::XStream
> xTempStream( io::TempFile::create(xContext
), uno::UNO_QUERY_THROW
);
133 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory( embed::StorageFactory::create(xContext
) );
135 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xTempStream
),
136 uno::Any(embed::ElementModes::READWRITE
) };
137 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
138 uno::UNO_QUERY_THROW
);
142 xStorage
->copyToStorage( xTempStorage
);
143 } catch( const uno::Exception
& )
145 css::uno::Any anyEx
= cppu::getCaughtException();
146 throw embed::StorageWrappedTargetException(
147 u
"Can't copy storage!"_ustr
,
148 uno::Reference
< uno::XInterface
>(),
153 if ( xTempStorage
.is() )
154 xTempStorage
->dispose();
156 catch ( const uno::Exception
& )
161 uno::Reference
< io::XOutputStream
> xTempOut
= xTempStream
->getOutputStream();
163 xTempOut
->closeOutput();
165 catch ( const uno::Exception
& )
169 xResult
= xTempStream
->getInputStream();
176 static void TransferMediaType( const uno::Reference
< embed::XStorage
>& i_rSource
, const uno::Reference
< embed::XStorage
>& i_rTarget
)
180 const uno::Reference
< beans::XPropertySet
> xSourceProps( i_rSource
, uno::UNO_QUERY_THROW
);
181 const uno::Reference
< beans::XPropertySet
> xTargetProps( i_rTarget
, uno::UNO_QUERY_THROW
);
182 static constexpr OUString
sMediaTypePropName( u
"MediaType"_ustr
);
183 xTargetProps
->setPropertyValue( sMediaTypePropName
, xSourceProps
->getPropertyValue( sMediaTypePropName
) );
185 catch( const uno::Exception
& )
187 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
192 static uno::Reference
< util::XCloseable
> CreateDocument( const uno::Reference
< uno::XComponentContext
>& _rxContext
,
193 const OUString
& _rDocumentServiceName
, bool _bEmbeddedScriptSupport
, const bool i_bDocumentRecoverySupport
)
195 static constexpr OUStringLiteral sEmbeddedObject
= u
"EmbeddedObject";
196 static constexpr OUStringLiteral sEmbeddedScriptSupport
= u
"EmbeddedScriptSupport";
197 static constexpr OUStringLiteral sDocumentRecoverySupport
= u
"DocumentRecoverySupport";
198 ::comphelper::NamedValueCollection aArguments
;
199 aArguments
.put( sEmbeddedObject
, true );
200 aArguments
.put( sEmbeddedScriptSupport
, _bEmbeddedScriptSupport
);
201 aArguments
.put( sDocumentRecoverySupport
, i_bDocumentRecoverySupport
);
203 uno::Reference
< uno::XInterface
> xDocument
;
206 xDocument
= _rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
207 _rDocumentServiceName
, aArguments
.getWrappedPropertyValues(), _rxContext
);
209 catch( const uno::Exception
& )
211 // if an embedded object implementation does not support XInitialization,
212 // the default factory from cppuhelper will throw an
213 // IllegalArgumentException when we try to create the instance with arguments.
214 // Okay, so we fall back to creating the instance without any arguments.
215 OSL_FAIL("Consider implementing interface XInitialization to avoid duplicate construction");
216 xDocument
= _rxContext
->getServiceManager()->createInstanceWithContext( _rDocumentServiceName
, _rxContext
);
219 SAL_WARN_IF(!xDocument
.is(), "embeddedobj.common", "Service " << _rDocumentServiceName
<< " is not available?");
220 return uno::Reference
< util::XCloseable
>( xDocument
, uno::UNO_QUERY
);
224 static void SetDocToEmbedded( const uno::Reference
< frame::XModel
>& rDocument
, const OUString
& aModuleName
)
229 uno::Sequence
< beans::PropertyValue
> aSeq
{ comphelper::makePropertyValue(u
"SetEmbedded"_ustr
, true) };
230 rDocument
->attachResource( OUString(), aSeq
);
232 if ( !aModuleName
.isEmpty() )
236 uno::Reference
< frame::XModule
> xModule( rDocument
, uno::UNO_QUERY_THROW
);
237 xModule
->setIdentifier( aModuleName
);
239 catch( const uno::Exception
& )
245 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
246 const uno::Reference
< embed::XStorage
>& xNewObjectStorage
,
247 const OUString
& aNewName
)
249 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
251 SAL_WARN_IF( xNewObjectStorage
!= m_xObjectStorage
, "embeddedobj.common", "The storage must be the same!" );
255 auto xOldObjectStorage
= m_xObjectStorage
;
256 m_xObjectStorage
= xNewObjectStorage
;
257 m_xParentStorage
= xNewParentStorage
;
258 m_aEntryName
= aNewName
;
260 // the linked document should not be switched
263 uno::Reference
< document::XStorageBasedDocument
> xDoc( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
265 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
269 if ( xOldObjectStorage
.is() )
270 xOldObjectStorage
->dispose();
272 catch ( const uno::Exception
& )
278 void OCommonEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
279 const OUString
& aNewName
)
281 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
284 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
286 uno::Reference
< embed::XStorage
> xNewOwnStorage
= xNewParentStorage
->openStorageElement( aNewName
, nStorageMode
);
287 SAL_WARN_IF( !xNewOwnStorage
.is(), "embeddedobj.common", "The method can not return empty reference!" );
289 SwitchOwnPersistence( xNewParentStorage
, xNewOwnStorage
, aNewName
);
293 void OCommonEmbeddedObject::EmbedAndReparentDoc_Impl( const uno::Reference
< util::XCloseable
>& i_rxDocument
) const
295 SetDocToEmbedded( uno::Reference
< frame::XModel
>( i_rxDocument
, uno::UNO_QUERY
), m_aModuleName
);
299 uno::Reference
< container::XChild
> xChild( i_rxDocument
, uno::UNO_QUERY
);
301 xChild
->setParent( m_xParent
);
303 catch( const lang::NoSupportException
& )
305 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::EmbedAndReparentDoc: cannot set parent at document!" );
310 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::InitNewDocument_Impl()
312 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
313 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
315 uno::Reference
< frame::XModel
> xModel( xDocument
, uno::UNO_QUERY
);
316 uno::Reference
< frame::XLoadable
> xLoadable( xModel
, uno::UNO_QUERY_THROW
);
320 // set the document mode to embedded as the first action on document!!!
321 EmbedAndReparentDoc_Impl( xDocument
);
323 // if we have a storage to recover the document from, do not use initNew, but instead load from that storage
324 bool bInitNew
= true;
325 if ( m_xRecoveryStorage
.is() )
327 uno::Reference
< document::XStorageBasedDocument
> xDoc( xLoadable
, uno::UNO_QUERY
);
328 SAL_WARN_IF( !xDoc
.is(), "embeddedobj.common", "OCommonEmbeddedObject::InitNewDocument_Impl: cannot recover from a storage when the document is not storage based!" );
331 ::comphelper::NamedValueCollection aLoadArgs
;
332 FillDefaultLoadArgs_Impl( m_xRecoveryStorage
, aLoadArgs
);
334 xDoc
->loadFromStorage( m_xRecoveryStorage
, aLoadArgs
.getPropertyValues() );
335 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
342 // init document as a new
343 xLoadable
->initNew();
345 xModel
->attachResource( xModel
->getURL(), m_aDocMediaDescriptor
);
347 catch( const uno::Exception
& )
349 if ( xDocument
.is() )
353 xDocument
->close( true );
355 catch( const uno::Exception
& )
366 bool OCommonEmbeddedObject::getAllowLinkUpdate() const
368 // assume we can update if we can't determine a parent
369 bool bAllowLinkUpdate(true);
373 uno::Reference
<container::XChild
> xParent(m_xParent
, uno::UNO_QUERY
);
376 uno::Reference
<container::XChild
> xGrandParent(xParent
->getParent(), uno::UNO_QUERY
);
379 xParent
= std::move(xGrandParent
);
382 uno::Reference
<beans::XPropertySet
> xPropSet(xParent
, uno::UNO_QUERY
);
385 uno::Any aAny
= xPropSet
->getPropertyValue(u
"AllowLinkUpdate"_ustr
);
386 aAny
>>= bAllowLinkUpdate
;
389 catch (const uno::Exception
&)
393 SAL_WARN_IF(!bAllowLinkUpdate
, "embeddedobj.common", "getAllowLinkUpdate is false");
395 return bAllowLinkUpdate
;
398 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadLink_Impl()
400 if (!getAllowLinkUpdate())
403 sal_Int32 nLen
= m_bLinkHasPassword
? 3 : 2;
404 uno::Sequence
< beans::PropertyValue
> aArgs( m_aDocMediaDescriptor
.getLength() + nLen
);
405 auto pArgs
= aArgs
.getArray();
408 if (m_aLinkTempFile
.is())
409 sURL
= m_aLinkTempFile
->getUri();
412 if (INetURLObject(sURL
).IsExoticProtocol())
414 SAL_WARN("embeddedobj.common", "Ignore exotic protocol: " << pArgs
[0].Value
);
418 pArgs
[0].Name
= "URL";
419 pArgs
[0].Value
<<= sURL
;
421 pArgs
[1].Name
= "FilterName";
422 pArgs
[1].Value
<<= m_aLinkFilterName
;
424 if ( m_bLinkHasPassword
)
426 pArgs
[2].Name
= "Password";
427 pArgs
[2].Value
<<= m_aLinkPassword
;
430 for ( sal_Int32 nInd
= 0; nInd
< m_aDocMediaDescriptor
.getLength(); nInd
++ )
432 // return early if this document is not trusted to open links
433 if (m_aDocMediaDescriptor
[nInd
].Name
== utl::MediaDescriptor::PROP_REFERRER
)
436 m_aDocMediaDescriptor
[nInd
].Value
>>= referer
;
437 if (SvtSecurityOptions::isUntrustedReferer(referer
))
440 pArgs
[nInd
+nLen
].Name
= m_aDocMediaDescriptor
[nInd
].Name
;
441 pArgs
[nInd
+nLen
].Value
= m_aDocMediaDescriptor
[nInd
].Value
;
444 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
445 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
446 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY_THROW
);
450 handleLinkedOLE(CopyBackToOLELink::CopyLinkToTemp
);
452 // the document is not really an embedded one, it is a link
453 EmbedAndReparentDoc_Impl( xDocument
);
456 xLoadable
->load( aArgs
);
458 if ( !m_bLinkHasPassword
)
460 // check if there is a password to cache
461 uno::Reference
< frame::XModel
> xModel( xLoadable
, uno::UNO_QUERY_THROW
);
462 const uno::Sequence
< beans::PropertyValue
> aProps
= xModel
->getArgs();
463 for ( beans::PropertyValue
const & prop
: aProps
)
464 if ( prop
.Name
== "Password" && ( prop
.Value
>>= m_aLinkPassword
) )
466 m_bLinkHasPassword
= true;
471 catch( const uno::Exception
& )
473 if ( xDocument
.is() )
477 xDocument
->close( true );
479 catch( const uno::Exception
& )
491 OUString
OCommonEmbeddedObject::GetFilterName( sal_Int32 nVersion
) const
493 OUString aFilterName
= GetPresetFilterName();
494 if ( aFilterName
.isEmpty() )
496 OUString sDocumentServiceName
= GetDocumentServiceName();
497 if (comphelper::IsFuzzing() && nVersion
== SOFFICE_FILEFORMAT_CURRENT
&&
498 sDocumentServiceName
== "com.sun.star.chart2.ChartDocument")
500 return u
"chart8"_ustr
;
503 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
504 aFilterName
= aHelper
.GetDefaultFilterFromServiceName(sDocumentServiceName
, nVersion
);
506 // If no filter is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
507 if (aFilterName
.isEmpty() && nVersion
== SOFFICE_FILEFORMAT_CURRENT
)
508 aFilterName
= aHelper
.GetDefaultFilterFromServiceName(GetDocumentServiceName(), SOFFICE_FILEFORMAT_60
);
509 } catch( const uno::Exception
& )
517 void OCommonEmbeddedObject::FillDefaultLoadArgs_Impl( const uno::Reference
< embed::XStorage
>& i_rxStorage
,
518 ::comphelper::NamedValueCollection
& o_rLoadArgs
) const
520 o_rLoadArgs
.put( u
"DocumentBaseURL"_ustr
, GetBaseURL_Impl() );
521 o_rLoadArgs
.put( u
"HierarchicalDocumentName"_ustr
, m_aEntryName
);
522 o_rLoadArgs
.put( u
"ReadOnly"_ustr
, m_bReadOnly
);
524 OUString aFilterName
= GetFilterName( ::comphelper::OStorageHelper::GetXStorageFormat( i_rxStorage
) );
525 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "OCommonEmbeddedObject::FillDefaultLoadArgs_Impl: Wrong document service name!" );
526 if ( aFilterName
.isEmpty() )
527 throw io::IOException(); // TODO: error message/code
529 o_rLoadArgs
.put( u
"FilterName"_ustr
, aFilterName
);
533 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::LoadDocumentFromStorage_Impl()
535 ENSURE_OR_THROW( m_xObjectStorage
.is(), "no object storage" );
537 const uno::Reference
< embed::XStorage
> xSourceStorage( m_xRecoveryStorage
.is() ? m_xRecoveryStorage
: m_xObjectStorage
);
539 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
540 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
542 //#i103460# ODF: take the size given from the parent frame as default
543 uno::Reference
< chart2::XChartDocument
> xChart( xDocument
, uno::UNO_QUERY
);
546 uno::Reference
< embed::XVisualObject
> xChartVisualObject( xChart
, uno::UNO_QUERY
);
547 if( xChartVisualObject
.is() )
548 xChartVisualObject
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
, m_aDefaultSizeForChart_In_100TH_MM
);
551 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY
);
552 uno::Reference
< document::XStorageBasedDocument
> xDoc( xDocument
, uno::UNO_QUERY
);
553 if ( !xDoc
.is() && !xLoadable
.is() )
554 throw uno::RuntimeException();
556 ::comphelper::NamedValueCollection aLoadArgs
;
557 FillDefaultLoadArgs_Impl( xSourceStorage
, aLoadArgs
);
559 uno::Reference
< io::XInputStream
> xTempInpStream
;
562 xTempInpStream
= createTempInpStreamFromStor( xSourceStorage
, m_xContext
);
563 if ( !xTempInpStream
.is() )
564 throw uno::RuntimeException();
566 OUString aTempFileURL
;
569 // no need to let the file stay after the stream is removed since the embedded document
570 // can not be stored directly
571 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempInpStream
, uno::UNO_QUERY_THROW
);
572 xTempStreamProps
->getPropertyValue(u
"Uri"_ustr
) >>= aTempFileURL
;
574 catch( const uno::Exception
& )
578 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
580 aLoadArgs
.put( u
"URL"_ustr
, aTempFileURL
);
581 aLoadArgs
.put( u
"InputStream"_ustr
, xTempInpStream
);
585 aLoadArgs
.merge( m_aDocMediaDescriptor
, true );
589 // set the document mode to embedded as the first step!!!
590 EmbedAndReparentDoc_Impl( xDocument
);
594 aLoadArgs
.put(u
"ReadOnly"_ustr
, true);
599 xDoc
->loadFromStorage( xSourceStorage
, aLoadArgs
.getPropertyValues() );
600 if ( xSourceStorage
!= m_xObjectStorage
)
601 SwitchDocToStorage_Impl( xDoc
, m_xObjectStorage
);
604 xLoadable
->load( aLoadArgs
.getPropertyValues() );
606 catch( const uno::Exception
& )
608 if ( xDocument
.is() )
612 xDocument
->close( true );
614 catch( const uno::Exception
& )
616 DBG_UNHANDLED_EXCEPTION("embeddedobj.common");
627 uno::Reference
< io::XInputStream
> OCommonEmbeddedObject::StoreDocumentToTempStream_Impl(
628 sal_Int32 nStorageFormat
,
629 const OUString
& aBaseURL
,
630 const OUString
& aHierarchName
)
632 uno::Reference
< io::XOutputStream
> xTempOut(
633 io::TempFile::create(m_xContext
),
634 uno::UNO_QUERY_THROW
);
635 uno::Reference
< io::XInputStream
> aResult( xTempOut
, uno::UNO_QUERY_THROW
);
637 uno::Reference
< frame::XStorable
> xStorable
;
639 osl::MutexGuard
aGuard( m_aMutex
);
640 if ( m_xDocHolder
.is() )
641 xStorable
.set( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
644 if( !xStorable
.is() )
645 throw uno::RuntimeException(u
"No storage is provided for storing!"_ustr
); // TODO:
647 OUString aFilterName
= GetFilterName( nStorageFormat
);
649 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
650 if ( aFilterName
.isEmpty() )
651 throw io::IOException(u
"No filter name provided / Wrong document service name"_ustr
); // TODO:
653 uno::Sequence
< beans::PropertyValue
> aArgs
{
654 comphelper::makePropertyValue(u
"FilterName"_ustr
, aFilterName
),
655 comphelper::makePropertyValue(u
"OutputStream"_ustr
, xTempOut
),
656 comphelper::makePropertyValue(u
"DocumentBaseURL"_ustr
, aBaseURL
),
657 comphelper::makePropertyValue(u
"HierarchicalDocumentName"_ustr
, aHierarchName
)
660 xStorable
->storeToURL( u
"private:stream"_ustr
, aArgs
);
663 xTempOut
->closeOutput();
665 catch( const uno::Exception
& )
667 SAL_WARN( "embeddedobj.common", "Looks like stream was closed already" );
674 void OCommonEmbeddedObject::SaveObject_Impl()
676 if ( !m_xClientSite
.is() )
681 // check whether the component is modified,
682 // if not there is no need for storing
683 uno::Reference
< util::XModifiable
> xModifiable( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
684 if ( xModifiable
.is() && !xModifiable
->isModified() )
687 catch( const uno::Exception
& )
691 m_xClientSite
->saveObject();
693 catch( const uno::Exception
& )
695 SAL_WARN( "embeddedobj.common", "The object was not stored!" );
700 OUString
OCommonEmbeddedObject::GetBaseURL_Impl() const
704 if ( m_xClientSite
.is() )
708 uno::Reference
< frame::XModel
> xParentModel( m_xClientSite
->getComponent(), uno::UNO_QUERY_THROW
);
709 const uno::Sequence
< beans::PropertyValue
> aModelProps
= xParentModel
->getArgs();
710 for ( beans::PropertyValue
const & prop
: aModelProps
)
711 if ( prop
.Name
== "DocumentBaseURL" )
713 prop
.Value
>>= aBaseURL
;
717 catch( const uno::Exception
& )
721 if ( aBaseURL
.isEmpty() )
723 for ( beans::PropertyValue
const & prop
: m_aDocMediaDescriptor
)
724 if ( prop
.Name
== "DocumentBaseURL" )
726 prop
.Value
>>= aBaseURL
;
731 if ( aBaseURL
.isEmpty() )
732 aBaseURL
= m_aDefaultParentBaseURL
;
738 OUString
OCommonEmbeddedObject::GetBaseURLFrom_Impl(
739 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
740 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
744 for ( beans::PropertyValue
const & prop
: lArguments
)
745 if ( prop
.Name
== "DocumentBaseURL" )
747 prop
.Value
>>= aBaseURL
;
751 if ( aBaseURL
.isEmpty() )
753 for ( beans::PropertyValue
const & prop
: lObjArgs
)
754 if ( prop
.Name
== "DefaultParentBaseURL" )
756 prop
.Value
>>= aBaseURL
;
765 void OCommonEmbeddedObject::SwitchDocToStorage_Impl( const uno::Reference
< document::XStorageBasedDocument
>& xDoc
, const uno::Reference
< embed::XStorage
>& xStorage
)
767 xDoc
->switchToStorage( xStorage
);
769 uno::Reference
< util::XModifiable
> xModif( xDoc
, uno::UNO_QUERY
);
771 xModif
->setModified( false );
773 if ( m_xRecoveryStorage
.is() )
774 m_xRecoveryStorage
.clear();
779 beans::PropertyValue
getStringPropertyValue(const uno::Sequence
<beans::PropertyValue
>& rProps
,
780 const OUString
& rName
)
784 for (beans::PropertyValue
const & prop
: rProps
)
786 if (prop
.Name
== rName
)
793 return comphelper::makePropertyValue(rName
, aStr
);
798 void OCommonEmbeddedObject::StoreDocToStorage_Impl(
799 const uno::Reference
<embed::XStorage
>& xStorage
,
800 const uno::Sequence
<beans::PropertyValue
>& rMediaArgs
,
801 const uno::Sequence
<beans::PropertyValue
>& rObjArgs
,
802 sal_Int32 nStorageFormat
,
803 const OUString
& aHierarchName
,
804 bool bAttachToTheStorage
)
806 SAL_WARN_IF( !xStorage
.is(), "embeddedobj.common", "No storage is provided for storing!" );
808 if ( !xStorage
.is() )
809 throw uno::RuntimeException(); // TODO:
811 uno::Reference
< document::XStorageBasedDocument
> xDoc
;
813 osl::MutexGuard
aGuard( m_aMutex
);
814 if ( m_xDocHolder
.is() )
815 xDoc
.set( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
818 OUString aBaseURL
= GetBaseURLFrom_Impl(rMediaArgs
, rObjArgs
);
822 OUString aFilterName
= GetFilterName( nStorageFormat
);
824 // No filter found? Try the older format, e.g. Base has only that.
825 if (aFilterName
.isEmpty() && nStorageFormat
== SOFFICE_FILEFORMAT_CURRENT
)
826 aFilterName
= GetFilterName( SOFFICE_FILEFORMAT_60
);
828 SAL_WARN_IF( aFilterName
.isEmpty(), "embeddedobj.common", "Wrong document service name!" );
829 if ( aFilterName
.isEmpty() )
830 throw io::IOException(); // TODO:
832 uno::Sequence
<beans::PropertyValue
> aArgs
{
833 comphelper::makePropertyValue(u
"FilterName"_ustr
, aFilterName
),
834 comphelper::makePropertyValue(u
"HierarchicalDocumentName"_ustr
, aHierarchName
),
835 comphelper::makePropertyValue(u
"DocumentBaseURL"_ustr
, aBaseURL
),
836 getStringPropertyValue(rObjArgs
, u
"SourceShellID"_ustr
),
837 getStringPropertyValue(rObjArgs
, u
"DestinationShellID"_ustr
),
840 xDoc
->storeToStorage( xStorage
, aArgs
);
841 if ( bAttachToTheStorage
)
842 SwitchDocToStorage_Impl( xDoc
, xStorage
);
846 // store document to temporary stream based on temporary file
847 uno::Reference
< io::XInputStream
> xTempIn
= StoreDocumentToTempStream_Impl( nStorageFormat
, aBaseURL
, aHierarchName
);
849 SAL_WARN_IF( !xTempIn
.is(), "embeddedobj.common", "The stream reference can not be empty!" );
851 // open storage based on document temporary file for reading
852 uno::Reference
< lang::XSingleServiceFactory
> xStorageFactory
= embed::StorageFactory::create(m_xContext
);
854 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xTempIn
) };
855 uno::Reference
< embed::XStorage
> xTempStorage( xStorageFactory
->createInstanceWithArguments( aArgs
),
856 uno::UNO_QUERY_THROW
);
858 // object storage must be committed automatically
859 xTempStorage
->copyToStorage( xStorage
);
864 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::CreateDocFromMediaDescr_Impl(
865 const uno::Sequence
< beans::PropertyValue
>& aMedDescr
)
867 uno::Reference
< util::XCloseable
> xDocument( CreateDocument( m_xContext
, GetDocumentServiceName(),
868 m_bEmbeddedScriptSupport
, m_bDocumentRecoverySupport
) );
870 uno::Reference
< frame::XLoadable
> xLoadable( xDocument
, uno::UNO_QUERY_THROW
);
874 // set the document mode to embedded as the first action on the document!!!
875 EmbedAndReparentDoc_Impl( xDocument
);
877 xLoadable
->load( addAsTemplate( aMedDescr
) );
879 catch( const uno::Exception
& )
881 if ( xDocument
.is() )
885 xDocument
->close( true );
887 catch( const uno::Exception
& )
899 uno::Reference
< util::XCloseable
> OCommonEmbeddedObject::CreateTempDocFromLink_Impl()
901 uno::Reference
< util::XCloseable
> xResult
;
903 SAL_WARN_IF( !m_bIsLinkURL
, "embeddedobj.common", "The object is not a linked one!" );
905 uno::Sequence
< beans::PropertyValue
> aTempMediaDescr
;
907 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
909 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
911 catch ( const beans::IllegalTypeException
& )
913 // the container just has an unknown type, use current file format
915 catch ( const uno::Exception
& )
917 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
920 if ( m_xDocHolder
->GetComponent().is() )
922 aTempMediaDescr
.realloc( 4 );
924 // TODO/LATER: may be private:stream should be used as target URL
925 OUString aTempFileURL
;
926 uno::Reference
< io::XInputStream
> xTempStream
= StoreDocumentToTempStream_Impl( SOFFICE_FILEFORMAT_CURRENT
,
931 // no need to let the file stay after the stream is removed since the embedded document
932 // can not be stored directly
933 uno::Reference
< beans::XPropertySet
> xTempStreamProps( xTempStream
, uno::UNO_QUERY_THROW
);
934 xTempStreamProps
->getPropertyValue(u
"Uri"_ustr
) >>= aTempFileURL
;
936 catch( const uno::Exception
& )
940 SAL_WARN_IF( aTempFileURL
.isEmpty(), "embeddedobj.common", "Couldn't retrieve temporary file URL!" );
943 = { comphelper::makePropertyValue(u
"URL"_ustr
, aTempFileURL
),
944 comphelper::makePropertyValue(u
"InputStream"_ustr
, xTempStream
),
945 comphelper::makePropertyValue(u
"FilterName"_ustr
, GetFilterName( nStorageFormat
)),
946 comphelper::makePropertyValue(u
"AsTemplate"_ustr
, true) };
950 aTempMediaDescr
= { comphelper::makePropertyValue(
952 // tdf#141529 use URL of the linked TempFile if it exists
953 m_aLinkTempFile
.is() ? m_aLinkTempFile
->getUri() : m_aLinkURL
),
954 comphelper::makePropertyValue(u
"FilterName"_ustr
, m_aLinkFilterName
) };
957 xResult
= CreateDocFromMediaDescr_Impl( aTempMediaDescr
);
963 void SAL_CALL
OCommonEmbeddedObject::setPersistentEntry(
964 const uno::Reference
< embed::XStorage
>& xStorage
,
965 const OUString
& sEntName
,
966 sal_Int32 nEntryConnectionMode
,
967 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
968 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
970 // the type of the object must be already set
971 // a kind of typedetection should be done in the factory
973 ::osl::MutexGuard
aGuard( m_aMutex
);
975 throw lang::DisposedException(); // TODO
977 if ( !xStorage
.is() )
978 throw lang::IllegalArgumentException( u
"No parent storage is provided!"_ustr
,
979 static_cast< ::cppu::OWeakObject
* >(this),
982 if ( sEntName
.isEmpty() )
983 throw lang::IllegalArgumentException( u
"Empty element name is provided!"_ustr
,
984 static_cast< ::cppu::OWeakObject
* >(this),
987 // May be LOADED should be forbidden here ???
988 if ( ( m_nObjectState
!= -1 || nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
989 && ( m_nObjectState
== -1 || nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
) )
991 // if the object is not loaded
992 // it can not get persistent representation without initialization
994 // if the object is loaded
995 // it can switch persistent representation only without initialization
997 throw embed::WrongStateException(
998 u
"Can't change persistent representation of activated object!"_ustr
,
999 static_cast< ::cppu::OWeakObject
* >(this) );
1002 if ( m_bWaitSaveCompleted
)
1004 if ( nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
)
1005 throw embed::WrongStateException(
1006 u
"The object waits for saveCompleted() call!"_ustr
,
1007 static_cast< ::cppu::OWeakObject
* >(this) );
1008 // saveCompleted is expected, handle it accordingly
1009 if ( m_xNewParentStorage
== xStorage
&& m_aNewEntryName
== sEntName
)
1011 saveCompleted( true );
1015 // if a completely different entry is provided, switch first back to the old persistence in saveCompleted
1016 // and then switch to the target persistence
1017 bool bSwitchFurther
= ( m_xParentStorage
!= xStorage
|| m_aEntryName
!= sEntName
);
1018 saveCompleted( false );
1019 if ( !bSwitchFurther
)
1023 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1024 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1025 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1028 m_aEntryName
= sEntName
;
1032 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
1034 // detect entry existence
1035 bool bElExists
= xNameAccess
->hasByName( sEntName
);
1037 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
,
1038 nEntryConnectionMode
!= embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
);
1040 m_bReadOnly
= false;
1041 for ( beans::PropertyValue
const & prop
: lArguments
)
1042 if ( prop
.Name
== "ReadOnly" )
1043 prop
.Value
>>= m_bReadOnly
;
1045 // TODO: use lObjArgs for StoreVisualReplacement
1046 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1047 if ( prop
.Name
== "OutplaceDispatchInterceptor" )
1049 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1050 if ( prop
.Value
>>= xDispatchInterceptor
)
1051 m_xDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1053 else if ( prop
.Name
== "DefaultParentBaseURL" )
1055 prop
.Value
>>= m_aDefaultParentBaseURL
;
1057 else if ( prop
.Name
== "Parent" )
1059 prop
.Value
>>= m_xParent
;
1061 else if ( prop
.Name
== "IndividualMiscStatus" )
1063 sal_Int64 nMiscStatus
=0;
1064 prop
.Value
>>= nMiscStatus
;
1065 m_nMiscStatus
|= nMiscStatus
;
1067 else if ( prop
.Name
== "CloneFrom" )
1069 uno::Reference
< embed::XEmbeddedObject
> xObj
;
1070 prop
.Value
>>= xObj
;
1073 m_bHasClonedSize
= true;
1074 m_aClonedSize
= xObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
1075 m_nClonedMapUnit
= xObj
->getMapUnit( embed::Aspects::MSOLE_CONTENT
);
1078 else if ( prop
.Name
== "OutplaceFrameProperties" )
1080 uno::Sequence
< uno::Any
> aOutFrameProps
;
1081 uno::Sequence
< beans::NamedValue
> aOutFramePropsTyped
;
1082 if ( prop
.Value
>>= aOutFrameProps
)
1084 m_xDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1086 else if ( prop
.Value
>>= aOutFramePropsTyped
)
1088 aOutFrameProps
.realloc( aOutFramePropsTyped
.getLength() );
1089 uno::Any
* pProp
= aOutFrameProps
.getArray();
1090 for ( const beans::NamedValue
* pTypedProp
= aOutFramePropsTyped
.getConstArray();
1091 pTypedProp
!= aOutFramePropsTyped
.getConstArray() + aOutFramePropsTyped
.getLength();
1092 ++pTypedProp
, ++pProp
1095 *pProp
<<= *pTypedProp
;
1097 m_xDocHolder
->SetOutplaceFrameProperties( aOutFrameProps
);
1100 SAL_WARN( "embeddedobj.common", "OCommonEmbeddedObject::setPersistentEntry: illegal type for argument 'OutplaceFrameProperties'!" );
1102 else if ( prop
.Name
== "ModuleName" )
1104 prop
.Value
>>= m_aModuleName
;
1106 else if ( prop
.Name
== "EmbeddedScriptSupport" )
1108 OSL_VERIFY( prop
.Value
>>= m_bEmbeddedScriptSupport
);
1110 else if ( prop
.Name
== "DocumentRecoverySupport" )
1112 OSL_VERIFY( prop
.Value
>>= m_bDocumentRecoverySupport
);
1114 else if ( prop
.Name
== "RecoveryStorage" )
1116 OSL_VERIFY( prop
.Value
>>= m_xRecoveryStorage
);
1120 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1122 SwitchOwnPersistence( xStorage
, sEntName
);
1124 if ( nEntryConnectionMode
== embed::EntryInitModes::DEFAULT_INIT
)
1128 // the initialization from existing storage allows to leave object in loaded state
1129 m_nObjectState
= embed::EmbedStates::LOADED
;
1133 m_xDocHolder
->SetComponent( InitNewDocument_Impl(), m_bReadOnly
);
1134 if ( !m_xDocHolder
->GetComponent().is() )
1135 throw io::IOException(); // TODO: can not create document
1137 m_nObjectState
= embed::EmbedStates::RUNNING
;
1142 if ( ( nStorageMode
& embed::ElementModes::READWRITE
) != embed::ElementModes::READWRITE
)
1143 throw io::IOException();
1145 if ( nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
1147 // the document just already changed its storage to store to
1148 // the links to OOo documents for now ignore this call
1149 // TODO: OOo links will have persistence so it will be switched here
1151 else if ( nEntryConnectionMode
== embed::EntryInitModes::TRUNCATE_INIT
)
1153 if ( m_xRecoveryStorage
.is() )
1154 TransferMediaType( m_xRecoveryStorage
, m_xObjectStorage
);
1157 m_xDocHolder
->SetComponent( InitNewDocument_Impl(), m_bReadOnly
);
1159 if ( !m_xDocHolder
->GetComponent().is() )
1160 throw io::IOException(); // TODO: can not create document
1162 m_nObjectState
= embed::EmbedStates::RUNNING
;
1164 else if ( nEntryConnectionMode
== embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
)
1166 m_xDocHolder
->SetComponent( CreateDocFromMediaDescr_Impl( lArguments
), m_bReadOnly
);
1167 m_nObjectState
= embed::EmbedStates::RUNNING
;
1169 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1174 throw lang::IllegalArgumentException( u
"Wrong connection mode is provided!"_ustr
,
1175 static_cast< ::cppu::OWeakObject
* >(this),
1181 void SAL_CALL
OCommonEmbeddedObject::storeToEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1182 const OUString
& sEntName
,
1183 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1184 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1186 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1188 throw lang::DisposedException(); // TODO
1190 if ( m_nObjectState
== -1 )
1192 // the object is still not loaded
1193 throw embed::WrongStateException( u
"Can't store object without persistence!"_ustr
,
1194 static_cast< ::cppu::OWeakObject
* >(this) );
1197 if ( m_bWaitSaveCompleted
)
1198 throw embed::WrongStateException(
1199 u
"The object waits for saveCompleted() call!"_ustr
,
1200 static_cast< ::cppu::OWeakObject
* >(this) );
1202 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1203 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1204 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1208 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1210 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1211 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1213 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1215 catch ( const beans::IllegalTypeException
& )
1217 // the container just has an unknown type, use current file format
1219 catch ( const uno::Exception
& )
1221 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1223 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1225 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1226 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1227 // setting MediaType is done later anyway, no need to do it here
1232 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1234 catch ( const beans::IllegalTypeException
& )
1236 // the container just has an unknown type, use current file format
1238 catch ( const uno::Exception
& )
1240 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1243 bool bTryOptimization
= false;
1244 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1246 // StoreVisualReplacement and VisualReplacement args have no sense here
1247 if ( prop
.Name
== "CanTryOptimization" )
1248 prop
.Value
>>= bTryOptimization
;
1251 bool bSwitchBackToLoaded
= false;
1253 // Storing to different format can be done only in running state.
1254 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1256 // TODO/LATER: copying is not legal for documents with relative links.
1257 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1259 bool bOptimizationWorks
= false;
1260 if ( bTryOptimization
)
1264 // try to use optimized copying
1265 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1266 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1267 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1268 bOptimizationWorks
= true;
1270 catch( const uno::Exception
& )
1275 if ( !bOptimizationWorks
)
1276 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1280 changeState( embed::EmbedStates::RUNNING
);
1281 bSwitchBackToLoaded
= true;
1285 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1288 uno::Reference
< embed::XStorage
> xSubStorage
=
1289 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1291 if ( !xSubStorage
.is() )
1292 throw uno::RuntimeException(); //TODO
1295 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1296 StoreDocToStorage_Impl(
1297 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1300 if ( bSwitchBackToLoaded
)
1301 changeState( embed::EmbedStates::LOADED
);
1303 // TODO: should the listener notification be done?
1307 void SAL_CALL
OCommonEmbeddedObject::storeAsEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1308 const OUString
& sEntName
,
1309 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1310 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1312 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1314 throw lang::DisposedException(); // TODO
1316 bool AutoSaveEvent
= false;
1317 utl::MediaDescriptor
lArgs(lObjArgs
);
1318 lArgs
[utl::MediaDescriptor::PROP_AUTOSAVEEVENT
] >>= AutoSaveEvent
;
1320 if ( m_nObjectState
== -1 )
1322 // the object is still not loaded
1323 throw embed::WrongStateException( u
"Can't store object without persistence!"_ustr
,
1324 static_cast< ::cppu::OWeakObject
* >(this) );
1327 if ( m_bWaitSaveCompleted
)
1328 throw embed::WrongStateException(
1329 u
"The object waits for saveCompleted() call!"_ustr
,
1330 static_cast< ::cppu::OWeakObject
* >(this) );
1332 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1333 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1334 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1337 m_aNewEntryName
= sEntName
;
1339 if ( !AutoSaveEvent
)
1340 handleLinkedOLE(CopyBackToOLELink::CopyTempToLink
);
1345 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1347 sal_Int32 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1348 sal_Int32 nOriginalStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1350 nTargetStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( xStorage
);
1352 catch ( const beans::IllegalTypeException
& )
1354 // the container just has an unknown type, use current file format
1356 catch ( const uno::Exception
& )
1358 SAL_WARN( "embeddedobj.common", "Can not retrieve target storage media type!" );
1360 if (nTargetStorageFormat
== SOFFICE_FILEFORMAT_60
)
1362 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1363 nTargetStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1364 // setting MediaType is done later anyway, no need to do it here
1369 nOriginalStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1371 catch ( const beans::IllegalTypeException
& )
1373 // the container just has an unknown type, use current file format
1375 catch ( const uno::Exception
& )
1377 SAL_WARN( "embeddedobj.common", "Can not retrieve own storage media type!" );
1380 PostEvent_Impl( u
"OnSaveAs"_ustr
);
1382 bool bTryOptimization
= false;
1383 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1385 // StoreVisualReplacement and VisualReplacement args have no sense here
1386 if ( prop
.Name
== "CanTryOptimization" )
1387 prop
.Value
>>= bTryOptimization
;
1390 bool bSwitchBackToLoaded
= false;
1392 // Storing to different format can be done only in running state.
1393 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1395 // TODO/LATER: copying is not legal for documents with relative links.
1396 if ( nTargetStorageFormat
== nOriginalStorageFormat
)
1398 bool bOptimizationWorks
= false;
1399 if ( bTryOptimization
)
1403 // try to use optimized copying
1404 uno::Reference
< embed::XOptimizedStorage
> xSource( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1405 uno::Reference
< embed::XOptimizedStorage
> xTarget( xStorage
, uno::UNO_QUERY_THROW
);
1406 xSource
->copyElementDirectlyTo( m_aEntryName
, xTarget
, sEntName
);
1407 bOptimizationWorks
= true;
1409 catch( const uno::Exception
& )
1414 if ( !bOptimizationWorks
)
1415 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1419 changeState( embed::EmbedStates::RUNNING
);
1420 bSwitchBackToLoaded
= true;
1424 uno::Reference
< embed::XStorage
> xSubStorage
=
1425 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READWRITE
);
1427 if ( !xSubStorage
.is() )
1428 throw uno::RuntimeException(); //TODO
1430 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1433 // TODO/LATER: support hierarchical name for embedded objects in embedded objects
1434 StoreDocToStorage_Impl(
1435 xSubStorage
, lArguments
, lObjArgs
, nTargetStorageFormat
, sEntName
, false );
1438 if ( bSwitchBackToLoaded
)
1439 changeState( embed::EmbedStates::LOADED
);
1442 m_bWaitSaveCompleted
= true;
1443 m_xNewObjectStorage
= std::move(xSubStorage
);
1444 m_xNewParentStorage
= xStorage
;
1445 m_aNewEntryName
= sEntName
;
1446 m_aNewDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1448 // TODO: register listeners for storages above, in case they are disposed
1449 // an exception will be thrown on saveCompleted( true )
1451 // TODO: should the listener notification be done here or in saveCompleted?
1455 void SAL_CALL
OCommonEmbeddedObject::saveCompleted( sal_Bool bUseNew
)
1457 ::osl::MutexGuard
aGuard( m_aMutex
);
1459 throw lang::DisposedException(); // TODO
1461 if ( m_nObjectState
== -1 )
1463 // the object is still not loaded
1464 throw embed::WrongStateException( u
"Can't store object without persistence!"_ustr
,
1465 static_cast< ::cppu::OWeakObject
* >(this) );
1468 // for now support of this interface is required to allow breaking of links and converting them to normal embedded
1469 // objects, so the persist name must be handled correctly ( althowgh no real persist entry is used )
1470 // OSL_ENSURE( !m_bIsLinkURL, "This method implementation must not be used for links!" );
1474 m_aEntryName
= m_aNewEntryName
;
1475 m_aNewEntryName
.clear();
1479 // it is allowed to call saveCompleted( false ) for nonstored objects
1480 if ( !m_bWaitSaveCompleted
&& !bUseNew
)
1483 SAL_WARN_IF( !m_bWaitSaveCompleted
, "embeddedobj.common", "Unexpected saveCompleted() call!" );
1484 if ( !m_bWaitSaveCompleted
)
1485 throw io::IOException(); // TODO: illegal call
1487 OSL_ENSURE( m_xNewObjectStorage
.is() && m_xNewParentStorage
.is() , "Internal object information is broken!" );
1488 if ( !m_xNewObjectStorage
.is() || !m_xNewParentStorage
.is() )
1489 throw uno::RuntimeException(); // TODO: broken internal information
1493 SwitchOwnPersistence( m_xNewParentStorage
, m_xNewObjectStorage
, m_aNewEntryName
);
1494 m_aDocMediaDescriptor
= m_aNewDocMediaDescriptor
;
1496 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
1498 xModif
->setModified( false );
1500 PostEvent_Impl( u
"OnSaveAsDone"_ustr
);
1505 m_xNewObjectStorage
->dispose();
1507 catch ( const uno::Exception
& )
1512 m_xNewObjectStorage
.clear();
1513 m_xNewParentStorage
.clear();
1514 m_aNewEntryName
.clear();
1515 m_aNewDocMediaDescriptor
.realloc( 0 );
1516 m_bWaitSaveCompleted
= false;
1520 // TODO: notify listeners
1522 if ( m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
)
1524 // TODO: update visual representation
1530 sal_Bool SAL_CALL
OCommonEmbeddedObject::hasEntry()
1532 ::osl::MutexGuard
aGuard( m_aMutex
);
1534 throw lang::DisposedException(); // TODO
1536 if ( m_bWaitSaveCompleted
)
1537 throw embed::WrongStateException(
1538 u
"The object waits for saveCompleted() call!"_ustr
,
1539 static_cast< ::cppu::OWeakObject
* >(this) );
1541 if ( m_xObjectStorage
.is() )
1548 OUString SAL_CALL
OCommonEmbeddedObject::getEntryName()
1550 ::osl::MutexGuard
aGuard( m_aMutex
);
1552 throw lang::DisposedException(); // TODO
1554 if ( m_nObjectState
== -1 )
1556 // the object is still not loaded
1557 throw embed::WrongStateException( u
"The object persistence is not initialized!"_ustr
,
1558 static_cast< ::cppu::OWeakObject
* >(this) );
1561 if ( m_bWaitSaveCompleted
)
1562 throw embed::WrongStateException(
1563 u
"The object waits for saveCompleted() call!"_ustr
,
1564 static_cast< ::cppu::OWeakObject
* >(this) );
1566 return m_aEntryName
;
1570 void SAL_CALL
OCommonEmbeddedObject::storeOwn()
1572 // during switching from Activated to Running and from Running to Loaded states the object will
1573 // ask container to store the object, the container has to make decision
1576 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1578 throw lang::DisposedException(); // TODO
1580 if ( m_nObjectState
== -1 )
1582 // the object is still not loaded
1583 throw embed::WrongStateException( u
"Can't store object without persistence!"_ustr
,
1584 static_cast< ::cppu::OWeakObject
* >(this) );
1587 if ( m_bWaitSaveCompleted
)
1588 throw embed::WrongStateException(
1589 u
"The object waits for saveCompleted() call!"_ustr
,
1590 static_cast< ::cppu::OWeakObject
* >(this) );
1593 throw io::IOException(); // TODO: access denied
1595 // nothing to do, if the object is in loaded state
1596 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1599 PostEvent_Impl( u
"OnSave"_ustr
);
1601 SAL_WARN_IF( !m_xDocHolder
->GetComponent().is(), "embeddedobj.common", "If an object is activated or in running state it must have a document!" );
1602 if ( !m_xDocHolder
->GetComponent().is() )
1603 throw uno::RuntimeException();
1607 // TODO: just store the document to its location
1608 uno::Reference
< frame::XStorable
> xStorable( m_xDocHolder
->GetComponent(), uno::UNO_QUERY_THROW
);
1610 // free the main mutex for the storing time
1619 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStorage
.is(), "The object has no valid persistence!" );
1621 if ( !m_xObjectStorage
.is() )
1622 throw io::IOException(); //TODO: access denied
1624 sal_Int32 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1626 nStorageFormat
= ::comphelper::OStorageHelper::GetXStorageFormat( m_xParentStorage
);
1628 catch ( const beans::IllegalTypeException
& )
1630 // the container just has an unknown type, use current file format
1632 catch ( const uno::Exception
& )
1634 SAL_WARN( "embeddedobj.common", "Can not retrieve storage media type!" );
1636 if (nStorageFormat
== SOFFICE_FILEFORMAT_60
)
1638 SAL_INFO("embeddedobj.common", "fdo#78159: Storing OOoXML as ODF");
1639 nStorageFormat
= SOFFICE_FILEFORMAT_CURRENT
;
1640 // setting MediaType is done later anyway, no need to do it here
1644 uno::Sequence
<beans::PropertyValue
> aEmpty
;
1645 uno::Sequence
<beans::PropertyValue
> aMediaArgs
{ comphelper::makePropertyValue(
1646 u
"DocumentBaseURL"_ustr
, GetBaseURL_Impl()) };
1647 StoreDocToStorage_Impl( m_xObjectStorage
, aMediaArgs
, aEmpty
, nStorageFormat
, m_aEntryName
, true );
1651 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY
);
1653 xModif
->setModified( false );
1655 PostEvent_Impl( u
"OnSaveDone"_ustr
);
1659 sal_Bool SAL_CALL
OCommonEmbeddedObject::isReadonly()
1661 ::osl::MutexGuard
aGuard( m_aMutex
);
1663 throw lang::DisposedException(); // TODO
1665 if ( m_nObjectState
== -1 )
1667 // the object is still not loaded
1668 throw embed::WrongStateException( u
"The object persistence is not initialized!"_ustr
,
1669 static_cast< ::cppu::OWeakObject
* >(this) );
1672 if ( m_bWaitSaveCompleted
)
1673 throw embed::WrongStateException(
1674 u
"The object waits for saveCompleted() call!"_ustr
,
1675 static_cast< ::cppu::OWeakObject
* >(this) );
1681 void SAL_CALL
OCommonEmbeddedObject::reload(
1682 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1683 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1685 // TODO: use lObjArgs
1686 // for now this method is used only to switch readonly state
1688 ::osl::MutexGuard
aGuard( m_aMutex
);
1690 throw lang::DisposedException(); // TODO
1692 if ( m_nObjectState
== -1 )
1694 // the object is still not loaded
1695 throw embed::WrongStateException( u
"The object persistence is not initialized!"_ustr
,
1696 static_cast< ::cppu::OWeakObject
* >(this) );
1699 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
1701 // the object is still not loaded
1702 throw embed::WrongStateException(
1703 u
"The object must be in loaded state to be reloaded!"_ustr
,
1704 static_cast< ::cppu::OWeakObject
* >(this) );
1707 if ( m_bWaitSaveCompleted
)
1708 throw embed::WrongStateException(
1709 u
"The object waits for saveCompleted() call!"_ustr
,
1710 static_cast< ::cppu::OWeakObject
* >(this) );
1714 // reload of the link
1715 OUString aOldLinkFilter
= m_aLinkFilterName
;
1717 OUString aNewLinkFilter
;
1718 for ( beans::PropertyValue
const & prop
: lArguments
)
1720 if ( prop
.Name
== "URL" )
1723 prop
.Value
>>= m_aLinkURL
;
1724 m_aLinkFilterName
.clear();
1726 else if ( prop
.Name
== "FilterName" )
1728 prop
.Value
>>= aNewLinkFilter
;
1729 m_aLinkFilterName
.clear();
1733 ::comphelper::MimeConfigurationHelper
aHelper( m_xContext
);
1734 if ( m_aLinkFilterName
.isEmpty() )
1736 if ( !aNewLinkFilter
.isEmpty() )
1737 m_aLinkFilterName
= aNewLinkFilter
;
1740 uno::Sequence
< beans::PropertyValue
> aArgs
{ comphelper::makePropertyValue(
1741 u
"URL"_ustr
, m_aLinkURL
) };
1742 m_aLinkFilterName
= aHelper
.UpdateMediaDescriptorWithFilterName( aArgs
, false );
1746 if ( aOldLinkFilter
!= m_aLinkFilterName
)
1748 uno::Sequence
< beans::NamedValue
> aObject
= aHelper
.GetObjectPropsByFilter( m_aLinkFilterName
);
1750 // TODO/LATER: probably the document holder could be cleaned explicitly as in the destructor
1751 m_xDocHolder
.clear();
1753 LinkInit_Impl( aObject
, lArguments
, lObjArgs
);
1757 m_aDocMediaDescriptor
= GetValuableArgs_Impl( lArguments
, true );
1759 // TODO: use lObjArgs for StoreVisualReplacement
1760 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1761 if ( prop
.Name
== "OutplaceDispatchInterceptor" )
1763 uno::Reference
< frame::XDispatchProviderInterceptor
> xDispatchInterceptor
;
1764 if ( prop
.Value
>>= xDispatchInterceptor
)
1765 m_xDocHolder
->SetOutplaceDispatchInterceptor( xDispatchInterceptor
);
1771 // when document allows reloading through API the object can be reloaded not only in loaded state
1773 bool bOldReadOnlyValue
= m_bReadOnly
;
1775 m_bReadOnly
= false;
1776 for ( beans::PropertyValue
const & prop
: lArguments
)
1777 if ( prop
.Name
== "ReadOnly" )
1778 prop
.Value
>>= m_bReadOnly
;
1780 if ( bOldReadOnlyValue
== m_bReadOnly
|| m_bIsLinkURL
)
1783 // close own storage
1785 if ( m_xObjectStorage
.is() )
1786 m_xObjectStorage
->dispose();
1788 catch ( const uno::Exception
& )
1792 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1793 m_xObjectStorage
= m_xParentStorage
->openStorageElement( m_aEntryName
, nStorageMode
);
1796 sal_Bool SAL_CALL
OCommonEmbeddedObject::isStored()
1798 if (!m_xObjectStorage
.is())
1801 return m_xObjectStorage
->getElementNames().hasElements();
1805 void SAL_CALL
OCommonEmbeddedObject::breakLink( const uno::Reference
< embed::XStorage
>& xStorage
,
1806 const OUString
& sEntName
)
1808 ::osl::ResettableMutexGuard
aGuard( m_aMutex
);
1810 throw lang::DisposedException(); // TODO
1812 if (!m_bIsLinkURL
|| m_nObjectState
== -1)
1814 // it must be a linked initialized object
1815 throw embed::WrongStateException(
1816 u
"The object is not a valid linked object!"_ustr
,
1817 static_cast< ::cppu::OWeakObject
* >(this) );
1819 // the current implementation of OOo links does not implement this method since it does not implement
1820 // all the set of interfaces required for OOo embedded object ( XEmbedPersist is not supported ).
1822 if ( !xStorage
.is() )
1823 throw lang::IllegalArgumentException( u
"No parent storage is provided!"_ustr
,
1824 static_cast< ::cppu::OWeakObject
* >(this),
1827 if ( sEntName
.isEmpty() )
1828 throw lang::IllegalArgumentException( u
"Empty element name is provided!"_ustr
,
1829 static_cast< ::cppu::OWeakObject
* >(this),
1832 if ( m_bWaitSaveCompleted
)
1833 throw embed::WrongStateException(
1834 u
"The object waits for saveCompleted() call!"_ustr
,
1835 static_cast< ::cppu::OWeakObject
* >(this) );
1837 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
1839 m_bReadOnly
= false;
1841 if ( m_xParentStorage
!= xStorage
|| m_aEntryName
!= sEntName
)
1842 SwitchOwnPersistence( xStorage
, sEntName
);
1844 // for linked object it means that it becomes embedded object
1845 // the document must switch it's persistence also
1847 // TODO/LATER: handle the case when temp doc can not be created
1848 // the document is a new embedded object so it must be marked as modified
1849 uno::Reference
< util::XCloseable
> xDocument
= CreateTempDocFromLink_Impl();
1852 if(m_xDocHolder
.is() && m_xDocHolder
->GetComponent().is())
1854 // tdf#141528 m_xDocHolder->GetComponent() may be not set, so add it
1855 // to the try path to not get thrown out of the local context to the next
1856 // higher try...catch on the stack. To make breakLink work it is
1857 // *necessary* to execute the code below that resets the linked state,
1858 // esp. the *.clear stuff and resetting m_bIsLink.
1859 uno::Reference
< util::XModifiable
> xModif( m_xDocHolder
->GetComponent(), uno::UNO_QUERY_THROW
);
1861 // all other locations in this file check for xModif.is(), so do it here, too
1863 xModif
->setModified( true );
1866 catch( const uno::Exception
& )
1869 m_xDocHolder
->SetComponent( xDocument
, m_bReadOnly
);
1870 SAL_WARN_IF( !m_xDocHolder
->GetComponent().is(), "embeddedobj.common", "If document can't be created, an exception must be thrown!" );
1872 if ( m_nObjectState
== embed::EmbedStates::LOADED
)
1874 // the state is changed and can not be switched to loaded state back without saving
1875 m_nObjectState
= embed::EmbedStates::RUNNING
;
1876 StateChangeNotification_Impl( false, embed::EmbedStates::LOADED
, m_nObjectState
, aGuard
);
1878 else if ( m_nObjectState
== embed::EmbedStates::ACTIVE
)
1879 m_xDocHolder
->Show();
1881 // tdf#141529 reset all stuff involved in linked state, including
1882 // the OLE content copied to the temp file
1883 m_bIsLinkURL
= false;
1884 m_aLinkTempFile
.clear();
1885 m_aLinkFilterName
.clear();
1890 sal_Bool SAL_CALL
OCommonEmbeddedObject::isLink()
1892 ::osl::MutexGuard
aGuard( m_aMutex
);
1894 throw lang::DisposedException(); // TODO
1896 return m_bIsLinkURL
;
1900 OUString SAL_CALL
OCommonEmbeddedObject::getLinkURL()
1902 ::osl::MutexGuard
aGuard( m_aMutex
);
1904 throw lang::DisposedException(); // TODO
1906 if ( !m_bIsLinkURL
)
1907 throw embed::WrongStateException(
1908 u
"The object is not a link object!"_ustr
,
1909 static_cast< ::cppu::OWeakObject
* >(this) );
1914 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */