1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 #include <com/sun/star/container/XChild.hpp>
27 #include <com/sun/star/container/XNameAccess.hpp>
28 #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
29 #include <com/sun/star/embed/XLinkCreator.hpp>
30 #include <com/sun/star/embed/XEmbedPersist.hpp>
31 #include <com/sun/star/embed/XLinkageSupport.hpp>
32 #include <com/sun/star/embed/XTransactedObject.hpp>
33 #include <com/sun/star/embed/XOptimizedStorage.hpp>
34 #include <com/sun/star/embed/EntryInitModes.hpp>
35 #include <com/sun/star/util/XCloseable.hpp>
36 #include <com/sun/star/util/XModifiable.hpp>
37 #include <com/sun/star/embed/EmbedStates.hpp>
38 #include <com/sun/star/datatransfer/XTransferable.hpp>
39 #include <com/sun/star/beans/XPropertySetInfo.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/embed/Aspects.hpp>
42 #include <com/sun/star/embed/EmbedMisc.hpp>
43 
44 #include <comphelper/seqstream.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/storagehelper.hxx>
47 #include <comphelper/embeddedobjectcontainer.hxx>
48 #include <comphelper/sequence.hxx>
49 #include <cppuhelper/weakref.hxx>
50 #include <hash_map>
51 #include <algorithm>
52 
53 #include <rtl/logfile.hxx>
54 
55 using namespace ::com::sun::star;
56 
57 namespace comphelper
58 {
59 
60 struct hashObjectName_Impl
61 {
operator ()comphelper::hashObjectName_Impl62 	size_t operator()(const ::rtl::OUString Str) const
63 	{
64 		return (size_t)Str.hashCode();
65 	}
66 };
67 
68 struct eqObjectName_Impl
69 {
operator ()comphelper::eqObjectName_Impl70 	sal_Bool operator()(const ::rtl::OUString Str1, const ::rtl::OUString Str2) const
71 	{
72 		return ( Str1 == Str2 );
73 	}
74 };
75 
76 typedef std::hash_map
77 <
78 	::rtl::OUString,
79 	::com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject >,
80 	hashObjectName_Impl,
81 	eqObjectName_Impl
82 >
83 EmbeddedObjectContainerNameMap;
84 
85 struct EmbedImpl
86 {
87 	// TODO/LATER: remove objects from temp. Container storage when object is disposed
88 	EmbeddedObjectContainerNameMap maObjectContainer;
89 	uno::Reference < embed::XStorage > mxStorage;
90 	EmbeddedObjectContainer* mpTempObjectContainer;
91 	uno::Reference < embed::XStorage > mxImageStorage;
92 	uno::WeakReference < uno::XInterface > m_xModel;
93 	//EmbeddedObjectContainerNameMap maTempObjectContainer;
94 	//uno::Reference < embed::XStorage > mxTempStorage;
95 
96 	/// bitfield
97 	bool mbOwnsStorage : 1;
98 	bool mbUserAllowsLinkUpdate : 1;
99 
100 	const uno::Reference < embed::XStorage >& GetReplacements();
101 };
102 
GetReplacements()103 const uno::Reference < embed::XStorage >& EmbedImpl::GetReplacements()
104 {
105 	if ( !mxImageStorage.is() )
106 	{
107 		try
108 		{
109 			mxImageStorage = mxStorage->openStorageElement(
110 				::rtl::OUString::createFromAscii( "ObjectReplacements" ), embed::ElementModes::READWRITE );
111 		}
112 		catch ( uno::Exception& )
113 		{
114 			mxImageStorage = mxStorage->openStorageElement(
115 				::rtl::OUString::createFromAscii( "ObjectReplacements" ), embed::ElementModes::READ );
116 		}
117 	}
118 
119 	if ( !mxImageStorage.is() )
120 		throw io::IOException();
121 
122 	return mxImageStorage;
123 }
124 
EmbeddedObjectContainer()125 EmbeddedObjectContainer::EmbeddedObjectContainer()
126 {
127 	pImpl = new EmbedImpl;
128 	pImpl->mxStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
129 	pImpl->mbOwnsStorage = true;
130 	pImpl->mbUserAllowsLinkUpdate = true;
131 	pImpl->mpTempObjectContainer = 0;
132 }
133 
EmbeddedObjectContainer(const uno::Reference<embed::XStorage> & rStor)134 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor )
135 {
136 	pImpl = new EmbedImpl;
137 	pImpl->mxStorage = rStor;
138 	pImpl->mbOwnsStorage = false;
139 	pImpl->mbUserAllowsLinkUpdate = true;
140 	pImpl->mpTempObjectContainer = 0;
141 }
142 
EmbeddedObjectContainer(const uno::Reference<embed::XStorage> & rStor,const uno::Reference<uno::XInterface> & xModel)143 EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor, const uno::Reference < uno::XInterface >& xModel )
144 {
145 	pImpl = new EmbedImpl;
146 	pImpl->mxStorage = rStor;
147 	pImpl->mbOwnsStorage = false;
148 	pImpl->mbUserAllowsLinkUpdate = true;
149 	pImpl->mpTempObjectContainer = 0;
150 	pImpl->m_xModel = xModel;
151 }
152 
SwitchPersistence(const uno::Reference<embed::XStorage> & rStor)153 void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference < embed::XStorage >& rStor )
154 {
155 	ReleaseImageSubStorage();
156 
157 	if ( pImpl->mbOwnsStorage )
158 		pImpl->mxStorage->dispose();
159 
160 	pImpl->mxStorage = rStor;
161 	pImpl->mbOwnsStorage = false;
162 }
163 
CommitImageSubStorage()164 sal_Bool EmbeddedObjectContainer::CommitImageSubStorage()
165 {
166 	if ( pImpl->mxImageStorage.is() )
167 	{
168 		try
169 		{
170 			sal_Bool bReadOnlyMode = sal_True;
171 			uno::Reference < beans::XPropertySet > xSet(pImpl->mxImageStorage,uno::UNO_QUERY);
172 			if ( xSet.is() )
173 			{
174 				// get the open mode from the parent storage
175 				sal_Int32 nMode = 0;
176 				uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("OpenMode") );
177 				if ( aAny >>= nMode )
178 					bReadOnlyMode = !(nMode & embed::ElementModes::WRITE );
179 			} // if ( xSet.is() )
180 			if ( !bReadOnlyMode )
181 			{
182 				uno::Reference< embed::XTransactedObject > xTransact( pImpl->mxImageStorage, uno::UNO_QUERY_THROW );
183 				xTransact->commit();
184 			}
185 		}
186 		catch( uno::Exception& )
187 		{
188 			return sal_False;
189 		}
190 	}
191 
192 	return sal_True;
193 }
194 
ReleaseImageSubStorage()195 void EmbeddedObjectContainer::ReleaseImageSubStorage()
196 {
197 	CommitImageSubStorage();
198 
199 	if ( pImpl->mxImageStorage.is() )
200 	{
201 		try
202 		{
203 			pImpl->mxImageStorage->dispose();
204 			pImpl->mxImageStorage = uno::Reference< embed::XStorage >();
205 		}
206 		catch( uno::Exception& )
207 		{
208 			OSL_ASSERT( "Problems releasing image substorage!\n" );
209 		}
210 	}
211 }
212 
~EmbeddedObjectContainer()213 EmbeddedObjectContainer::~EmbeddedObjectContainer()
214 {
215 	ReleaseImageSubStorage();
216 
217 	if ( pImpl->mbOwnsStorage )
218 		pImpl->mxStorage->dispose();
219 
220 	delete pImpl->mpTempObjectContainer;
221 	delete pImpl;
222 }
223 
CloseEmbeddedObjects()224 void EmbeddedObjectContainer::CloseEmbeddedObjects()
225 {
226 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
227 	while ( aIt != pImpl->maObjectContainer.end() )
228 	{
229 		uno::Reference < util::XCloseable > xClose( (*aIt).second, uno::UNO_QUERY );
230 		if ( xClose.is() )
231 		{
232 			try
233 			{
234 				xClose->close( sal_True );
235 			}
236 			catch ( uno::Exception& )
237 			{
238 			}
239 		}
240 
241 		aIt++;
242 	}
243 }
244 
CreateUniqueObjectName()245 ::rtl::OUString EmbeddedObjectContainer::CreateUniqueObjectName()
246 {
247 	::rtl::OUString aPersistName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Object ") );
248 	::rtl::OUString aStr;
249 	sal_Int32 i=1;
250 	do
251 	{
252 		aStr = aPersistName;
253 		aStr += ::rtl::OUString::valueOf( i++ );
254 	}
255 	while( HasEmbeddedObject( aStr ) );
256 	// TODO/LATER: should we consider deleted objects?
257 
258 	return aStr;
259 }
260 
GetObjectNames()261 uno::Sequence < ::rtl::OUString > EmbeddedObjectContainer::GetObjectNames()
262 {
263 	uno::Sequence < ::rtl::OUString > aSeq( pImpl->maObjectContainer.size() );
264 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
265 	sal_Int32 nIdx=0;
266 	while ( aIt != pImpl->maObjectContainer.end() )
267 		aSeq[nIdx++] = (*aIt++).first;
268 	return aSeq;
269 }
270 
HasEmbeddedObjects()271 sal_Bool EmbeddedObjectContainer::HasEmbeddedObjects()
272 {
273 	return pImpl->maObjectContainer.size() != 0;
274 }
275 
HasEmbeddedObject(const::rtl::OUString & rName)276 sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const ::rtl::OUString& rName )
277 {
278 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
279 	if ( aIt == pImpl->maObjectContainer.end() )
280 	{
281 		uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
282 		return xAccess->hasByName(rName);
283 	}
284 	else
285 		return sal_True;
286 }
287 
HasEmbeddedObject(const uno::Reference<embed::XEmbeddedObject> & xObj)288 sal_Bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj )
289 {
290 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
291 	while ( aIt != pImpl->maObjectContainer.end() )
292 	{
293 		if ( (*aIt).second == xObj )
294 			return sal_True;
295 		else
296 			aIt++;
297 	}
298 
299 	return sal_False;
300 }
301 
HasInstantiatedEmbeddedObject(const::rtl::OUString & rName)302 sal_Bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const ::rtl::OUString& rName )
303 {
304 	// allows to detect whether the object was already instantiated
305 	// currently the filter instantiate it on loading, so this method allows
306 	// to avoid objects pointing to the same persistence
307 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
308 	return ( aIt != pImpl->maObjectContainer.end() );
309 }
310 
GetEmbeddedObjectName(const::com::sun::star::uno::Reference<::com::sun::star::embed::XEmbeddedObject> & xObj)311 ::rtl::OUString EmbeddedObjectContainer::GetEmbeddedObjectName( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj )
312 {
313 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
314 	while ( aIt != pImpl->maObjectContainer.end() )
315 	{
316 		if ( (*aIt).second == xObj )
317 			return (*aIt).first;
318 		else
319 			aIt++;
320 	}
321 
322 	OSL_ENSURE( 0, "Unknown object!" );
323 	return ::rtl::OUString();
324 }
325 
GetEmbeddedObject(const::rtl::OUString & rName)326 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::GetEmbeddedObject( const ::rtl::OUString& rName )
327 {
328 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetEmbeddedObject" );
329 
330 	OSL_ENSURE( !rName.isEmpty(), "Empty object name!");
331 
332 	uno::Reference < embed::XEmbeddedObject > xObj;
333 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
334 
335 #if OSL_DEBUG_LEVEL > 1
336 	uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
337 	uno::Sequence< ::rtl::OUString> aSeq = xAccess->getElementNames();
338 	const ::rtl::OUString* pIter = aSeq.getConstArray();
339 	const ::rtl::OUString* pEnd  = pIter + aSeq.getLength();
340 	for(;pIter != pEnd;++pIter)
341 	{
342 		(void)*pIter;
343 	}
344 	OSL_ENSURE( aIt != pImpl->maObjectContainer.end() || xAccess->hasByName(rName), "Could not return object!" );
345 #endif
346 
347 	// check if object was already created
348 	if ( aIt != pImpl->maObjectContainer.end() )
349 		xObj = (*aIt).second;
350 	else
351 		xObj = Get_Impl( rName, uno::Reference < embed::XEmbeddedObject >() );
352 
353 	return xObj;
354 }
355 
Get_Impl(const::rtl::OUString & rName,const uno::Reference<embed::XEmbeddedObject> & xCopy)356 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::Get_Impl( const ::rtl::OUString& rName, const uno::Reference < embed::XEmbeddedObject >& xCopy )
357 {
358 	uno::Reference < embed::XEmbeddedObject > xObj;
359 	try
360 	{
361 		// create the object from the storage
362 		uno::Reference < beans::XPropertySet > xSet( pImpl->mxStorage, uno::UNO_QUERY );
363 		sal_Bool bReadOnlyMode = sal_True;
364 		if ( xSet.is() )
365 		{
366 			// get the open mode from the parent storage
367 			sal_Int32 nMode = 0;
368 			uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("OpenMode") );
369 			if ( aAny >>= nMode )
370 				bReadOnlyMode = !(nMode & embed::ElementModes::WRITE );
371 		}
372 
373 		// object was not added until now - should happen only by calling this method from "inside"
374 		//TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call)
375 		uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance(
376 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY );
377 		uno::Sequence< beans::PropertyValue > aObjDescr( xCopy.is() ? 2 : 1 );
378 		aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
379 		aObjDescr[0].Value <<= pImpl->m_xModel.get();
380 		if ( xCopy.is() )
381 		{
382 			aObjDescr[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CloneFrom" ) );
383 			aObjDescr[1].Value <<= xCopy;
384 		}
385 
386 		uno::Sequence< beans::PropertyValue > aMediaDescr( 1 );
387 		aMediaDescr[0].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly"));
388 		aMediaDescr[0].Value <<= bReadOnlyMode;
389 		xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromEntry(
390 				pImpl->mxStorage, rName,
391 				aMediaDescr, aObjDescr ), uno::UNO_QUERY );
392 
393 		// insert object into my list
394 		AddEmbeddedObject( xObj, rName );
395 	}
396 	catch ( uno::Exception& )
397 	{
398 	}
399 
400 	return xObj;
401 }
402 
CreateEmbeddedObject(const uno::Sequence<sal_Int8> & rClassId,const uno::Sequence<beans::PropertyValue> & rArgs,::rtl::OUString & rNewName)403 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId,
404 			const uno::Sequence < beans::PropertyValue >& rArgs, ::rtl::OUString& rNewName )
405 {
406 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CreateEmbeddedObject" );
407 
408 	if ( rNewName.isEmpty() )
409 		rNewName = CreateUniqueObjectName();
410 
411 	OSL_ENSURE( !HasEmbeddedObject(rNewName), "Object to create already exists!");
412 
413 	// create object from classid by inserting it into storage
414 	uno::Reference < embed::XEmbeddedObject > xObj;
415 	try
416 	{
417 		uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance(
418 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY );
419 
420 		uno::Sequence< beans::PropertyValue > aObjDescr( rArgs.getLength() + 1 );
421 		aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
422 		aObjDescr[0].Value <<= pImpl->m_xModel.get();
423 		::std::copy( rArgs.getConstArray(), rArgs.getConstArray() + rArgs.getLength(), aObjDescr.getArray() + 1 );
424 		xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitNew(
425 					rClassId, ::rtl::OUString(), pImpl->mxStorage, rNewName,
426 					aObjDescr ), uno::UNO_QUERY );
427 
428 		AddEmbeddedObject( xObj, rNewName );
429 
430 		OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
431 					"A freshly create object should be running always!\n" );
432 	}
433 	catch ( uno::Exception& )
434 	{
435 	}
436 
437 	return xObj;
438 }
439 
CreateEmbeddedObject(const uno::Sequence<sal_Int8> & rClassId,::rtl::OUString & rNewName)440 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( const uno::Sequence < sal_Int8 >& rClassId, ::rtl::OUString& rNewName )
441 {
442 	return CreateEmbeddedObject( rClassId, uno::Sequence < beans::PropertyValue >(), rNewName );
443 }
444 
AddEmbeddedObject(const::com::sun::star::uno::Reference<::com::sun::star::embed::XEmbeddedObject> & xObj,const::rtl::OUString & rName)445 void EmbeddedObjectContainer::AddEmbeddedObject( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, const ::rtl::OUString& rName )
446 {
447 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::AddEmbeddedObject" );
448 
449 #if OSL_DEBUG_LEVEL > 1
450 	OSL_ENSURE( !rName.isEmpty(), "Added object doesn't have a name!");
451 	uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
452 	uno::Reference < embed::XEmbedPersist > xEmb( xObj, uno::UNO_QUERY );
453 	uno::Reference < embed::XLinkageSupport > xLink( xEmb, uno::UNO_QUERY );
454 	// if the object has a persistence and the object is not a link than it must have persistence entry in the storage
455 	OSL_ENSURE( !( xEmb.is() && ( !xLink.is() || !xLink->isLink() ) ) || xAccess->hasByName(rName),
456 					"Added element not in storage!" );
457 #endif
458 
459 	// remember object - it needs to be in storage already
460 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
461 	OSL_ENSURE( aIt == pImpl->maObjectContainer.end(), "Element already inserted!" );
462 	pImpl->maObjectContainer[ rName ] = xObj;
463 	uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY );
464 	if ( xChild.is() && xChild->getParent() != pImpl->m_xModel.get() )
465 		xChild->setParent( pImpl->m_xModel.get() );
466 
467 	// look for object in temorary container
468 	if ( pImpl->mpTempObjectContainer )
469 	{
470 		aIt = pImpl->mpTempObjectContainer->pImpl->maObjectContainer.begin();
471 		while ( aIt != pImpl->mpTempObjectContainer->pImpl->maObjectContainer.end() )
472 		{
473 			if ( (*aIt).second == xObj )
474 			{
475 				// copy replacement image from temporary container (if there is any)
476 				::rtl::OUString aTempName = (*aIt).first;
477 				::rtl::OUString aMediaType;
478 				uno::Reference < io::XInputStream > xStream = pImpl->mpTempObjectContainer->GetGraphicStream( xObj, &aMediaType );
479 				if ( xStream.is() )
480 				{
481 					InsertGraphicStream( xStream, rName, aMediaType );
482 					xStream = 0;
483 					pImpl->mpTempObjectContainer->RemoveGraphicStream( aTempName );
484 				}
485 
486 				// remove object from storage of temporary container
487 				uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
488 				if ( xPersist.is() )
489 				{
490 					try
491 					{
492 						pImpl->mpTempObjectContainer->pImpl->mxStorage->removeElement( aTempName );
493 					}
494 					catch ( uno::Exception& )
495 					{
496 					}
497 				}
498 
499 				// temp. container needs to forget the object
500 				pImpl->mpTempObjectContainer->pImpl->maObjectContainer.erase( aIt );
501 				break;
502 			}
503 			else
504 				aIt++;
505 		}
506 	}
507 }
508 
StoreEmbeddedObject(const uno::Reference<embed::XEmbeddedObject> & xObj,::rtl::OUString & rName,sal_Bool bCopy)509 sal_Bool EmbeddedObjectContainer::StoreEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName, sal_Bool bCopy )
510 {
511 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::StoreEmbeddedObject" );
512 
513 	uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
514 	if ( rName.isEmpty() )
515 		rName = CreateUniqueObjectName();
516 
517 #if OSL_DEBUG_LEVEL > 1
518 	uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
519 	OSL_ENSURE( !xPersist.is() || !xAccess->hasByName(rName), "Inserting element already present in storage!" );
520 	OSL_ENSURE( xPersist.is() || xObj->getCurrentState() == embed::EmbedStates::RUNNING, "Non persistent object inserted!");
521 #endif
522 
523 	// insert objects' storage into the container storage (if object has one)
524 	try
525 	{
526 		if ( xPersist.is() )
527 		{
528 			uno::Sequence < beans::PropertyValue > aSeq;
529 			if ( bCopy )
530 				xPersist->storeToEntry( pImpl->mxStorage, rName, aSeq, aSeq );
531 			else
532 			{
533 				// TODO/LATER: possible optimisation, don't store immediately
534 				//xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq );
535 				xPersist->storeAsEntry( pImpl->mxStorage, rName, aSeq, aSeq );
536 				xPersist->saveCompleted( sal_True );
537 			}
538 		}
539 	}
540 	catch ( uno::Exception& )
541 	{
542 		// TODO/LATER: better error recovery should keep storage intact
543 		return sal_False;
544 	}
545 
546 	return sal_True;
547 }
548 
InsertEmbeddedObject(const uno::Reference<embed::XEmbeddedObject> & xObj,::rtl::OUString & rName)549 sal_Bool EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName )
550 {
551 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( Object )" );
552 	// store it into the container storage
553 	if ( StoreEmbeddedObject( xObj, rName, sal_False ) )
554 	{
555 		// remember object
556 		AddEmbeddedObject( xObj, rName );
557 		return sal_True;
558 	}
559 	else
560 		return sal_False;
561 }
562 
InsertEmbeddedObject(const uno::Reference<io::XInputStream> & xStm,::rtl::OUString & rNewName)563 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const uno::Reference < io::XInputStream >& xStm, ::rtl::OUString& rNewName )
564 {
565 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( InputStream )" );
566 
567 	if ( rNewName.isEmpty() )
568 		rNewName = CreateUniqueObjectName();
569 
570 	// store it into the container storage
571 	sal_Bool bIsStorage = sal_False;
572 	try
573 	{
574 		// first try storage persistence
575 		uno::Reference < embed::XStorage > xStore = ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm );
576 
577 		// storage was created from stream successfully
578 		bIsStorage = sal_True;
579 
580 		uno::Reference < embed::XStorage > xNewStore = pImpl->mxStorage->openStorageElement( rNewName, embed::ElementModes::READWRITE );
581 		xStore->copyToStorage( xNewStore );
582 	}
583 	catch ( uno::Exception& )
584 	{
585 		if ( bIsStorage )
586 			// it is storage persistence, but opening of new substorage or copying to it failed
587 			return uno::Reference < embed::XEmbeddedObject >();
588 
589 		// stream didn't contain a storage, now try stream persistence
590 		try
591 		{
592 			uno::Reference < io::XStream > xNewStream = pImpl->mxStorage->openStreamElement( rNewName, embed::ElementModes::READWRITE );
593 			::comphelper::OStorageHelper::CopyInputToOutput( xStm, xNewStream->getOutputStream() );
594 
595 			// No mediatype is provided so the default for OLE objects value is used
596 			// it is correct so for now, but what if somebody introduces a new stream based embedded object?
597 			// Probably introducing of such an object must be restricted ( a storage must be used! ).
598 			uno::Reference< beans::XPropertySet > xProps( xNewStream, uno::UNO_QUERY_THROW );
599 			xProps->setPropertyValue(
600 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ),
601 					uno::makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.oleobject" ) ) ) );
602 		}
603 		catch ( uno::Exception& )
604 		{
605 			// complete disaster!
606 			return uno::Reference < embed::XEmbeddedObject >();
607 		}
608 	}
609 
610 	// stream was copied into the container storage in either way, now try to open something form it
611 	uno::Reference < embed::XEmbeddedObject > xRet = GetEmbeddedObject( rNewName );
612 	try
613 	{
614 		if ( !xRet.is() )
615 			// no object could be created, so withdraw insertion
616 			pImpl->mxStorage->removeElement( rNewName );
617 	}
618 	catch ( uno::Exception& )
619 	{
620 	}
621 
622 	return xRet;
623 }
624 
InsertEmbeddedObject(const::com::sun::star::uno::Sequence<::com::sun::star::beans::PropertyValue> & aMedium,::rtl::OUString & rNewName)625 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, ::rtl::OUString& rNewName )
626 {
627 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedObject( MediaDescriptor )" );
628 
629 	if ( rNewName.isEmpty() )
630 		rNewName = CreateUniqueObjectName();
631 
632 	uno::Reference < embed::XEmbeddedObject > xObj;
633 	try
634 	{
635 		uno::Reference < embed::XEmbedObjectCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance(
636 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY );
637 		uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
638 		aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
639 		aObjDescr[0].Value <<= pImpl->m_xModel.get();
640 		xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceInitFromMediaDescriptor(
641 				pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY );
642 		uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
643 
644 		OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
645 					"A freshly create object should be running always!\n" );
646 
647 		// possible optimization: store later!
648 		if ( xPersist.is())
649 			xPersist->storeOwn();
650 
651 		AddEmbeddedObject( xObj, rNewName );
652 	}
653 	catch ( uno::Exception& )
654 	{
655 	}
656 
657 	return xObj;
658 }
659 
InsertEmbeddedLink(const::com::sun::star::uno::Sequence<::com::sun::star::beans::PropertyValue> & aMedium,::rtl::OUString & rNewName)660 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedLink( const ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue >& aMedium, ::rtl::OUString& rNewName )
661 {
662 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertEmbeddedLink" );
663 
664 	if ( rNewName.isEmpty() )
665 		rNewName = CreateUniqueObjectName();
666 
667 	uno::Reference < embed::XEmbeddedObject > xObj;
668 	try
669 	{
670 		uno::Reference < embed::XLinkCreator > xFactory( ::comphelper::getProcessServiceFactory()->createInstance(
671 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator")) ), uno::UNO_QUERY );
672 		uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
673 		aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
674 		aObjDescr[0].Value <<= pImpl->m_xModel.get();
675 		xObj = uno::Reference < embed::XEmbeddedObject >( xFactory->createInstanceLink(
676 				pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY );
677 
678 		uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
679 
680 		OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED,
681 					"A freshly create object should be running always!\n" );
682 
683 		// possible optimization: store later!
684 		if ( xPersist.is())
685 			xPersist->storeOwn();
686 
687 		AddEmbeddedObject( xObj, rNewName );
688 	}
689 	catch ( uno::Exception& )
690 	{
691 	}
692 
693 	return xObj;
694 }
695 
TryToCopyGraphReplacement(EmbeddedObjectContainer & rSrc,const::rtl::OUString & aOrigName,const::rtl::OUString & aTargetName)696 sal_Bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer& rSrc,
697 															const ::rtl::OUString& aOrigName,
698 															const ::rtl::OUString& aTargetName )
699 {
700 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::TryToCopyGraphReplacement" );
701 
702 	sal_Bool bResult = sal_False;
703 
704 	if ( ( &rSrc != this || !aOrigName.equals( aTargetName ) ) && !aOrigName.isEmpty() && !aTargetName.isEmpty() )
705 	{
706 		::rtl::OUString aMediaType;
707 		uno::Reference < io::XInputStream > xGrStream = rSrc.GetGraphicStream( aOrigName, &aMediaType );
708 		if ( xGrStream.is() )
709 			bResult = InsertGraphicStream( xGrStream, aTargetName, aMediaType );
710 	}
711 
712 	return bResult;
713 }
714 
CopyEmbeddedObject(EmbeddedObjectContainer & rSrc,const uno::Reference<embed::XEmbeddedObject> & xObj,::rtl::OUString & rName)715 sal_Bool EmbeddedObjectContainer::CopyEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName )
716 {
717 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyEmbeddedObject" );
718 
719 	OSL_ENSURE( sal_False,
720 				"This method is depricated! Use EmbeddedObjectContainer::CopyAndGetEmbeddedObject() to copy object!\n" );
721 
722 	// get the object name before(!) it is assigned to a new storage
723 	::rtl::OUString aOrigName;
724 	uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
725 	if ( xPersist.is() )
726 		aOrigName = xPersist->getEntryName();
727 
728 	if ( rName.isEmpty() )
729 		rName = CreateUniqueObjectName();
730 
731 	if ( StoreEmbeddedObject( xObj, rName, sal_True ) )
732 	{
733 		TryToCopyGraphReplacement( rSrc, aOrigName, rName );
734 		return sal_True;
735 	}
736 
737 	return sal_False;
738 }
739 
CopyAndGetEmbeddedObject(EmbeddedObjectContainer & rSrc,const uno::Reference<embed::XEmbeddedObject> & xObj,::rtl::OUString & rName)740 uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CopyAndGetEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName )
741 {
742 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CopyAndGetEmbeddedObject" );
743 
744 	uno::Reference< embed::XEmbeddedObject > xResult;
745 
746 	// TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future
747 	// do an incompatible change so that object name is provided in all the move and copy methods
748 	::rtl::OUString aOrigName;
749 	try
750 	{
751 		uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY_THROW );
752 		aOrigName = xPersist->getEntryName();
753 	}
754 	catch( uno::Exception& )
755 	{}
756 
757 	if ( rName.isEmpty() )
758 		rName = CreateUniqueObjectName();
759 
760 	// objects without persistence are not really stored by the method
761 	if ( xObj.is() && StoreEmbeddedObject( xObj, rName, sal_True ) )
762 	{
763 		xResult = Get_Impl( rName, xObj);
764 		if ( !xResult.is() )
765 		{
766 			// this is a case when object has no real persistence
767 			// in such cases a new object should be explicitly created and initialized with the data of the old one
768 			try
769 			{
770 				uno::Reference< embed::XLinkageSupport > xOrigLinkage( xObj, uno::UNO_QUERY );
771 				if ( xOrigLinkage.is() && xOrigLinkage->isLink() )
772 				{
773 					// this is a OOo link, it has no persistence
774 					::rtl::OUString aURL = xOrigLinkage->getLinkURL();
775 					if ( aURL.isEmpty() )
776 						throw uno::RuntimeException();
777 
778 					// create new linked object from the URL the link is based on
779 					uno::Reference < embed::XLinkCreator > xCreator(
780 						::comphelper::getProcessServiceFactory()->createInstance(
781 							::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator") ) ),
782 						uno::UNO_QUERY_THROW );
783 
784 					uno::Sequence< beans::PropertyValue > aMediaDescr( 1 );
785 					aMediaDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
786 					aMediaDescr[0].Value <<= aURL;
787 					uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
788 					aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
789 					aObjDescr[0].Value <<= pImpl->m_xModel.get();
790 					xResult = uno::Reference < embed::XEmbeddedObject >(
791 								xCreator->createInstanceLink(
792 									pImpl->mxStorage,
793 									rName,
794 									aMediaDescr,
795 									aObjDescr ),
796 								uno::UNO_QUERY_THROW );
797 				}
798 				else
799 				{
800 					// the component is required for copying of this object
801 					if ( xObj->getCurrentState() == embed::EmbedStates::LOADED )
802 						xObj->changeState( embed::EmbedStates::RUNNING );
803 
804 					// this must be an object based on properties, otherwise we can not copy it currently
805 					uno::Reference< beans::XPropertySet > xOrigProps( xObj->getComponent(), uno::UNO_QUERY_THROW );
806 
807 					// use object class ID to create a new one and transfer all the properties
808 					uno::Reference < embed::XEmbedObjectCreator > xCreator(
809 						::comphelper::getProcessServiceFactory()->createInstance(
810 							::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.EmbeddedObjectCreator") ) ),
811 						uno::UNO_QUERY_THROW );
812 
813 					uno::Sequence< beans::PropertyValue > aObjDescr( 1 );
814 					aObjDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Parent" ) );
815 					aObjDescr[0].Value <<= pImpl->m_xModel.get();
816 					xResult = uno::Reference < embed::XEmbeddedObject >(
817 								xCreator->createInstanceInitNew(
818 									xObj->getClassID(),
819 									xObj->getClassName(),
820 									pImpl->mxStorage,
821 									rName,
822 									aObjDescr ),
823 								uno::UNO_QUERY_THROW );
824 
825 					if ( xResult->getCurrentState() == embed::EmbedStates::LOADED )
826 						xResult->changeState( embed::EmbedStates::RUNNING );
827 
828 					uno::Reference< beans::XPropertySet > xTargetProps( xResult->getComponent(), uno::UNO_QUERY_THROW );
829 
830 					// copy all the properties from xOrigProps to xTargetProps
831 					uno::Reference< beans::XPropertySetInfo > xOrigInfo = xOrigProps->getPropertySetInfo();
832 					if ( !xOrigInfo.is() )
833 						throw uno::RuntimeException();
834 
835 					uno::Sequence< beans::Property > aPropertiesList = xOrigInfo->getProperties();
836 					for ( sal_Int32 nInd = 0; nInd < aPropertiesList.getLength(); nInd++ )
837 					{
838 						try
839 						{
840 							xTargetProps->setPropertyValue(
841 								aPropertiesList[nInd].Name,
842 								xOrigProps->getPropertyValue( aPropertiesList[nInd].Name ) );
843 						}
844 						catch( beans::PropertyVetoException& )
845 						{
846 							// impossibility to copy readonly property is not treated as an error for now
847 							// but the assertion is helpful to detect such scenarios and review them
848 							OSL_ENSURE( sal_False, "Could not copy readonly property!\n" );
849 						}
850 					}
851 				}
852 
853 				if ( xResult.is() )
854 					AddEmbeddedObject( xResult, rName );
855 			}
856 			catch( uno::Exception& )
857 			{
858 				if ( xResult.is() )
859 				{
860 					try
861 					{
862 						xResult->close( sal_True );
863 					}
864 					catch( uno::Exception& )
865 					{}
866 					xResult = uno::Reference< embed::XEmbeddedObject >();
867 				}
868 			}
869 		}
870 	}
871 
872 	OSL_ENSURE( xResult.is(), "Can not copy embedded object that has no persistence!\n" );
873 
874 	if ( xResult.is() )
875 	{
876 		// the object is successfully copied, try to copy graphical replacement
877 		if ( !aOrigName.isEmpty() )
878 			TryToCopyGraphReplacement( rSrc, aOrigName, rName );
879 
880 		// the object might need the size to be set
881 		try
882 		{
883 			if ( xResult->getStatus( embed::Aspects::MSOLE_CONTENT ) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD )
884 				xResult->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT,
885 											xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) );
886 		}
887 		catch( uno::Exception& )
888 		{}
889 	}
890 
891 	return xResult;
892 }
893 
MoveEmbeddedObject(EmbeddedObjectContainer & rSrc,const uno::Reference<embed::XEmbeddedObject> & xObj,::rtl::OUString & rName)894 sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( EmbeddedObjectContainer& rSrc, const uno::Reference < embed::XEmbeddedObject >& xObj, ::rtl::OUString& rName )
895 {
896 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Object )" );
897 
898 	// get the object name before(!) it is assigned to a new storage
899 	uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
900 	::rtl::OUString aName;
901 	if ( xPersist.is() )
902 		aName = xPersist->getEntryName();
903 
904 	// now move the object to the new container; the returned name is the new persist name in this container
905 	sal_Bool bRet;
906 
907 	try
908 	{
909 		bRet = InsertEmbeddedObject( xObj, rName );
910 		if ( bRet )
911 			TryToCopyGraphReplacement( rSrc, aName, rName );
912 	}
913 	catch ( uno::Exception& e )
914 	{
915 		(void)e;
916 		OSL_ENSURE( sal_False, "Failed to insert embedded object into storage!" );
917 		bRet = sal_False;
918 	}
919 
920 	if ( bRet )
921 	{
922 		// now remove the object from the former container
923 		bRet = sal_False;
924 		EmbeddedObjectContainerNameMap::iterator aIt = rSrc.pImpl->maObjectContainer.begin();
925 		while ( aIt != rSrc.pImpl->maObjectContainer.end() )
926 		{
927 			if ( (*aIt).second == xObj )
928 			{
929 				rSrc.pImpl->maObjectContainer.erase( aIt );
930 				bRet = sal_True;
931 				break;
932 			}
933 
934 			aIt++;
935 		}
936 
937 		OSL_ENSURE( bRet, "Object not found for removal!" );
938 		if ( xPersist.is() )
939 		{
940 			// now it's time to remove the storage from the container storage
941 			try
942 			{
943 				if ( xPersist.is() )
944 					rSrc.pImpl->mxStorage->removeElement( aName );
945 			}
946 			catch ( uno::Exception& )
947 			{
948 				OSL_ENSURE( sal_False, "Failed to remove object from storage!" );
949 				bRet = sal_False;
950 			}
951 		}
952 
953 		// rSrc.RemoveGraphicStream( aName );
954 	}
955 
956 	return bRet;
957 }
958 
959 //sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const ::rtl::OUString& rName, sal_Bool bClose )
960 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
RemoveEmbeddedObject(const::rtl::OUString & rName,sal_Bool bClose,sal_Bool bKeepToTempStorage)961 sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const ::rtl::OUString& rName, sal_Bool bClose, sal_Bool bKeepToTempStorage )
962 {
963 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Name )" );
964 
965 	uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( rName );
966 	if ( xObj.is() )
967 		//return RemoveEmbeddedObject( xObj, bClose );
968 		return RemoveEmbeddedObject( xObj, bClose, bKeepToTempStorage );
969 	else
970 		return sal_False;
971 }
972 
MoveEmbeddedObject(const::rtl::OUString & rName,EmbeddedObjectContainer & rCnt)973 sal_Bool EmbeddedObjectContainer::MoveEmbeddedObject( const ::rtl::OUString& rName, EmbeddedObjectContainer& rCnt )
974 {
975 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::MoveEmbeddedObject( Name )" );
976 
977 	// find object entry
978 	EmbeddedObjectContainerNameMap::iterator aIt2 = rCnt.pImpl->maObjectContainer.find( rName );
979 	OSL_ENSURE( aIt2 == rCnt.pImpl->maObjectContainer.end(), "Object does already exist in target container!" );
980 
981 	if ( aIt2 != rCnt.pImpl->maObjectContainer.end() )
982 		return sal_False;
983 
984 	uno::Reference < embed::XEmbeddedObject > xObj;
985 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.find( rName );
986 	if ( aIt != pImpl->maObjectContainer.end() )
987 	{
988 		xObj = (*aIt).second;
989 		try
990 		{
991 			if ( xObj.is() )
992 			{
993 				// move object
994 				::rtl::OUString aName( rName );
995 				rCnt.InsertEmbeddedObject( xObj, aName );
996 				pImpl->maObjectContainer.erase( aIt );
997 				uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
998 				if ( xPersist.is() )
999 					pImpl->mxStorage->removeElement( rName );
1000 			}
1001 			else
1002 			{
1003 				// copy storages; object *must* have persistence!
1004 				uno::Reference < embed::XStorage > xOld = pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READ );
1005 				uno::Reference < embed::XStorage > xNew = rCnt.pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READWRITE );
1006 				xOld->copyToStorage( xNew );
1007 			}
1008 
1009 			rCnt.TryToCopyGraphReplacement( *this, rName, rName );
1010 			// RemoveGraphicStream( rName );
1011 
1012 			return sal_True;
1013 		}
1014 		catch ( uno::Exception& )
1015 		{
1016 			OSL_ENSURE(0,"Could not move object!");
1017 			return sal_False;
1018 		}
1019 
1020 	}
1021 	else
1022 		OSL_ENSURE(0,"Unknown object!");
1023 	return sal_False;
1024 }
1025 
1026 //sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose )
1027 // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+
RemoveEmbeddedObject(const uno::Reference<embed::XEmbeddedObject> & xObj,sal_Bool bClose,sal_Bool bKeepToTempStorage)1028 sal_Bool EmbeddedObjectContainer::RemoveEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Bool bClose, sal_Bool bKeepToTempStorage )
1029 {
1030 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveEmbeddedObject( Object )" );
1031 
1032 	uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1033 	::rtl::OUString aName;
1034 	if ( xPersist.is() )
1035 		aName = xPersist->getEntryName();
1036 
1037 #if OSL_DEBUG_LEVEL > 1
1038 	uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY );
1039 	uno::Reference < embed::XLinkageSupport > xLink( xPersist, uno::UNO_QUERY );
1040 	sal_Bool bIsNotEmbedded = !xPersist.is() || xLink.is() && xLink->isLink();
1041 
1042 	// if the object has a persistence and the object is not a link than it must have persistence entry in the storage
1043 	OSL_ENSURE( bIsNotEmbedded || xAccess->hasByName(aName), "Removing element not present in storage!" );
1044 #endif
1045 
1046 	// try to close it if permitted
1047 	if ( bClose )
1048 	{
1049 		uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY );
1050 		try
1051 		{
1052 			xClose->close( sal_True );
1053 		}
1054 		catch ( util::CloseVetoException& )
1055 		{
1056 			bClose = sal_False;
1057 		}
1058 	}
1059 
1060 	if ( !bClose )
1061 	{
1062 		// somebody still needs the object, so we must assign a temporary persistence
1063 		try
1064 		{
1065 		//	if ( xPersist.is() )
1066 			if ( xPersist.is() && bKeepToTempStorage )	// #i119941
1067 			{
1068 				/*
1069 				// TODO/LATER: needs storage handling! Why not letting the object do it?!
1070 				if ( !pImpl->mxTempStorage.is() )
1071 					pImpl->mxTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
1072 				uno::Sequence < beans::PropertyValue > aSeq;
1073 
1074 				::rtl::OUString aTmpPersistName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Object ") );
1075 				aTmpPersistName += ::rtl::OUString::valueOf( (sal_Int32) pImpl->maTempObjectContainer.size() );
1076 
1077 				xPersist->storeAsEntry( pImpl->mxTempStorage, aTmpPersistName, aSeq, aSeq );
1078 				xPersist->saveCompleted( sal_True );
1079 
1080 				pImpl->maTempObjectContainer[ aTmpPersistName ] = uno::Reference < embed::XEmbeddedObject >();
1081 				*/
1082 
1083 				if ( !pImpl->mpTempObjectContainer )
1084 				{
1085 					pImpl->mpTempObjectContainer = new EmbeddedObjectContainer();
1086 					try
1087 					{
1088 						// TODO/LATER: in future probably the temporary container will have two storages ( of two formats )
1089 						//             the media type will be provided with object insertion
1090 						::rtl::OUString aOrigStorMediaType;
1091 						uno::Reference< beans::XPropertySet > xStorProps( pImpl->mxStorage, uno::UNO_QUERY_THROW );
1092 						static const ::rtl::OUString s_sMediaType(RTL_CONSTASCII_USTRINGPARAM("MediaType"));
1093 						xStorProps->getPropertyValue( s_sMediaType ) >>= aOrigStorMediaType;
1094 
1095 						OSL_ENSURE( !aOrigStorMediaType.isEmpty(), "No valuable media type in the storage!\n" );
1096 
1097 						uno::Reference< beans::XPropertySet > xTargetStorProps(
1098 																	pImpl->mpTempObjectContainer->pImpl->mxStorage,
1099 																	uno::UNO_QUERY_THROW );
1100 						xTargetStorProps->setPropertyValue( s_sMediaType,uno::makeAny( aOrigStorMediaType ) );
1101 					}
1102 					catch( uno::Exception& )
1103 					{
1104 						OSL_ENSURE( sal_False, "Can not set the new media type to a storage!\n" );
1105 					}
1106 				}
1107 
1108 				::rtl::OUString aTempName, aMediaType;
1109 				pImpl->mpTempObjectContainer->InsertEmbeddedObject( xObj, aTempName );
1110 
1111 				uno::Reference < io::XInputStream > xStream = GetGraphicStream( xObj, &aMediaType );
1112 				if ( xStream.is() )
1113 					pImpl->mpTempObjectContainer->InsertGraphicStream( xStream, aTempName, aMediaType );
1114 
1115 				// object is stored, so at least it can be set to loaded state
1116 				xObj->changeState( embed::EmbedStates::LOADED );
1117 			}
1118 			else
1119 				// objects without persistence need to stay in running state if they shall not be closed
1120 				xObj->changeState( embed::EmbedStates::RUNNING );
1121 		}
1122 		catch ( uno::Exception& )
1123 		{
1124 			return sal_False;
1125 		}
1126 	}
1127 
1128 	sal_Bool bFound = sal_False;
1129 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1130 	while ( aIt != pImpl->maObjectContainer.end() )
1131 	{
1132 		if ( (*aIt).second == xObj )
1133 		{
1134 			pImpl->maObjectContainer.erase( aIt );
1135 			bFound = sal_True;
1136 			uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY );
1137 			if ( xChild.is() )
1138 				xChild->setParent( uno::Reference < uno::XInterface >() );
1139 			break;
1140 		}
1141 
1142 		aIt++;
1143 	}
1144 
1145 	OSL_ENSURE( bFound, "Object not found for removal!" );
1146 	// if ( xPersist.is() )
1147 	if ( xPersist.is() && bKeepToTempStorage )	// #i119941
1148 	{
1149 		// remove replacement image (if there is one)
1150 		RemoveGraphicStream( aName );
1151 
1152 		// now it's time to remove the storage from the container storage
1153 		try
1154 		{
1155 #if OSL_DEBUG_LEVEL > 1
1156 			// if the object has a persistence and the object is not a link than it must have persistence entry in storage
1157 			OSL_ENSURE( bIsNotEmbedded || pImpl->mxStorage->hasByName( aName ), "The object has no persistence entry in the storage!" );
1158 #endif
1159 			if ( xPersist.is() && pImpl->mxStorage->hasByName( aName ) )
1160 				pImpl->mxStorage->removeElement( aName );
1161 		}
1162 		catch ( uno::Exception& )
1163 		{
1164 			OSL_ENSURE( sal_False, "Failed to remove object from storage!" );
1165 			return sal_False;
1166 		}
1167 	}
1168 
1169 	return sal_True;
1170 }
1171 
CloseEmbeddedObject(const uno::Reference<embed::XEmbeddedObject> & xObj)1172 sal_Bool EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj )
1173 {
1174 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::CloseEmbeddedObject" );
1175 
1176 	// disconnect the object from the container and close it if possible
1177 
1178 	sal_Bool bFound = sal_False;
1179 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1180 	while ( aIt != pImpl->maObjectContainer.end() )
1181 	{
1182 		if ( (*aIt).second == xObj )
1183 		{
1184 			pImpl->maObjectContainer.erase( aIt );
1185 			bFound = sal_True;
1186 			break;
1187 		}
1188 
1189 		aIt++;
1190 	}
1191 
1192 	if ( bFound )
1193 	{
1194 		uno::Reference < ::util::XCloseable > xClose( xObj, uno::UNO_QUERY );
1195 		try
1196 		{
1197 			xClose->close( sal_True );
1198 		}
1199 		catch ( uno::Exception& )
1200 		{
1201 			// it is no problem if the object is already closed
1202 			// TODO/LATER: what if the object can not be closed?
1203 		}
1204 	}
1205 
1206 	return bFound;
1207 }
1208 
GetGraphicStream(const::rtl::OUString & aName,rtl::OUString * pMediaType)1209 uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::rtl::OUString& aName, rtl::OUString* pMediaType )
1210 {
1211 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Name )" );
1212 
1213 	uno::Reference < io::XInputStream > xStream;
1214 
1215 	OSL_ENSURE( !aName.isEmpty(), "Retrieving graphic for unknown object!" );
1216 	if ( !aName.isEmpty() )
1217 	{
1218 		try
1219 		{
1220 			uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1221 			uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( aName, embed::ElementModes::READ );
1222 			xStream = xGraphicStream->getInputStream();
1223 			if ( pMediaType )
1224 			{
1225 				uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
1226 				if ( xSet.is() )
1227 				{
1228 					uno::Any aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("MediaType") );
1229 					aAny >>= *pMediaType;
1230 				}
1231 			}
1232 		}
1233 		catch ( uno::Exception& )
1234 		{
1235 		}
1236 	}
1237 
1238 	return xStream;
1239 }
1240 
GetGraphicStream(const::com::sun::star::uno::Reference<::com::sun::star::embed::XEmbeddedObject> & xObj,rtl::OUString * pMediaType)1241 uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj, rtl::OUString* pMediaType )
1242 {
1243 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Object )" );
1244 
1245 	// get the object name
1246 	::rtl::OUString aName;
1247 	EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin();
1248 	while ( aIt != pImpl->maObjectContainer.end() )
1249 	{
1250 		if ( (*aIt).second == xObj )
1251 		{
1252 			aName = (*aIt).first;
1253 			break;
1254 		}
1255 
1256 		aIt++;
1257 	}
1258 
1259 	// try to load it from the container storage
1260 	return GetGraphicStream( aName, pMediaType );
1261 }
1262 
InsertGraphicStream(const com::sun::star::uno::Reference<com::sun::star::io::XInputStream> & rStream,const::rtl::OUString & rObjectName,const rtl::OUString & rMediaType)1263 sal_Bool EmbeddedObjectContainer::InsertGraphicStream( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const ::rtl::OUString& rObjectName, const rtl::OUString& rMediaType )
1264 {
1265 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStream" );
1266 
1267 	try
1268 	{
1269 		uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1270 
1271 		// store it into the subfolder
1272 		uno::Reference < io::XOutputStream > xOutStream;
1273 		uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( rObjectName,
1274 				embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1275 		xOutStream = xGraphicStream->getOutputStream();
1276 		::comphelper::OStorageHelper::CopyInputToOutput( rStream, xOutStream );
1277 		xOutStream->flush();
1278 
1279 		uno::Reference< beans::XPropertySet > xPropSet( xGraphicStream, uno::UNO_QUERY );
1280 		if ( !xPropSet.is() )
1281 			throw uno::RuntimeException();
1282 
1283 		xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" ),
1284 									uno::makeAny( (sal_Bool)sal_True ) );
1285 		uno::Any aAny;
1286 		aAny <<= rMediaType;
1287 		xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny );
1288 
1289 		xPropSet->setPropertyValue( ::rtl::OUString::createFromAscii( "Compressed" ),
1290 									uno::makeAny( (sal_Bool)sal_True ) );
1291 	}
1292 	catch( uno::Exception& )
1293 	{
1294 		return sal_False;
1295 	}
1296 
1297 	return sal_True;
1298 }
1299 
InsertGraphicStreamDirectly(const com::sun::star::uno::Reference<com::sun::star::io::XInputStream> & rStream,const::rtl::OUString & rObjectName,const rtl::OUString & rMediaType)1300 sal_Bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const ::rtl::OUString& rObjectName, const rtl::OUString& rMediaType )
1301 {
1302 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStreamDirectly" );
1303 
1304 	try
1305 	{
1306 		uno::Reference < embed::XStorage > xReplacement = pImpl->GetReplacements();
1307 		uno::Reference < embed::XOptimizedStorage > xOptRepl( xReplacement, uno::UNO_QUERY_THROW );
1308 
1309 		// store it into the subfolder
1310 		uno::Sequence< beans::PropertyValue > aProps( 3 );
1311 		aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) );
1312 		aProps[0].Value <<= rMediaType;
1313 		aProps[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" ) );
1314 		aProps[1].Value <<= (sal_Bool)sal_True;
1315 		aProps[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) );
1316 		aProps[2].Value <<= (sal_Bool)sal_True;
1317 
1318 		if ( xReplacement->hasByName( rObjectName ) )
1319 			xReplacement->removeElement( rObjectName );
1320 
1321 		xOptRepl->insertStreamElementDirect( rObjectName, rStream, aProps );
1322 	}
1323 	catch( uno::Exception& )
1324 	{
1325 		return sal_False;
1326 	}
1327 
1328 	return sal_True;
1329 }
1330 
1331 
RemoveGraphicStream(const::rtl::OUString & rObjectName)1332 sal_Bool EmbeddedObjectContainer::RemoveGraphicStream( const ::rtl::OUString& rObjectName )
1333 {
1334 	RTL_LOGFILE_CONTEXT( aLog, "comphelper (mv76033) comphelper::EmbeddedObjectContainer::RemoveGraphicStream" );
1335 
1336 	try
1337 	{
1338 		uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements();
1339 		xReplacements->removeElement( rObjectName );
1340 	}
1341 	catch( uno::Exception& )
1342 	{
1343 		return sal_False;
1344 	}
1345 
1346 	return sal_True;
1347 }
1348 namespace {
InsertStreamIntoPicturesStorage_Impl(const uno::Reference<embed::XStorage> & xDocStor,const uno::Reference<io::XInputStream> & xInStream,const::rtl::OUString & aStreamName)1349 	void InsertStreamIntoPicturesStorage_Impl( const uno::Reference< embed::XStorage >& xDocStor,
1350 											const uno::Reference< io::XInputStream >& xInStream,
1351 											const ::rtl::OUString& aStreamName )
1352 	{
1353 		OSL_ENSURE( !aStreamName.isEmpty() && xInStream.is() && xDocStor.is(), "Misuse of the method!\n" );
1354 
1355 		try
1356 		{
1357 			uno::Reference< embed::XStorage > xPictures = xDocStor->openStorageElement(
1358 										::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pictures" ) ),
1359 										embed::ElementModes::READWRITE );
1360 			uno::Reference< io::XStream > xObjReplStr = xPictures->openStreamElement(
1361 										aStreamName,
1362 										embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1363 			uno::Reference< io::XOutputStream > xOutStream(
1364 										xObjReplStr->getInputStream(), uno::UNO_QUERY_THROW );
1365 
1366 			::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xOutStream );
1367 			xOutStream->closeOutput();
1368 
1369 			uno::Reference< embed::XTransactedObject > xTransact( xPictures, uno::UNO_QUERY );
1370 			if ( xTransact.is() )
1371 				xTransact->commit();
1372 		}
1373 		catch( uno::Exception& )
1374 		{
1375 			OSL_ENSURE( sal_False, "The pictures storage is not available!\n" );
1376 		}
1377 	}
1378 
1379 }
1380 // -----------------------------------------------------------------------------
StoreAsChildren(sal_Bool _bOasisFormat,sal_Bool _bCreateEmbedded,const uno::Reference<embed::XStorage> & _xStorage)1381 sal_Bool EmbeddedObjectContainer::StoreAsChildren(sal_Bool _bOasisFormat,sal_Bool _bCreateEmbedded,const uno::Reference < embed::XStorage >& _xStorage)
1382 {
1383 	sal_Bool bResult = sal_False;
1384 	try
1385 	{
1386 		comphelper::EmbeddedObjectContainer aCnt( _xStorage );
1387 		const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames();
1388 		const ::rtl::OUString* pIter = aNames.getConstArray();
1389 		const ::rtl::OUString* pEnd  = pIter + aNames.getLength();
1390 		for(;pIter != pEnd;++pIter)
1391 		{
1392 			uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1393 			OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
1394 			if ( xObj.is() )
1395 			{
1396 				sal_Bool bSwitchBackToLoaded = sal_False;
1397 				uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY );
1398 
1399 				uno::Reference < io::XInputStream > xStream;
1400 				::rtl::OUString aMediaType;
1401 
1402 				sal_Int32 nCurState = xObj->getCurrentState();
1403 				if ( nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING )
1404 				{
1405 					// means that the object is not active
1406 					// copy replacement image from old to new container
1407 					xStream = GetGraphicStream( xObj, &aMediaType );
1408 				}
1409 
1410 				if ( !xStream.is() && getUserAllowsLinkUpdate() )
1411 				{
1412 					// the image must be regenerated
1413 					// TODO/LATER: another aspect could be used
1414 					if ( xObj->getCurrentState() == embed::EmbedStates::LOADED )
1415 							bSwitchBackToLoaded = sal_True;
1416 
1417 					xStream = GetGraphicReplacementStream(
1418 															embed::Aspects::MSOLE_CONTENT,
1419 															xObj,
1420 															&aMediaType );
1421 				}
1422 
1423 				if ( _bOasisFormat || (xLink.is() && xLink->isLink()) )
1424 				{
1425 					if ( xStream.is() )
1426 					{
1427 						if ( _bOasisFormat )
1428 						{
1429 							// if it is an embedded object or the optimized inserting fails the normal inserting should be done
1430 							if ( _bCreateEmbedded
1431 								 || !aCnt.InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) )
1432 								 aCnt.InsertGraphicStream( xStream, *pIter, aMediaType );
1433 						}
1434 						else
1435 						{
1436 							// it is a linked object exported into SO7 format
1437 							InsertStreamIntoPicturesStorage_Impl( _xStorage, xStream, *pIter );
1438 						}
1439 					}
1440 				}
1441 
1442 				uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1443 				if ( xPersist.is() )
1444 				{
1445 					uno::Sequence< beans::PropertyValue > aArgs( _bOasisFormat ? 2 : 3 );
1446 					aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StoreVisualReplacement" ) );
1447 					aArgs[0].Value <<= (sal_Bool)( !_bOasisFormat );
1448 
1449 					// if it is an embedded object or the optimized inserting fails the normal inserting should be done
1450 					aArgs[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CanTryOptimization" ) );
1451 					aArgs[1].Value <<= !_bCreateEmbedded;
1452 					if ( !_bOasisFormat )
1453 					{
1454 						// if object has no cached replacement it will use this one
1455 						aArgs[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VisualReplacement" ) );
1456 						aArgs[2].Value <<= xStream;
1457 					}
1458 
1459 					xPersist->storeAsEntry( _xStorage,
1460 											xPersist->getEntryName(),
1461 											uno::Sequence< beans::PropertyValue >(),
1462 											aArgs );
1463 				}
1464 
1465 				if ( bSwitchBackToLoaded )
1466 					// switch back to loaded state; that way we have a minimum cache confusion
1467 					xObj->changeState( embed::EmbedStates::LOADED );
1468 			}
1469 		}
1470 
1471 		bResult = aCnt.CommitImageSubStorage();
1472 
1473 	}
1474 	catch ( uno::Exception& )
1475 	{
1476 		// TODO/LATER: error handling
1477 		bResult = sal_False;
1478 	}
1479 
1480 	// the old SO6 format does not store graphical replacements
1481 	if ( !_bOasisFormat && bResult )
1482 	{
1483 		try
1484 		{
1485 			// the substorage still can not be locked by the embedded object conteiner
1486 			::rtl::OUString aObjReplElement( RTL_CONSTASCII_USTRINGPARAM( "ObjectReplacements" ) );
1487 			if ( _xStorage->hasByName( aObjReplElement ) && _xStorage->isStorageElement( aObjReplElement ) )
1488 				_xStorage->removeElement( aObjReplElement );
1489 		}
1490 		catch ( uno::Exception& )
1491 		{
1492 			// TODO/LATER: error handling;
1493 			bResult = sal_False;
1494 		}
1495 	}
1496 	return bResult;
1497 }
1498 // -----------------------------------------------------------------------------
StoreChildren(sal_Bool _bOasisFormat,sal_Bool _bObjectsOnly)1499 sal_Bool EmbeddedObjectContainer::StoreChildren(sal_Bool _bOasisFormat,sal_Bool _bObjectsOnly)
1500 {
1501 	sal_Bool bResult = sal_True;
1502 	const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames();
1503 	const ::rtl::OUString* pIter = aNames.getConstArray();
1504 	const ::rtl::OUString* pEnd  = pIter + aNames.getLength();
1505 	for(;pIter != pEnd;++pIter)
1506 	{
1507 		uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1508 		OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
1509 		if ( xObj.is() )
1510 		{
1511 			sal_Int32 nCurState = xObj->getCurrentState();
1512 			if ( _bOasisFormat && nCurState != embed::EmbedStates::LOADED && nCurState != embed::EmbedStates::RUNNING )
1513 			{
1514 				// means that the object is active
1515 				// the image must be regenerated
1516 				::rtl::OUString aMediaType;
1517 
1518 				// TODO/LATER: another aspect could be used
1519 				uno::Reference < io::XInputStream > xStream =
1520 							GetGraphicReplacementStream(
1521 														embed::Aspects::MSOLE_CONTENT,
1522 														xObj,
1523 														&aMediaType );
1524 				if ( xStream.is() )
1525 				{
1526 					if ( !InsertGraphicStreamDirectly( xStream, *pIter, aMediaType ) )
1527 						InsertGraphicStream( xStream, *pIter, aMediaType );
1528 				}
1529 			}
1530 
1531 			// TODO/LATER: currently the object by default does not cache replacement image
1532 			// that means that if somebody loads SO7 document and store its objects using
1533 			// this method the images might be lost.
1534 			// Currently this method is only used on storing to alien formats, that means
1535 			// that SO7 documents storing does not use it, and all other filters are
1536 			// based on OASIS format. But if it changes the method must be fixed. The fix
1537 			// must be done only on demand since it can affect performance.
1538 
1539 			uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1540 			if ( xPersist.is() )
1541 			{
1542 				try
1543 				{
1544 					// TODO/LATER: only storing if changed!
1545 					//xPersist->storeOwn();	//commented, i120168
1546 
1547 					// begin:all charts will be persisted as xml format on disk when saving, which is time consuming.
1548 					// '_bObjectsOnly' mean we are storing to alien formats.
1549 					//  'isStorageElement' mean current object is NOT an MS OLE format. (may also include in future), i120168
1550 					if (_bObjectsOnly && (nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING)
1551 						&& (pImpl->mxStorage->isStorageElement( *pIter ) ))
1552 					{
1553 						uno::Reference< util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY );
1554 						if ( xModifiable.is() && xModifiable->isModified())
1555 						{
1556 							xPersist->storeOwn();
1557 						}
1558 						else
1559 						{
1560 							// do nothing. Embedded model is not modified, no need to persist.
1561 						}
1562 					}
1563 					else // the embedded object is in active status, always store back it.
1564 					{
1565 						xPersist->storeOwn();
1566 					}
1567 					// end i120168
1568 				}
1569 				catch( uno::Exception& )
1570 				{
1571 					// TODO/LATER: error handling
1572 					bResult = sal_False;
1573 					break;
1574 				}
1575 			}
1576 
1577 			if ( !_bOasisFormat && !_bObjectsOnly )
1578 			{
1579 				// copy replacement images for linked objects
1580 				try
1581 				{
1582 					uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY );
1583 					if ( xLink.is() && xLink->isLink() )
1584 					{
1585 						::rtl::OUString aMediaType;
1586 						uno::Reference < io::XInputStream > xInStream = GetGraphicStream( xObj, &aMediaType );
1587 						if ( xInStream.is() )
1588 							InsertStreamIntoPicturesStorage_Impl( pImpl->mxStorage, xInStream, *pIter );
1589 					}
1590 				}
1591 				catch( uno::Exception& )
1592 				{
1593 				}
1594 			}
1595 		}
1596 	}
1597 
1598 	if ( bResult && _bOasisFormat )
1599 		bResult = CommitImageSubStorage();
1600 
1601 	if ( bResult && !_bObjectsOnly )
1602 	{
1603 		try
1604 		{
1605 			ReleaseImageSubStorage();
1606 			::rtl::OUString aObjReplElement( RTL_CONSTASCII_USTRINGPARAM( "ObjectReplacements" ) );
1607 			if ( !_bOasisFormat && pImpl->mxStorage->hasByName( aObjReplElement ) && pImpl->mxStorage->isStorageElement( aObjReplElement ) )
1608 				pImpl->mxStorage->removeElement( aObjReplElement );
1609 		}
1610 		catch( uno::Exception& )
1611 		{
1612 			// TODO/LATER: error handling
1613 			bResult = sal_False;
1614 		}
1615 	}
1616 	return bResult;
1617 }
1618 // -----------------------------------------------------------------------------
GetGraphicReplacementStream(sal_Int64 nViewAspect,const uno::Reference<embed::XEmbeddedObject> & xObj,::rtl::OUString * pMediaType)1619 uno::Reference< io::XInputStream > EmbeddedObjectContainer::GetGraphicReplacementStream(
1620 																sal_Int64 nViewAspect,
1621 																const uno::Reference< embed::XEmbeddedObject >& xObj,
1622 																::rtl::OUString* pMediaType )
1623 {
1624 	uno::Reference< io::XInputStream > xInStream;
1625 	if ( xObj.is() )
1626 	{
1627 		try
1628 		{
1629 			// retrieving of the visual representation can switch object to running state
1630 			embed::VisualRepresentation aRep = xObj->getPreferredVisualRepresentation( nViewAspect );
1631 			if ( pMediaType )
1632 				*pMediaType = aRep.Flavor.MimeType;
1633 
1634 			uno::Sequence < sal_Int8 > aSeq;
1635 			aRep.Data >>= aSeq;
1636 			xInStream = new ::comphelper::SequenceInputStream( aSeq );
1637 		}
1638 		catch ( uno::Exception& )
1639 		{
1640 		}
1641 	}
1642 
1643 	return xInStream;
1644 }
1645 // -----------------------------------------------------------------------------
SetPersistentEntries(const uno::Reference<embed::XStorage> & _xStorage,bool _bClearModifedFlag)1646 sal_Bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference< embed::XStorage >& _xStorage,bool _bClearModifedFlag)
1647 {
1648 	sal_Bool bError = sal_False;
1649 	const uno::Sequence < ::rtl::OUString > aNames = GetObjectNames();
1650 	const ::rtl::OUString* pIter = aNames.getConstArray();
1651 	const ::rtl::OUString* pEnd  = pIter + aNames.getLength();
1652 	for(;pIter != pEnd;++pIter)
1653 	{
1654 		uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( *pIter );
1655 		OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" );
1656 		if ( xObj.is() )
1657 		{
1658 			uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY );
1659 			if ( xPersist.is() )
1660 			{
1661 				try
1662 				{
1663 					xPersist->setPersistentEntry( _xStorage,
1664 												*pIter,
1665 												embed::EntryInitModes::NO_INIT,
1666 												uno::Sequence< beans::PropertyValue >(),
1667 												uno::Sequence< beans::PropertyValue >() );
1668 
1669 				}
1670 				catch( uno::Exception& )
1671 				{
1672 					// TODO/LATER: error handling
1673 					bError = sal_True;
1674 					break;
1675 				}
1676 			}
1677 			if ( _bClearModifedFlag )
1678 			{
1679 				// if this method is used as part of SaveCompleted the object must stay unmodified after execution
1680 				try
1681 				{
1682 					uno::Reference< util::XModifiable > xModif( xObj->getComponent(), uno::UNO_QUERY_THROW );
1683 					if ( xModif->isModified() )
1684 						xModif->setModified( sal_False );
1685 				}
1686 				catch( uno::Exception& )
1687 				{
1688 				}
1689 			}
1690 		}
1691 	}
1692 	return bError;
1693 }
1694 
getUserAllowsLinkUpdate() const1695 bool EmbeddedObjectContainer::getUserAllowsLinkUpdate() const
1696 {
1697 	return pImpl->mbUserAllowsLinkUpdate;
1698 }
1699 
setUserAllowsLinkUpdate(bool bNew)1700 void EmbeddedObjectContainer::setUserAllowsLinkUpdate(bool bNew)
1701 {
1702 	if(pImpl->mbUserAllowsLinkUpdate != bNew)
1703 	{
1704 		pImpl->mbUserAllowsLinkUpdate = bNew;
1705 	}
1706 }
1707 
1708 }
1709