xref: /aoo42x/main/svx/source/xml/xmleohlp.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 
31 #include <stdio.h>
32 #include <com/sun/star/io/XStream.hpp>
33 #include <com/sun/star/embed/XTransactedObject.hpp>
34 #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
35 #include <com/sun/star/embed/XEmbedObjectFactory.hpp>
36 #include <com/sun/star/embed/ElementModes.hpp>
37 #include <com/sun/star/embed/XEmbeddedObject.hpp>
38 #ifndef _COM_SUN_STAR_EMBED_XEMBED_PERSIST_HPP_
39 #include <com/sun/star/embed/XEmbedPersist.hpp>
40 #endif
41 #include <com/sun/star/embed/EntryInitModes.hpp>
42 #include <com/sun/star/embed/EmbedStates.hpp>
43 #include <com/sun/star/embed/Aspects.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <tools/debug.hxx>
46 #include <unotools/streamwrap.hxx>
47 #include <unotools/tempfile.hxx>
48 
49 #include <svtools/embedhlp.hxx>
50 #include <unotools/ucbstreamhelper.hxx>
51 #include <comphelper/processfactory.hxx>
52 #include <comphelper/storagehelper.hxx>
53 #include <comphelper/embeddedobjectcontainer.hxx>
54 
55 #ifndef _SO_CLSIDS_HXX
56 #include <sot/clsids.hxx>
57 #endif
58 #include <map>
59 #include "svx/xmleohlp.hxx"
60 
61 // -----------
62 // - Defines -
63 // -----------
64 
65 using namespace ::osl;
66 using namespace ::cppu;
67 using namespace ::utl;
68 using namespace ::com::sun::star;
69 using namespace ::com::sun::star::document;
70 using namespace ::com::sun::star::uno;
71 using namespace ::com::sun::star::container;
72 using namespace ::com::sun::star::io;
73 using namespace ::com::sun::star::lang;
74 
75 #define XML_CONTAINERSTORAGE_NAME_60		"Pictures"
76 #define XML_CONTAINERSTORAGE_NAME		"ObjectReplacements"
77 #define XML_EMBEDDEDOBJECT_URL_BASE		"vnd.sun.star.EmbeddedObject:"
78 #define XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE		"vnd.sun.star.GraphicObject:"
79 
80 // -----------------------------------------------------------------------------
81 
82 // -----------------------------------------------------------------------------
83 
84 class OutputStorageWrapper_Impl : public ::cppu::WeakImplHelper1<XOutputStream>
85 {
86 	::osl::Mutex	maMutex;
87 	Reference < XOutputStream > xOut;
88 	TempFile aTempFile;
89 	sal_Bool bStreamClosed : 1;
90     SvStream* pStream;
91 
92 public:
93 	OutputStorageWrapper_Impl();
94 	virtual ~OutputStorageWrapper_Impl();
95 
96 // stario::XOutputStream
97 	virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) throw(NotConnectedException, BufferSizeExceededException, RuntimeException);
98 	virtual void SAL_CALL flush() throw(NotConnectedException, BufferSizeExceededException, RuntimeException);
99 	virtual void SAL_CALL closeOutput() throw(NotConnectedException, BufferSizeExceededException, RuntimeException);
100 
101     SvStream*   GetStream();
102 };
103 
104 OutputStorageWrapper_Impl::OutputStorageWrapper_Impl()
105     : bStreamClosed( sal_False )
106     , pStream(0)
107 {
108 	aTempFile.EnableKillingFile();
109     pStream = aTempFile.GetStream( STREAM_READWRITE );
110 	xOut = new OOutputStreamWrapper( *pStream );
111 }
112 
113 OutputStorageWrapper_Impl::~OutputStorageWrapper_Impl()
114 {
115 }
116 
117 SvStream *OutputStorageWrapper_Impl::GetStream()
118 {
119     if( bStreamClosed )
120         return pStream;
121     return NULL;
122 }
123 
124 void SAL_CALL OutputStorageWrapper_Impl::writeBytes(
125 		const Sequence< sal_Int8 >& aData)
126 	throw(NotConnectedException, BufferSizeExceededException, RuntimeException)
127 {
128 	MutexGuard			aGuard( maMutex );
129 	xOut->writeBytes( aData );
130 }
131 
132 void SAL_CALL OutputStorageWrapper_Impl::flush()
133 	throw(NotConnectedException, BufferSizeExceededException, RuntimeException)
134 {
135 	MutexGuard			aGuard( maMutex );
136 	xOut->flush();
137 }
138 
139 void SAL_CALL OutputStorageWrapper_Impl::closeOutput()
140 	throw(NotConnectedException, BufferSizeExceededException, RuntimeException)
141 {
142 	MutexGuard			aGuard( maMutex );
143 	xOut->closeOutput();
144 	bStreamClosed = sal_True;
145 }
146 
147 // -----------------------------------------------------------------------------
148 
149 struct OUStringLess
150 {
151 	bool operator() ( const ::rtl::OUString& r1, const ::rtl::OUString& r2 ) const
152 	{
153 		return (r1 < r2) != sal_False;
154 	}
155 };
156 
157 // -----------------------------------------------------------------------------
158 
159 // -----------------------------
160 // - SvXMLEmbeddedObjectHelper -
161 // -----------------------------
162 DBG_NAME(SvXMLEmbeddedObjectHelper)
163 SvXMLEmbeddedObjectHelper::SvXMLEmbeddedObjectHelper() :
164 	WeakComponentImplHelper2< XEmbeddedObjectResolver, XNameAccess >( maMutex ),
165 	maReplacementGraphicsContainerStorageName( RTL_CONSTASCII_USTRINGPARAM(XML_CONTAINERSTORAGE_NAME) ),
166 	maReplacementGraphicsContainerStorageName60( RTL_CONSTASCII_USTRINGPARAM(XML_CONTAINERSTORAGE_NAME_60) ),
167 	mpDocPersist( 0 ),
168 	meCreateMode( EMBEDDEDOBJECTHELPER_MODE_READ ),
169 	mpStreamMap( 0 )
170 {
171     DBG_CTOR(SvXMLEmbeddedObjectHelper,NULL);
172 }
173 
174 SvXMLEmbeddedObjectHelper::SvXMLEmbeddedObjectHelper( ::comphelper::IEmbeddedHelper& rDocPersist, SvXMLEmbeddedObjectHelperMode eCreateMode ) :
175 	WeakComponentImplHelper2< XEmbeddedObjectResolver, XNameAccess >( maMutex ),
176 	maReplacementGraphicsContainerStorageName( RTL_CONSTASCII_USTRINGPARAM(XML_CONTAINERSTORAGE_NAME) ),
177 	maReplacementGraphicsContainerStorageName60( RTL_CONSTASCII_USTRINGPARAM(XML_CONTAINERSTORAGE_NAME_60) ),
178 	mpDocPersist( 0 ),
179 	meCreateMode( EMBEDDEDOBJECTHELPER_MODE_READ ),
180 	mpStreamMap( 0 )
181 {
182     DBG_CTOR(SvXMLEmbeddedObjectHelper,NULL);
183 	Init( 0, rDocPersist, eCreateMode );
184 }
185 
186 
187 // -----------------------------------------------------------------------------
188 
189 SvXMLEmbeddedObjectHelper::~SvXMLEmbeddedObjectHelper()
190 {
191     DBG_DTOR(SvXMLEmbeddedObjectHelper,NULL);
192 	if( mpStreamMap )
193 	{
194 		SvXMLEmbeddedObjectHelper_Impl::iterator aIter = mpStreamMap->begin();
195 		SvXMLEmbeddedObjectHelper_Impl::iterator aEnd = mpStreamMap->end();
196 		for( ; aIter != aEnd; aIter++ )
197 		{
198 			if( aIter->second )
199 			{
200 				aIter->second->release();
201 				aIter->second = 0;
202 			}
203 		}
204 	}
205 }
206 
207 // -----------------------------------------------------------------------------
208 
209 void SAL_CALL SvXMLEmbeddedObjectHelper::disposing()
210 {
211 	Flush();
212 }
213 
214 // -----------------------------------------------------------------------------
215 
216 sal_Bool SvXMLEmbeddedObjectHelper::ImplGetStorageNames(
217 		const ::rtl::OUString& rURLStr,
218 		::rtl::OUString& rContainerStorageName,
219 		::rtl::OUString& rObjectStorageName,
220 		sal_Bool bInternalToExternal,
221 	    sal_Bool *pGraphicRepl,
222 		sal_Bool *pOasisFormat ) const
223 {
224 	// internal URL: vnd.sun.star.EmbeddedObject:<object-name>
225 	// 			 or: vnd.sun.star.EmbeddedObject:<path>/<object-name>
226 	// internal replacement images:
227 	//				 vnd.sun.star.EmbeddedObjectGraphic:<object-name>
228 	// 			 or: vnd.sun.star.EmbeddedObjectGraphic:<path>/<object-name>
229 	// external URL: ./<path>/<object-name>
230 	// 			 or: <path>/<object-name>
231 	// 			 or: <object-name>
232 	// currently, path may only consist of a single directory name
233 	// it is also possible to have additional arguments at the end of URL: <main URL>[?<name>=<value>[,<name>=<value>]*]
234 
235 	if( pGraphicRepl )
236 		*pGraphicRepl = sal_False;
237 
238 	if( pOasisFormat )
239 		*pOasisFormat = sal_True; // the default value
240 
241 	if( !rURLStr.getLength() )
242 		return sal_False;
243 
244 	// get rid of arguments
245 	sal_Int32 nPos = rURLStr.indexOf( '?' );
246 	::rtl::OUString aURLNoPar;
247 	if ( nPos == -1 )
248 		aURLNoPar = rURLStr;
249 	else
250 	{
251 		aURLNoPar = rURLStr.copy( 0, nPos );
252 
253 		// check the arguments
254 		nPos++;
255 		while( nPos >= 0 && nPos < rURLStr.getLength() )
256 		{
257 			::rtl::OUString aToken = rURLStr.getToken( 0, ',', nPos );
258 			if ( aToken.equalsIgnoreAsciiCase( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "oasis=false" ) ) ) )
259 			{
260 				if ( pOasisFormat )
261 					*pOasisFormat = sal_False;
262 				break;
263 			}
264 			else
265 			{
266 				DBG_ASSERT( sal_False, "invalid arguments was found in URL!" );
267 			}
268 		}
269 	}
270 
271 	if( bInternalToExternal )
272 	{
273 		nPos = aURLNoPar.indexOf( ':' );
274 		if( -1 == nPos )
275 			return sal_False;
276 		sal_Bool bObjUrl =
277 			0 == aURLNoPar.compareToAscii( XML_EMBEDDEDOBJECT_URL_BASE,
278 								 sizeof( XML_EMBEDDEDOBJECT_URL_BASE ) -1 );
279 		sal_Bool bGrUrl = !bObjUrl &&
280 		  	0 == aURLNoPar.compareToAscii( XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE,
281 						 sizeof( XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE ) -1 );
282 		if( !(bObjUrl || bGrUrl) )
283 			return sal_False;
284 
285 		sal_Int32 nPathStart = nPos + 1;
286 		nPos = aURLNoPar.lastIndexOf( '/' );
287 		if( -1 == nPos )
288 		{
289 			rContainerStorageName = ::rtl::OUString();
290 			rObjectStorageName = aURLNoPar.copy( nPathStart );
291 		}
292 		else if( nPos > nPathStart )
293 		{
294 			rContainerStorageName = aURLNoPar.copy( nPathStart, nPos-nPathStart);
295 			rObjectStorageName = aURLNoPar.copy( nPos+1 );
296 		}
297 		else
298 			return sal_False;
299 
300 		if( bGrUrl )
301 		{
302 			sal_Bool bOASIS = mxRootStorage.is() &&
303 				( SotStorage::GetVersion( mxRootStorage ) > SOFFICE_FILEFORMAT_60 );
304 			rContainerStorageName = bOASIS
305 					? maReplacementGraphicsContainerStorageName
306 					: maReplacementGraphicsContainerStorageName60;
307 
308 			if( pGraphicRepl )
309 				*pGraphicRepl = sal_True;
310 		}
311 
312 
313 	}
314 	else
315 	{
316 		DBG_ASSERT( '#' != aURLNoPar[0], "invalid object URL" );
317 
318 		sal_Int32 _nPos = aURLNoPar.lastIndexOf( '/' );
319 		if( -1 == _nPos )
320 		{
321 			rContainerStorageName = ::rtl::OUString();
322 			rObjectStorageName = aURLNoPar;
323 		}
324 		else
325 		{
326             //eliminate 'superfluous' slashes at start and end
327             //#i103076# load objects with all allowed xlink:href syntaxes
328             {
329                 //eliminate './' at start
330 			    sal_Int32 nStart = 0;
331                 sal_Int32 nCount = aURLNoPar.getLength();
332 			    if( 0 == aURLNoPar.compareToAscii( "./", 2 ) )
333                 {
334 				    nStart = 2;
335                     nCount -= 2;
336                 }
337 
338                 //eliminate '/' at end
339                 sal_Int32 nEnd = aURLNoPar.lastIndexOf( '/' );
340                 if( nEnd == aURLNoPar.getLength()-1 && nEnd != (nStart-1) )
341                     nCount--;
342 
343                 aURLNoPar = aURLNoPar.copy( nStart, nCount );
344             }
345 
346             _nPos = aURLNoPar.lastIndexOf( '/' );
347             if( _nPos >= 0 )
348 				rContainerStorageName = aURLNoPar.copy( 0, _nPos );
349 			rObjectStorageName = aURLNoPar.copy( _nPos+1 );
350 		}
351 	}
352 
353 	if( -1 != rContainerStorageName.indexOf( '/' ) )
354 	{
355 		DBG_ERROR( "SvXMLEmbeddedObjectHelper: invalid path name" );
356 		return sal_False;
357 	}
358 
359 	return sal_True;
360 }
361 
362 
363 // -----------------------------------------------------------------------------
364 
365 uno::Reference < embed::XStorage > SvXMLEmbeddedObjectHelper::ImplGetContainerStorage(
366 		const ::rtl::OUString& rStorageName )
367 {
368 	DBG_ASSERT( -1 == rStorageName.indexOf( '/' ) &&
369 				-1 == rStorageName.indexOf( '\\' ),
370 				"nested embedded storages aren't supported" );
371     if( !mxContainerStorage.is() ||
372 		( rStorageName != maCurContainerStorageName ) )
373 	{
374         if( mxContainerStorage.is() &&
375 			maCurContainerStorageName.getLength() > 0 &&
376 			EMBEDDEDOBJECTHELPER_MODE_WRITE == meCreateMode )
377         {
378             uno::Reference < embed::XTransactedObject > xTrans( mxContainerStorage, uno::UNO_QUERY );
379             if ( xTrans.is() )
380                 xTrans->commit();
381         }
382 
383         if( rStorageName.getLength() > 0 && mxRootStorage.is() )
384 		{
385             sal_Int32 nMode = EMBEDDEDOBJECTHELPER_MODE_WRITE == meCreateMode
386                                     ? ::embed::ElementModes::READWRITE
387                                     : ::embed::ElementModes::READ;
388             mxContainerStorage = mxRootStorage->openStorageElement( rStorageName,
389                                                              nMode );
390 		}
391 		else
392 		{
393             mxContainerStorage = mxRootStorage;
394 		}
395 		maCurContainerStorageName = rStorageName;
396 	}
397 
398 	return mxContainerStorage;
399 }
400 
401 // -----------------------------------------------------------------------------
402 
403 sal_Bool SvXMLEmbeddedObjectHelper::ImplReadObject(
404 		const ::rtl::OUString& rContainerStorageName,
405 		::rtl::OUString& rObjName,
406 	    const SvGlobalName *pClassId,
407         SvStream* pTemp )
408 {
409 	(void)pClassId;
410 
411     uno::Reference < embed::XStorage > xDocStor( mpDocPersist->getStorage() );
412     uno::Reference < embed::XStorage > xCntnrStor( ImplGetContainerStorage( rContainerStorageName ) );
413 
414     if( !xCntnrStor.is() && !pTemp )
415 		return sal_False;
416 
417 	String aSrcObjName( rObjName );
418     comphelper::EmbeddedObjectContainer& rContainer = mpDocPersist->getEmbeddedObjectContainer();
419 
420 	// Is the object name unique?
421 	// if the object is already instantiated by GetEmbeddedObject
422     // that means that the duplication is being loaded
423     sal_Bool bDuplicate = rContainer.HasInstantiatedEmbeddedObject( rObjName );
424 	DBG_ASSERT( !bDuplicate, "An object in the document is referenced twice!" );
425 
426     if( xDocStor != xCntnrStor || pTemp || bDuplicate )
427 	{
428         // TODO/LATER: make this alltogether a method in the EmbeddedObjectContainer
429 
430 		// create a unique name for the duplicate object
431         if( bDuplicate )
432             rObjName = rContainer.CreateUniqueObjectName();
433 
434 		if( pTemp )
435 		{
436             try
437             {
438 				pTemp->Seek( 0 );
439                 uno::Reference < io::XStream > xStm = xDocStor->openStreamElement( rObjName,
440                         embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
441                 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( xStm );
442                 *pTemp >> *pStream;
443                 delete pStream;
444 
445 				// TODO/LATER: what to do when other types of objects are based on substream persistence?
446 				// This is an ole object
447 				uno::Reference< beans::XPropertySet > xProps( xStm, uno::UNO_QUERY_THROW );
448 				xProps->setPropertyValue(
449 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ),
450 					uno::makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.oleobject" ) ) ) );
451 
452                 xStm->getOutputStream()->closeOutput();
453             }
454             catch ( uno::Exception& )
455             {
456                 return sal_False;
457             }
458 		}
459 		else
460 		{
461             try
462             {
463                 xCntnrStor->copyElementTo( aSrcObjName, xDocStor, rObjName );
464             }
465             catch ( uno::Exception& )
466             {
467                 return sal_False;
468             }
469 		}
470 	}
471 
472     // make object known to the container
473     // TODO/LATER: could be done a little bit more efficient!
474     ::rtl::OUString aName( rObjName );
475 
476 	// TODO/LATER: The provided pClassId is ignored for now.
477 	//             The stream contains OLE storage internally and this storage already has a class id specifying the
478 	//             server that was used to create the object. pClassId could be used to specify the server that should
479 	//             be used for the next opening, but this information seems to be out of the file format responsibility
480 	//             area.
481 	rContainer.GetEmbeddedObject( aName );
482 
483 	return sal_True;
484 }
485 
486 // -----------------------------------------------------------------------------
487 
488 ::rtl::OUString SvXMLEmbeddedObjectHelper::ImplInsertEmbeddedObjectURL(
489 		const ::rtl::OUString& rURLStr )
490 {
491 	::rtl::OUString sRetURL;
492 
493 	::rtl::OUString	aContainerStorageName, aObjectStorageName;
494 	if( !ImplGetStorageNames( rURLStr, aContainerStorageName,
495 							  aObjectStorageName,
496 							  EMBEDDEDOBJECTHELPER_MODE_WRITE == meCreateMode ) )
497 		return sRetURL;
498 
499 	if( EMBEDDEDOBJECTHELPER_MODE_READ == meCreateMode )
500 	{
501 		OutputStorageWrapper_Impl *pOut = 0;
502 		SvXMLEmbeddedObjectHelper_Impl::iterator aIter;
503 
504 		if( mpStreamMap )
505 		{
506 			aIter = mpStreamMap->find( rURLStr );
507 			if( aIter != mpStreamMap->end() && aIter->second )
508 				pOut = aIter->second;
509 		}
510 
511 		SvGlobalName aClassId, *pClassId = 0;
512 		sal_Int32 nPos = aObjectStorageName.lastIndexOf( '!' );
513 		if( -1 != nPos && aClassId.MakeId( aObjectStorageName.copy( nPos+1 ) ) )
514 		{
515 			aObjectStorageName = aObjectStorageName.copy( 0, nPos );
516 			pClassId = &aClassId;
517 		}
518 
519         ImplReadObject( aContainerStorageName, aObjectStorageName, pClassId, pOut ? pOut->GetStream() : 0 );
520         sRetURL = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(XML_EMBEDDEDOBJECT_URL_BASE) );
521 		sRetURL += aObjectStorageName;
522 
523 		if( pOut )
524 		{
525 			mpStreamMap->erase( aIter );
526 			pOut->release();
527 		}
528 	}
529 	else
530 	{
531 		// Objects are written using ::comphelper::IEmbeddedHelper::SaveAs
532 		sRetURL = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("./") );
533 		if( aContainerStorageName.getLength() )
534 		{
535 			sRetURL += aContainerStorageName;
536 			sRetURL += ::rtl::OUString( '/' );
537 		}
538 		sRetURL += aObjectStorageName;
539 	}
540 
541 	return sRetURL;
542 }
543 
544 // -----------------------------------------------------------------------------
545 
546 uno::Reference< io::XInputStream > SvXMLEmbeddedObjectHelper::ImplGetReplacementImage(
547 											const uno::Reference< embed::XEmbeddedObject >& xObj )
548 {
549 	uno::Reference< io::XInputStream > xStream;
550 
551 	if( xObj.is() )
552 	{
553 		try
554 		{
555 			sal_Bool bSwitchBackToLoaded = sal_False;
556 			sal_Int32 nCurState = xObj->getCurrentState();
557 			if ( nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING )
558 			{
559 				// means that the object is not active
560 				// copy replacement image from old to new container
561 				::rtl::OUString aMediaType;
562 				xStream = mpDocPersist->getEmbeddedObjectContainer().GetGraphicStream( xObj, &aMediaType );
563 			}
564 
565 			if ( !xStream.is() )
566 			{
567 				// the image must be regenerated
568 				// TODO/LATER: another aspect could be used
569 				if ( nCurState == embed::EmbedStates::LOADED )
570 					bSwitchBackToLoaded = sal_True;
571 
572 				::rtl::OUString aMediaType;
573 				xStream = svt::EmbeddedObjectRef::GetGraphicReplacementStream(
574 													embed::Aspects::MSOLE_CONTENT,
575 													xObj,
576 													&aMediaType );
577 			}
578 
579 			if ( bSwitchBackToLoaded )
580 				// switch back to loaded state; that way we have a minimum cache confusion
581 				xObj->changeState( embed::EmbedStates::LOADED );
582 		}
583 		catch( uno::Exception& )
584 		{}
585 	}
586 
587 	return xStream;
588 }
589 
590 // -----------------------------------------------------------------------------
591 
592 void SvXMLEmbeddedObjectHelper::Init(
593         const uno::Reference < embed::XStorage >& rRootStorage,
594         ::comphelper::IEmbeddedHelper& rPersist,
595 		SvXMLEmbeddedObjectHelperMode eCreateMode )
596 {
597     mxRootStorage = rRootStorage;
598 	mpDocPersist = &rPersist;
599 	meCreateMode = eCreateMode;
600 }
601 
602 // -----------------------------------------------------------------------------
603 
604 SvXMLEmbeddedObjectHelper* SvXMLEmbeddedObjectHelper::Create(
605         const uno::Reference < embed::XStorage >& rRootStorage,
606         ::comphelper::IEmbeddedHelper& rDocPersist,
607 		SvXMLEmbeddedObjectHelperMode eCreateMode,
608 		sal_Bool bDirect )
609 {
610 	(void)bDirect;
611 
612 	SvXMLEmbeddedObjectHelper* pThis = new SvXMLEmbeddedObjectHelper;
613 
614 	pThis->acquire();
615     pThis->Init( rRootStorage, rDocPersist, eCreateMode );
616 
617 	return pThis;
618 }
619 
620 SvXMLEmbeddedObjectHelper* SvXMLEmbeddedObjectHelper::Create(
621         ::comphelper::IEmbeddedHelper& rDocPersist,
622 		SvXMLEmbeddedObjectHelperMode eCreateMode )
623 {
624 	SvXMLEmbeddedObjectHelper* pThis = new SvXMLEmbeddedObjectHelper;
625 
626 	pThis->acquire();
627 	pThis->Init( 0, rDocPersist, eCreateMode );
628 
629 	return pThis;
630 }
631 
632 // -----------------------------------------------------------------------------
633 
634 void SvXMLEmbeddedObjectHelper::Destroy(
635 		SvXMLEmbeddedObjectHelper* pSvXMLEmbeddedObjectHelper )
636 {
637 	if( pSvXMLEmbeddedObjectHelper )
638 	{
639 		pSvXMLEmbeddedObjectHelper->dispose();
640 		pSvXMLEmbeddedObjectHelper->release();
641 	}
642 }
643 
644 // -----------------------------------------------------------------------------
645 
646 void SvXMLEmbeddedObjectHelper::Flush()
647 {
648 	if( mxTempStorage.is() )
649 	{
650 		Reference < XComponent > xComp( mxTempStorage, UNO_QUERY );
651 		xComp->dispose();
652 	}
653 }
654 
655 // XGraphicObjectResolver: alien objects!
656 ::rtl::OUString SAL_CALL SvXMLEmbeddedObjectHelper::resolveEmbeddedObjectURL( const ::rtl::OUString& aURL )
657 	throw(RuntimeException)
658 {
659 	MutexGuard			aGuard( maMutex );
660 
661 	return ImplInsertEmbeddedObjectURL( aURL );
662 }
663 
664 // XNameAccess: alien objects!
665 Any SAL_CALL SvXMLEmbeddedObjectHelper::getByName(
666 		const ::rtl::OUString& rURLStr )
667 	throw (NoSuchElementException, WrappedTargetException, RuntimeException)
668 {
669 	MutexGuard			aGuard( maMutex );
670 	Any aRet;
671 	if( EMBEDDEDOBJECTHELPER_MODE_READ == meCreateMode )
672 	{
673 		Reference < XOutputStream > xStrm;
674 		if( mpStreamMap )
675 		{
676 			SvXMLEmbeddedObjectHelper_Impl::iterator aIter =
677 				mpStreamMap->find( rURLStr );
678 			if( aIter != mpStreamMap->end() && aIter->second )
679 				xStrm = aIter->second;
680 		}
681 		if( !xStrm.is() )
682 		{
683 			OutputStorageWrapper_Impl *pOut = new OutputStorageWrapper_Impl;
684 			pOut->acquire();
685 			if( !mpStreamMap )
686 				mpStreamMap = new SvXMLEmbeddedObjectHelper_Impl;
687 			(*mpStreamMap)[rURLStr] = pOut;
688 			xStrm = pOut;
689 		}
690 
691 		aRet <<= xStrm;
692 	}
693 	else
694 	{
695 		sal_Bool bGraphicRepl = sal_False;
696 		sal_Bool bOasisFormat = sal_True;
697 		Reference < XInputStream > xStrm;
698 		::rtl::OUString aContainerStorageName, aObjectStorageName;
699 		if( ImplGetStorageNames( rURLStr, aContainerStorageName,
700 								 aObjectStorageName,
701 								 sal_True,
702 				   				 &bGraphicRepl,
703 								 &bOasisFormat ) )
704 		{
705             try
706             {
707 				comphelper::EmbeddedObjectContainer& rContainer =
708 						mpDocPersist->getEmbeddedObjectContainer();
709 
710     			Reference < embed::XEmbeddedObject > xObj = rContainer.GetEmbeddedObject( aObjectStorageName );
711 				DBG_ASSERT( xObj.is(), "Didn't get object" );
712 
713 				if( xObj.is() )
714 				{
715 					if( bGraphicRepl )
716 					{
717 						xStrm = ImplGetReplacementImage( xObj );
718 					}
719 					else
720 					{
721 						Reference < embed::XEmbedPersist > xPersist( xObj, UNO_QUERY );
722 						if( xPersist.is() )
723 						{
724 							if( !mxTempStorage.is() )
725 								mxTempStorage =
726 									comphelper::OStorageHelper::GetTemporaryStorage();
727 							Sequence < beans::PropertyValue > aDummy( 0 ), aEmbDescr( 1 );
728 							aEmbDescr[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StoreVisualReplacement" ) );
729 					   		aEmbDescr[0].Value <<= (sal_Bool)(!bOasisFormat);
730 							if ( !bOasisFormat )
731 							{
732 								::rtl::OUString aMimeType;
733 								uno::Reference< io::XInputStream > xGrInStream = ImplGetReplacementImage( xObj );
734 								if ( xGrInStream.is() )
735 								{
736 									aEmbDescr.realloc( 2 );
737 									aEmbDescr[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VisualReplacement" ) );
738 									aEmbDescr[1].Value <<= xGrInStream;
739 								}
740 							}
741 
742 							xPersist->storeToEntry( mxTempStorage, aObjectStorageName,
743 													aDummy, aEmbDescr );
744 							Reference < io::XStream > xStream =
745 								mxTempStorage->openStreamElement(
746 														aObjectStorageName,
747 														embed::ElementModes::READ);
748 							if( xStream.is() )
749 								xStrm = xStream->getInputStream();
750 						}
751 					}
752 				}
753             }
754             catch ( uno::Exception& )
755             {
756             }
757 		}
758 
759 		aRet <<= xStrm;
760 	}
761 
762 	return aRet;
763 }
764 
765 Sequence< ::rtl::OUString > SAL_CALL SvXMLEmbeddedObjectHelper::getElementNames()
766 	throw (RuntimeException)
767 {
768 	MutexGuard			aGuard( maMutex );
769 	return Sequence< ::rtl::OUString >(0);
770 }
771 
772 sal_Bool SAL_CALL SvXMLEmbeddedObjectHelper::hasByName( const ::rtl::OUString& rURLStr )
773 	throw (RuntimeException)
774 {
775 	MutexGuard			aGuard( maMutex );
776 	if( EMBEDDEDOBJECTHELPER_MODE_READ == meCreateMode )
777 	{
778 		return sal_True;
779 	}
780 	else
781 	{
782 		::rtl::OUString	aContainerStorageName, aObjectStorageName;
783 		if( !ImplGetStorageNames( rURLStr, aContainerStorageName,
784 								  aObjectStorageName,
785 								  sal_True ) )
786 			return sal_False;
787 
788         comphelper::EmbeddedObjectContainer& rContainer = mpDocPersist->getEmbeddedObjectContainer();
789         return aObjectStorageName.getLength() > 0 &&
790                rContainer.HasEmbeddedObject( aObjectStorageName );
791 	}
792 }
793 
794 // XNameAccess
795 Type SAL_CALL SvXMLEmbeddedObjectHelper::getElementType()
796 	throw (RuntimeException)
797 {
798 	MutexGuard			aGuard( maMutex );
799 	if( EMBEDDEDOBJECTHELPER_MODE_READ == meCreateMode )
800 		return ::getCppuType((const Reference<XOutputStream>*)0);
801 	else
802 		return ::getCppuType((const Reference<XInputStream>*)0);
803 }
804 
805 sal_Bool SAL_CALL SvXMLEmbeddedObjectHelper::hasElements()
806 	throw (RuntimeException)
807 {
808 	MutexGuard			aGuard( maMutex );
809 	if( EMBEDDEDOBJECTHELPER_MODE_READ == meCreateMode )
810 	{
811 		return sal_True;
812 	}
813 	else
814 	{
815         comphelper::EmbeddedObjectContainer& rContainer = mpDocPersist->getEmbeddedObjectContainer();
816         return rContainer.HasEmbeddedObjects();
817     }
818 }
819 
820