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 <com/sun/star/embed/ElementModes.hpp>
21 #include <com/sun/star/embed/EntryInitModes.hpp>
22 #include <com/sun/star/embed/XEmbedObjectFactory.hpp>
23 #include <com/sun/star/embed/OOoEmbeddedObjectFactory.hpp>
24 #include <com/sun/star/embed/OLEEmbeddedObjectFactory.hpp>
25 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/container/XNameAccess.hpp>
28 #include <com/sun/star/lang/XComponent.hpp>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <cppuhelper/weak.hxx>
32 #include <comphelper/documentconstants.hxx>
33 #include <officecfg/Office/Common.hxx>
35 #include <xcreator.hxx>
36 #include <dummyobject.hxx>
39 using namespace ::com::sun::star
;
41 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceInitNew(
42 const uno::Sequence
< sal_Int8
>& aClassID
,
43 const OUString
& aClassName
,
44 const uno::Reference
< embed::XStorage
>& xStorage
,
45 const OUString
& sEntName
,
46 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
49 throw lang::IllegalArgumentException( "No parent storage is provided!",
50 static_cast< ::cppu::OWeakObject
* >(this),
53 if ( sEntName
.isEmpty() )
54 throw lang::IllegalArgumentException( "Empty element name is provided!",
55 static_cast< ::cppu::OWeakObject
* >(this),
58 OUString aEmbedFactory
= m_aConfigHelper
.GetFactoryNameByClassID( aClassID
);
59 if ( aEmbedFactory
.isEmpty() )
61 // use system fallback
62 // TODO: in future users factories can be tested
63 aEmbedFactory
= "com.sun.star.embed.OLEEmbeddedObjectFactory";
66 uno::Reference
< uno::XInterface
> xFact( m_xContext
->getServiceManager()->createInstanceWithContext(aEmbedFactory
, m_xContext
) );
67 uno::Reference
< embed::XEmbedObjectCreator
> xEmbCreator( xFact
, uno::UNO_QUERY
);
68 if ( xEmbCreator
.is() )
69 return xEmbCreator
->createInstanceInitNew( aClassID
, aClassName
, xStorage
, sEntName
, lObjArgs
);
71 uno::Reference
< embed::XEmbedObjectFactory
> xEmbFact( xFact
, uno::UNO_QUERY_THROW
);
72 return xEmbFact
->createInstanceUserInit( aClassID
, aClassName
, xStorage
, sEntName
, embed::EntryInitModes::TRUNCATE_INIT
, uno::Sequence
< beans::PropertyValue
>(), lObjArgs
);
76 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceInitFromEntry(
77 const uno::Reference
< embed::XStorage
>& xStorage
,
78 const OUString
& sEntName
,
79 const uno::Sequence
< beans::PropertyValue
>& aMedDescr
,
80 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
83 throw lang::IllegalArgumentException( "No parent storage is provided!",
84 static_cast< ::cppu::OWeakObject
* >(this),
87 if ( sEntName
.isEmpty() )
88 throw lang::IllegalArgumentException( "Empty element name is provided!",
89 static_cast< ::cppu::OWeakObject
* >(this),
92 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
94 // detect entry existence
95 if ( !xNameAccess
->hasByName( sEntName
) )
96 throw container::NoSuchElementException();
99 OUString aEmbedFactory
;
100 if ( xStorage
->isStorageElement( sEntName
) )
102 // the object must be based on storage
103 uno::Reference
< embed::XStorage
> xSubStorage
=
104 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READ
);
106 uno::Reference
< beans::XPropertySet
> xPropSet( xSubStorage
, uno::UNO_QUERY_THROW
);
109 uno::Any aAny
= xPropSet
->getPropertyValue("MediaType");
112 catch ( const uno::Exception
& )
117 if ( xSubStorage
.is() )
118 xSubStorage
->dispose();
120 catch ( const uno::Exception
& )
126 // the object must be based on stream
127 // it means for now that this is an OLE object
129 // the object will be created as embedded object
130 // after it is loaded it can detect that it is a link
132 uno::Reference
< io::XStream
> xSubStream
=
133 xStorage
->openStreamElement( sEntName
, embed::ElementModes::READ
);
135 uno::Reference
< beans::XPropertySet
> xPropSet( xSubStream
, uno::UNO_QUERY_THROW
);
138 uno::Any aAny
= xPropSet
->getPropertyValue("MediaType");
140 if ( aMediaType
== "application/vnd.sun.star.oleobject" )
141 aEmbedFactory
= "com.sun.star.embed.OLEEmbeddedObjectFactory";
143 catch ( const uno::Exception
& )
148 uno::Reference
< lang::XComponent
> xComp( xSubStream
, uno::UNO_QUERY
);
152 catch ( const uno::Exception
& )
157 OSL_ENSURE( !aMediaType
.isEmpty(), "No media type is specified for the object!" );
158 if ( !aMediaType
.isEmpty() && aEmbedFactory
.isEmpty() )
160 aEmbedFactory
= m_aConfigHelper
.GetFactoryNameByMediaType( aMediaType
);
162 // If no factory is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
163 if (aEmbedFactory
.isEmpty() && aMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
)
164 aEmbedFactory
= m_aConfigHelper
.GetFactoryNameByMediaType(MIMETYPE_VND_SUN_XML_BASE_ASCII
);
167 if ( !aEmbedFactory
.isEmpty() )
169 uno::Reference
< uno::XInterface
> xFact
= m_xContext
->getServiceManager()->createInstanceWithContext(aEmbedFactory
, m_xContext
);
171 uno::Reference
< embed::XEmbedObjectCreator
> xEmbCreator( xFact
, uno::UNO_QUERY
);
172 if ( xEmbCreator
.is() )
173 return xEmbCreator
->createInstanceInitFromEntry( xStorage
, sEntName
, aMedDescr
, lObjArgs
);
175 uno::Reference
< embed::XEmbedObjectFactory
> xEmbFact( xFact
, uno::UNO_QUERY
);
177 return xEmbFact
->createInstanceUserInit( uno::Sequence
< sal_Int8
>(), OUString(), xStorage
, sEntName
, embed::EntryInitModes::DEFAULT_INIT
, aMedDescr
, lObjArgs
);
180 // the default object should be created, it will allow to store the contents on the next saving
181 uno::Reference
< uno::XInterface
> xResult( static_cast< cppu::OWeakObject
* >( new ODummyEmbeddedObject() ) );
182 uno::Reference
< embed::XEmbedPersist
> xPersist( xResult
, uno::UNO_QUERY_THROW
);
183 xPersist
->setPersistentEntry( xStorage
, sEntName
, embed::EntryInitModes::DEFAULT_INIT
, aMedDescr
, lObjArgs
);
188 * Decides if rFilter should be used to load data into a doc model or real OLE embedding should
189 * happen. Empty return value means the later.
191 static OUString
HandleFilter(const uno::Reference
<uno::XComponentContext
>& xComponentContext
,
192 const OUString
& rFilter
)
194 OUString aRet
= rFilter
;
196 if (!officecfg::Office::Common::Filter::Microsoft::Import::WinWordToWriter::get(
199 if (rFilter
== "MS Word 97" || rFilter
== "MS Word 2007 XML")
205 if (!officecfg::Office::Common::Filter::Microsoft::Import::ExcelToCalc::get(xComponentContext
))
207 if (rFilter
== "MS Excel 97" || rFilter
== "Calc MS Excel 2007 XML")
212 if (!officecfg::Office::Common::Filter::Microsoft::Import::PowerPointToImpress::get(
215 if (rFilter
== "MS PowerPoint 97" || rFilter
== "Impress MS PowerPoint 2007 XML")
220 if (!officecfg::Office::Common::Filter::Microsoft::Import::VisioToDraw::get(xComponentContext
))
222 if (rFilter
== "Visio Document")
227 if (!officecfg::Office::Common::Filter::Adobe::Import::PDFToDraw::get(xComponentContext
))
229 if (rFilter
== "draw_pdf_import")
238 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceInitFromMediaDescriptor(
239 const uno::Reference
< embed::XStorage
>& xStorage
,
240 const OUString
& sEntName
,
241 const uno::Sequence
< beans::PropertyValue
>& aMediaDescr
,
242 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
244 // TODO: use lObjArgs
246 if ( !xStorage
.is() )
247 throw lang::IllegalArgumentException( "No parent storage is provided!",
248 static_cast< ::cppu::OWeakObject
* >(this),
251 if ( sEntName
.isEmpty() )
252 throw lang::IllegalArgumentException( "Empty element name is provided!",
253 static_cast< ::cppu::OWeakObject
* >(this),
256 uno::Reference
< uno::XInterface
> xResult
;
257 uno::Sequence
< beans::PropertyValue
> aTempMedDescr( aMediaDescr
);
259 // check if there is FilterName
260 OUString aFilterName
= m_aConfigHelper
.UpdateMediaDescriptorWithFilterName( aTempMedDescr
, false );
262 aFilterName
= HandleFilter(m_xContext
, aFilterName
);
264 if ( !aFilterName
.isEmpty() )
266 // the object can be loaded by one of the office application
267 uno::Reference
< embed::XEmbeddedObjectCreator
> xOOoEmbCreator
=
268 embed::OOoEmbeddedObjectFactory::create( m_xContext
);
270 xResult
= xOOoEmbCreator
->createInstanceInitFromMediaDescriptor( xStorage
,
277 // must be an OLE object
279 // TODO: in future, when more object types are possible this place seems
280 // to be a weak one, probably configuration must provide a type detection service
281 // for every factory, so any file could go through services until it is recognized
282 // or there is no more services
283 // Or for example the typename can be used to detect object type if typedetection
284 // was also extended.
286 uno::Reference
< embed::XEmbeddedObjectCreator
> xOleEmbCreator
=
287 embed::OLEEmbeddedObjectFactory::create( m_xContext
);
289 xResult
= xOleEmbCreator
->createInstanceInitFromMediaDescriptor( xStorage
, sEntName
, aTempMedDescr
, lObjArgs
);
296 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceUserInit(
297 const uno::Sequence
< sal_Int8
>& aClassID
,
298 const OUString
& sClassName
,
299 const uno::Reference
< embed::XStorage
>& xStorage
,
300 const OUString
& sEntName
,
301 sal_Int32 nEntryConnectionMode
,
302 const uno::Sequence
< beans::PropertyValue
>& aArgs
,
303 const uno::Sequence
< beans::PropertyValue
>& aObjectArgs
)
305 if ( !xStorage
.is() )
306 throw lang::IllegalArgumentException( "No parent storage is provided!",
307 static_cast< ::cppu::OWeakObject
* >(this),
310 if ( sEntName
.isEmpty() )
311 throw lang::IllegalArgumentException( "Empty element name is provided!",
312 static_cast< ::cppu::OWeakObject
* >(this),
315 OUString aEmbedFactory
= m_aConfigHelper
.GetFactoryNameByClassID( aClassID
);
316 uno::Reference
< embed::XEmbedObjectFactory
> xEmbFactory(
317 m_xContext
->getServiceManager()->createInstanceWithContext(aEmbedFactory
, m_xContext
),
318 uno::UNO_QUERY_THROW
);
320 return xEmbFactory
->createInstanceUserInit( aClassID
,
324 nEntryConnectionMode
,
330 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceLink(
331 const uno::Reference
< embed::XStorage
>& xStorage
,
332 const OUString
& sEntName
,
333 const uno::Sequence
< beans::PropertyValue
>& aMediaDescr
,
334 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
336 uno::Reference
< uno::XInterface
> xResult
;
338 uno::Sequence
< beans::PropertyValue
> aTempMedDescr( aMediaDescr
);
340 // check if there is URL, URL must exist
342 for ( beans::PropertyValue
const & prop
: std::as_const(aTempMedDescr
) )
343 if ( prop
.Name
== "URL" )
346 if ( aURL
.isEmpty() )
347 throw lang::IllegalArgumentException( "No URL for the link is provided!",
348 static_cast< ::cppu::OWeakObject
* >(this),
351 OUString aFilterName
= m_aConfigHelper
.UpdateMediaDescriptorWithFilterName( aTempMedDescr
, false );
353 if ( !aFilterName
.isEmpty() )
355 // the object can be loaded by one of the office application
356 uno::Reference
< embed::XEmbeddedObjectCreator
> xOOoLinkCreator
=
357 embed::OOoEmbeddedObjectFactory::create( m_xContext
);
359 xResult
= xOOoLinkCreator
->createInstanceLink( xStorage
,
366 // must be an OLE link
368 // TODO: in future, when more object types are possible this place seems
369 // to be a weak one, probably configuration must provide a type detection service
370 // for every factory, so any file could go through services until it is recognized
371 // or there is no more services
372 // Or for example the typename can be used to detect object type if typedetection
373 // was also extended.
375 if ( !xStorage
.is() )
376 throw lang::IllegalArgumentException( "No parent storage is provided!",
377 static_cast< ::cppu::OWeakObject
* >(this),
380 if ( sEntName
.isEmpty() )
381 throw lang::IllegalArgumentException( "Empty element name is provided!",
382 static_cast< ::cppu::OWeakObject
* >(this),
385 uno::Reference
< embed::XEmbeddedObjectCreator
> xLinkCreator
=
386 embed::OLEEmbeddedObjectFactory::create( m_xContext
);
388 xResult
= xLinkCreator
->createInstanceLink( xStorage
, sEntName
, aTempMedDescr
, lObjArgs
);
394 OUString SAL_CALL
UNOEmbeddedObjectCreator::getImplementationName()
396 return "com.sun.star.comp.embed.EmbeddedObjectCreator";
399 sal_Bool SAL_CALL
UNOEmbeddedObjectCreator::supportsService( const OUString
& ServiceName
)
401 return cppu::supportsService(this, ServiceName
);
404 uno::Sequence
< OUString
> SAL_CALL
UNOEmbeddedObjectCreator::getSupportedServiceNames()
406 return { "com.sun.star.embed.EmbeddedObjectCreator", "com.sun.star.comp.embed.EmbeddedObjectCreator" };
409 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
410 embeddedobj_UNOEmbeddedObjectCreator_get_implementation(
411 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
413 return cppu::acquire(new UNOEmbeddedObjectCreator(context
));
416 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */