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/embed/XLinkFactory.hpp>
26 #include <com/sun/star/document/XTypeDetection.hpp>
27 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/container/XNameAccess.hpp>
30 #include <com/sun/star/lang/XComponent.hpp>
32 #include <comphelper/processfactory.hxx>
33 #include <cppuhelper/supportsservice.hxx>
34 #include <comphelper/documentconstants.hxx>
36 #include <xcreator.hxx>
37 #include <dummyobject.hxx>
40 using namespace ::com::sun::star
;
44 uno::Sequence
< OUString
> SAL_CALL
UNOEmbeddedObjectCreator::impl_staticGetSupportedServiceNames()
46 uno::Sequence
< OUString
> aRet(2);
47 aRet
[0] = "com.sun.star.embed.EmbeddedObjectCreator";
48 aRet
[1] = "com.sun.star.comp.embed.EmbeddedObjectCreator";
53 OUString SAL_CALL
UNOEmbeddedObjectCreator::impl_staticGetImplementationName()
55 return OUString("com.sun.star.comp.embed.EmbeddedObjectCreator");
59 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::impl_staticCreateSelfInstance(
60 const uno::Reference
< lang::XMultiServiceFactory
>& xServiceManager
)
62 return uno::Reference
< uno::XInterface
>( *new UNOEmbeddedObjectCreator( comphelper::getComponentContext(xServiceManager
) ) );
66 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceInitNew(
67 const uno::Sequence
< sal_Int8
>& aClassID
,
68 const OUString
& aClassName
,
69 const uno::Reference
< embed::XStorage
>& xStorage
,
70 const OUString
& sEntName
,
71 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
72 throw ( lang::IllegalArgumentException
,
75 uno::RuntimeException
, std::exception
)
77 uno::Reference
< uno::XInterface
> xResult
;
80 throw lang::IllegalArgumentException( "No parent storage is provided!",
81 static_cast< ::cppu::OWeakObject
* >(this),
84 if ( sEntName
.isEmpty() )
85 throw lang::IllegalArgumentException( "Empty element name is provided!",
86 static_cast< ::cppu::OWeakObject
* >(this),
89 OUString aEmbedFactory
= m_aConfigHelper
.GetFactoryNameByClassID( aClassID
);
90 if ( aEmbedFactory
.isEmpty() )
92 // use system fallback
93 // TODO: in future users factories can be tested
94 aEmbedFactory
= "com.sun.star.embed.OLEEmbeddedObjectFactory";
97 uno::Reference
< uno::XInterface
> xFact( m_xContext
->getServiceManager()->createInstanceWithContext(aEmbedFactory
, m_xContext
) );
98 uno::Reference
< embed::XEmbedObjectCreator
> xEmbCreator( xFact
, uno::UNO_QUERY
);
99 if ( xEmbCreator
.is() )
100 return xEmbCreator
->createInstanceInitNew( aClassID
, aClassName
, xStorage
, sEntName
, lObjArgs
);
102 uno::Reference
< embed::XEmbedObjectFactory
> xEmbFact( xFact
, uno::UNO_QUERY
);
103 if ( !xEmbFact
.is() )
104 throw uno::RuntimeException();
105 return xEmbFact
->createInstanceUserInit( aClassID
, aClassName
, xStorage
, sEntName
, embed::EntryInitModes::TRUNCATE_INIT
, uno::Sequence
< beans::PropertyValue
>(), lObjArgs
);
109 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceInitFromEntry(
110 const uno::Reference
< embed::XStorage
>& xStorage
,
111 const OUString
& sEntName
,
112 const uno::Sequence
< beans::PropertyValue
>& aMedDescr
,
113 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
114 throw ( lang::IllegalArgumentException
,
115 container::NoSuchElementException
,
118 uno::RuntimeException
, std::exception
)
120 if ( !xStorage
.is() )
121 throw lang::IllegalArgumentException( "No parent storage is provided!",
122 static_cast< ::cppu::OWeakObject
* >(this),
125 if ( sEntName
.isEmpty() )
126 throw lang::IllegalArgumentException( "Empty element name is provided!",
127 static_cast< ::cppu::OWeakObject
* >(this),
130 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY
);
131 if ( !xNameAccess
.is() )
132 throw uno::RuntimeException(); //TODO
134 // detect entry existence
135 if ( !xNameAccess
->hasByName( sEntName
) )
136 throw container::NoSuchElementException();
139 OUString aEmbedFactory
;
140 if ( xStorage
->isStorageElement( sEntName
) )
142 // the object must be based on storage
143 uno::Reference
< embed::XStorage
> xSubStorage
=
144 xStorage
->openStorageElement( sEntName
, embed::ElementModes::READ
);
146 uno::Reference
< beans::XPropertySet
> xPropSet( xSubStorage
, uno::UNO_QUERY
);
147 if ( !xPropSet
.is() )
148 throw uno::RuntimeException();
151 uno::Any aAny
= xPropSet
->getPropertyValue("MediaType");
154 catch ( const uno::Exception
& )
159 uno::Reference
< lang::XComponent
> xComp( xSubStorage
, uno::UNO_QUERY
);
163 catch ( const uno::Exception
& )
169 // the object must be based on stream
170 // it means for now that this is an OLE object
172 // the object will be created as embedded object
173 // after it is loaded it can detect that it is a link
175 uno::Reference
< io::XStream
> xSubStream
=
176 xStorage
->openStreamElement( sEntName
, embed::ElementModes::READ
);
178 uno::Reference
< beans::XPropertySet
> xPropSet( xSubStream
, uno::UNO_QUERY
);
179 if ( !xPropSet
.is() )
180 throw uno::RuntimeException();
183 uno::Any aAny
= xPropSet
->getPropertyValue("MediaType");
185 if ( aMediaType
== "application/vnd.sun.star.oleobject" )
186 aEmbedFactory
= "com.sun.star.embed.OLEEmbeddedObjectFactory";
188 catch ( const uno::Exception
& )
193 uno::Reference
< lang::XComponent
> xComp( xSubStream
, uno::UNO_QUERY
);
197 catch ( const uno::Exception
& )
202 OSL_ENSURE( !aMediaType
.isEmpty(), "No media type is specified for the object!" );
203 if ( !aMediaType
.isEmpty() && aEmbedFactory
.isEmpty() )
205 aEmbedFactory
= m_aConfigHelper
.GetFactoryNameByMediaType( aMediaType
);
207 // If no factory is found, fall back to the FileFormatVersion=6200 filter, Base only has that.
208 if (aEmbedFactory
.isEmpty() && aMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
)
209 aEmbedFactory
= m_aConfigHelper
.GetFactoryNameByMediaType(MIMETYPE_VND_SUN_XML_BASE_ASCII
);
212 if ( !aEmbedFactory
.isEmpty() )
214 uno::Reference
< uno::XInterface
> xFact
= m_xContext
->getServiceManager()->createInstanceWithContext(aEmbedFactory
, m_xContext
);
216 uno::Reference
< embed::XEmbedObjectCreator
> xEmbCreator( xFact
, uno::UNO_QUERY
);
217 if ( xEmbCreator
.is() )
218 return xEmbCreator
->createInstanceInitFromEntry( xStorage
, sEntName
, aMedDescr
, lObjArgs
);
220 uno::Reference
< embed::XEmbedObjectFactory
> xEmbFact( xFact
, uno::UNO_QUERY
);
222 return xEmbFact
->createInstanceUserInit( uno::Sequence
< sal_Int8
>(), OUString(), xStorage
, sEntName
, embed::EntryInitModes::DEFAULT_INIT
, aMedDescr
, lObjArgs
);
225 // the default object should be created, it will allow to store the contents on the next saving
226 uno::Reference
< uno::XInterface
> xResult( static_cast< cppu::OWeakObject
* >( new ODummyEmbeddedObject() ) );
227 uno::Reference
< embed::XEmbedPersist
> xPersist( xResult
, uno::UNO_QUERY_THROW
);
228 xPersist
->setPersistentEntry( xStorage
, sEntName
, embed::EntryInitModes::DEFAULT_INIT
, aMedDescr
, lObjArgs
);
233 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceInitFromMediaDescriptor(
234 const uno::Reference
< embed::XStorage
>& xStorage
,
235 const OUString
& sEntName
,
236 const uno::Sequence
< beans::PropertyValue
>& aMediaDescr
,
237 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
238 throw ( lang::IllegalArgumentException
,
241 uno::RuntimeException
, std::exception
)
243 // TODO: use lObjArgs
245 if ( !xStorage
.is() )
246 throw lang::IllegalArgumentException( "No parent storage is provided!",
247 static_cast< ::cppu::OWeakObject
* >(this),
250 if ( sEntName
.isEmpty() )
251 throw lang::IllegalArgumentException( "Empty element name is provided!",
252 static_cast< ::cppu::OWeakObject
* >(this),
255 uno::Reference
< uno::XInterface
> xResult
;
256 uno::Sequence
< beans::PropertyValue
> aTempMedDescr( aMediaDescr
);
258 // check if there is FilterName
259 OUString aFilterName
= m_aConfigHelper
.UpdateMediaDescriptorWithFilterName( aTempMedDescr
, false );
261 if ( !aFilterName
.isEmpty() )
263 // the object can be loaded by one of the office application
264 uno::Reference
< embed::XEmbeddedObjectCreator
> xOOoEmbCreator
=
265 embed::OOoEmbeddedObjectFactory::create( m_xContext
);
267 xResult
= xOOoEmbCreator
->createInstanceInitFromMediaDescriptor( xStorage
,
274 // must be an OLE object
276 // TODO: in future, when more object types are possible this place seems
277 // to be a weak one, probably configuration must provide a type detection service
278 // for every factory, so any file could go through services until it is recognized
279 // or there is no more services
280 // Or for example the typename can be used to detect object type if typedetection
281 // was also extended.
283 uno::Reference
< embed::XEmbeddedObjectCreator
> xOleEmbCreator
=
284 embed::OLEEmbeddedObjectFactory::create( m_xContext
);
286 xResult
= xOleEmbCreator
->createInstanceInitFromMediaDescriptor( xStorage
, sEntName
, aTempMedDescr
, lObjArgs
);
293 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceUserInit(
294 const uno::Sequence
< sal_Int8
>& aClassID
,
295 const OUString
& sClassName
,
296 const uno::Reference
< embed::XStorage
>& xStorage
,
297 const OUString
& sEntName
,
298 sal_Int32 nEntryConnectionMode
,
299 const uno::Sequence
< beans::PropertyValue
>& aArgs
,
300 const uno::Sequence
< beans::PropertyValue
>& aObjectArgs
)
301 throw ( lang::IllegalArgumentException
,
304 uno::RuntimeException
, std::exception
)
306 uno::Reference
< uno::XInterface
> xResult
;
308 if ( !xStorage
.is() )
309 throw lang::IllegalArgumentException( "No parent storage is provided!",
310 static_cast< ::cppu::OWeakObject
* >(this),
313 if ( sEntName
.isEmpty() )
314 throw lang::IllegalArgumentException( "Empty element name is provided!",
315 static_cast< ::cppu::OWeakObject
* >(this),
318 OUString aEmbedFactory
= m_aConfigHelper
.GetFactoryNameByClassID( aClassID
);
319 uno::Reference
< embed::XEmbedObjectFactory
> xEmbFactory(
320 m_xContext
->getServiceManager()->createInstanceWithContext(aEmbedFactory
, m_xContext
),
322 if ( !xEmbFactory
.is() )
323 throw uno::RuntimeException(); // TODO:
325 return xEmbFactory
->createInstanceUserInit( aClassID
,
329 nEntryConnectionMode
,
335 uno::Reference
< uno::XInterface
> SAL_CALL
UNOEmbeddedObjectCreator::createInstanceLink(
336 const uno::Reference
< embed::XStorage
>& xStorage
,
337 const OUString
& sEntName
,
338 const uno::Sequence
< beans::PropertyValue
>& aMediaDescr
,
339 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
340 throw ( lang::IllegalArgumentException
,
343 uno::RuntimeException
, std::exception
)
345 uno::Reference
< uno::XInterface
> xResult
;
347 uno::Sequence
< beans::PropertyValue
> aTempMedDescr( aMediaDescr
);
349 // check if there is URL, URL must exist
351 for ( sal_Int32 nInd
= 0; nInd
< aTempMedDescr
.getLength(); nInd
++ )
352 if ( aTempMedDescr
[nInd
].Name
== "URL" )
353 aTempMedDescr
[nInd
].Value
>>= aURL
;
355 if ( aURL
.isEmpty() )
356 throw lang::IllegalArgumentException( "No URL for the link is provided!",
357 static_cast< ::cppu::OWeakObject
* >(this),
360 OUString aFilterName
= m_aConfigHelper
.UpdateMediaDescriptorWithFilterName( aTempMedDescr
, false );
362 if ( !aFilterName
.isEmpty() )
364 // the object can be loaded by one of the office application
365 uno::Reference
< embed::XEmbeddedObjectCreator
> xOOoLinkCreator
=
366 embed::OOoEmbeddedObjectFactory::create( m_xContext
);
368 xResult
= xOOoLinkCreator
->createInstanceLink( xStorage
,
375 // must be an OLE link
377 // TODO: in future, when more object types are possible this place seems
378 // to be a weak one, probably configuration must provide a type detection service
379 // for every factory, so any file could go through services until it is recognized
380 // or there is no more services
381 // Or for example the typename can be used to detect object type if typedetection
382 // was also extended.
384 if ( !xStorage
.is() )
385 throw lang::IllegalArgumentException( "No parent storage is provided!",
386 static_cast< ::cppu::OWeakObject
* >(this),
389 if ( sEntName
.isEmpty() )
390 throw lang::IllegalArgumentException( "Empty element name is provided!",
391 static_cast< ::cppu::OWeakObject
* >(this),
394 uno::Reference
< embed::XEmbeddedObjectCreator
> xLinkCreator
=
395 embed::OLEEmbeddedObjectFactory::create( m_xContext
);
397 xResult
= xLinkCreator
->createInstanceLink( xStorage
, sEntName
, aTempMedDescr
, lObjArgs
);
403 OUString SAL_CALL
UNOEmbeddedObjectCreator::getImplementationName()
404 throw ( uno::RuntimeException
, std::exception
)
406 return impl_staticGetImplementationName();
409 sal_Bool SAL_CALL
UNOEmbeddedObjectCreator::supportsService( const OUString
& ServiceName
)
410 throw ( uno::RuntimeException
, std::exception
)
412 return cppu::supportsService(this, ServiceName
);
415 uno::Sequence
< OUString
> SAL_CALL
UNOEmbeddedObjectCreator::getSupportedServiceNames()
416 throw ( uno::RuntimeException
, std::exception
)
418 return impl_staticGetSupportedServiceNames();
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */