1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <com/sun/star/io/XStream.hpp>
23 #include <com/sun/star/embed/XTransactedObject.hpp>
24 #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
25 #include <com/sun/star/embed/XEmbedObjectFactory.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <com/sun/star/embed/XEmbeddedObject.hpp>
28 #include <com/sun/star/embed/XEmbedPersist.hpp>
29 #include <com/sun/star/embed/EntryInitModes.hpp>
30 #include <com/sun/star/embed/EmbedStates.hpp>
31 #include <com/sun/star/embed/Aspects.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <tools/debug.hxx>
34 #include <unotools/streamwrap.hxx>
35 #include <unotools/tempfile.hxx>
37 #include <svtools/embedhlp.hxx>
38 #include <unotools/ucbstreamhelper.hxx>
39 #include <comphelper/processfactory.hxx>
40 #include <comphelper/storagehelper.hxx>
41 #include <comphelper/embeddedobjectcontainer.hxx>
43 #include <comphelper/classids.hxx>
45 #include "svx/xmleohlp.hxx"
47 using namespace ::osl
;
48 using namespace ::cppu
;
49 using namespace ::utl
;
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::document
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::container
;
54 using namespace ::com::sun::star::io
;
55 using namespace ::com::sun::star::lang
;
57 #define XML_CONTAINERSTORAGE_NAME_60 "Pictures"
58 #define XML_CONTAINERSTORAGE_NAME "ObjectReplacements"
59 #define XML_EMBEDDEDOBJECT_URL_BASE "vnd.sun.star.EmbeddedObject:"
60 #define XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE "vnd.sun.star.GraphicObject:"
62 // -----------------------------------------------------------------------------
64 class OutputStorageWrapper_Impl
: public ::cppu::WeakImplHelper1
<XOutputStream
>
67 Reference
< XOutputStream
> xOut
;
69 bool bStreamClosed
: 1;
73 OutputStorageWrapper_Impl();
74 virtual ~OutputStorageWrapper_Impl();
76 // stario::XOutputStream
77 virtual void SAL_CALL
writeBytes(const Sequence
< sal_Int8
>& aData
) throw(NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
78 virtual void SAL_CALL
flush() throw(NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
79 virtual void SAL_CALL
closeOutput() throw(NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
81 SvStream
* GetStream();
84 OutputStorageWrapper_Impl::OutputStorageWrapper_Impl()
85 : bStreamClosed( false )
88 aTempFile
.EnableKillingFile();
89 pStream
= aTempFile
.GetStream( STREAM_READWRITE
);
90 xOut
= new OOutputStreamWrapper( *pStream
);
93 OutputStorageWrapper_Impl::~OutputStorageWrapper_Impl()
97 SvStream
*OutputStorageWrapper_Impl::GetStream()
104 void SAL_CALL
OutputStorageWrapper_Impl::writeBytes(
105 const Sequence
< sal_Int8
>& aData
)
106 throw(NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
108 MutexGuard
aGuard( maMutex
);
109 xOut
->writeBytes( aData
);
112 void SAL_CALL
OutputStorageWrapper_Impl::flush()
113 throw(NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
115 MutexGuard
aGuard( maMutex
);
119 void SAL_CALL
OutputStorageWrapper_Impl::closeOutput()
120 throw(NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
122 MutexGuard
aGuard( maMutex
);
124 bStreamClosed
= true;
129 bool operator() ( const OUString
& r1
, const OUString
& r2
) const
131 return (r1
< r2
) != sal_False
;
135 DBG_NAME(SvXMLEmbeddedObjectHelper
)
136 SvXMLEmbeddedObjectHelper::SvXMLEmbeddedObjectHelper() :
137 WeakComponentImplHelper2
< XEmbeddedObjectResolver
, XNameAccess
>( maMutex
),
138 maReplacementGraphicsContainerStorageName( XML_CONTAINERSTORAGE_NAME
),
139 maReplacementGraphicsContainerStorageName60( XML_CONTAINERSTORAGE_NAME_60
),
141 meCreateMode( EMBEDDEDOBJECTHELPER_MODE_READ
),
144 DBG_CTOR(SvXMLEmbeddedObjectHelper
,NULL
);
147 SvXMLEmbeddedObjectHelper::SvXMLEmbeddedObjectHelper( ::comphelper::IEmbeddedHelper
& rDocPersist
, SvXMLEmbeddedObjectHelperMode eCreateMode
) :
148 WeakComponentImplHelper2
< XEmbeddedObjectResolver
, XNameAccess
>( maMutex
),
149 maReplacementGraphicsContainerStorageName( XML_CONTAINERSTORAGE_NAME
),
150 maReplacementGraphicsContainerStorageName60( XML_CONTAINERSTORAGE_NAME_60
),
152 meCreateMode( EMBEDDEDOBJECTHELPER_MODE_READ
),
155 DBG_CTOR(SvXMLEmbeddedObjectHelper
,NULL
);
156 Init( 0, rDocPersist
, eCreateMode
);
159 SvXMLEmbeddedObjectHelper::~SvXMLEmbeddedObjectHelper()
161 DBG_DTOR(SvXMLEmbeddedObjectHelper
,NULL
);
164 SvXMLEmbeddedObjectHelper_Impl::iterator aIter
= mpStreamMap
->begin();
165 SvXMLEmbeddedObjectHelper_Impl::iterator aEnd
= mpStreamMap
->end();
166 for( ; aIter
!= aEnd
; ++aIter
)
170 aIter
->second
->release();
178 void SAL_CALL
SvXMLEmbeddedObjectHelper::disposing()
184 void SvXMLEmbeddedObjectHelper::splitObjectURL(OUString aURLNoPar
,
185 OUString
& rContainerStorageName
,
186 OUString
& rObjectStorageName
)
188 DBG_ASSERT( '#' != aURLNoPar
[0], "invalid object URL" );
190 sal_Int32 _nPos
= aURLNoPar
.lastIndexOf( '/' );
193 rContainerStorageName
= OUString();
194 rObjectStorageName
= aURLNoPar
;
198 //eliminate 'superfluous' slashes at start and end
199 //#i103076# load objects with all allowed xlink:href syntaxes
201 //eliminate './' at start
202 sal_Int32 nStart
= 0;
203 sal_Int32 nCount
= aURLNoPar
.getLength();
204 if( aURLNoPar
.startsWith( "./" ) )
210 //eliminate '/' at end
211 sal_Int32 nEnd
= aURLNoPar
.lastIndexOf( '/' );
212 if( nEnd
== aURLNoPar
.getLength()-1 && nEnd
!= (nStart
-1) )
215 aURLNoPar
= aURLNoPar
.copy( nStart
, nCount
);
218 _nPos
= aURLNoPar
.lastIndexOf( '/' );
220 rContainerStorageName
= aURLNoPar
.copy( 0, _nPos
);
221 rObjectStorageName
= aURLNoPar
.copy( _nPos
+1 );
225 sal_Bool
SvXMLEmbeddedObjectHelper::ImplGetStorageNames(
226 const OUString
& rURLStr
,
227 OUString
& rContainerStorageName
,
228 OUString
& rObjectStorageName
,
229 sal_Bool bInternalToExternal
,
230 sal_Bool
*pGraphicRepl
,
231 sal_Bool
*pOasisFormat
) const
233 // internal URL: vnd.sun.star.EmbeddedObject:<object-name>
234 // or: vnd.sun.star.EmbeddedObject:<path>/<object-name>
235 // internal replacement images:
236 // vnd.sun.star.EmbeddedObjectGraphic:<object-name>
237 // or: vnd.sun.star.EmbeddedObjectGraphic:<path>/<object-name>
238 // external URL: ./<path>/<object-name>
239 // or: <path>/<object-name>
241 // currently, path may only consist of a single directory name
242 // it is also possible to have additional arguments at the end of URL: <main URL>[?<name>=<value>[,<name>=<value>]*]
245 *pGraphicRepl
= sal_False
;
248 *pOasisFormat
= sal_True
; // the default value
250 if( rURLStr
.isEmpty() )
253 // get rid of arguments
254 sal_Int32 nPos
= rURLStr
.indexOf( '?' );
260 aURLNoPar
= rURLStr
.copy( 0, nPos
);
262 // check the arguments
264 while( nPos
>= 0 && nPos
< rURLStr
.getLength() )
266 OUString aToken
= rURLStr
.getToken( 0, ',', nPos
);
267 if ( aToken
.equalsIgnoreAsciiCase( OUString( "oasis=false" ) ) )
270 *pOasisFormat
= sal_False
;
275 DBG_ASSERT( sal_False
, "invalid arguments was found in URL!" );
280 if( bInternalToExternal
)
282 nPos
= aURLNoPar
.indexOf( ':' );
285 sal_Bool bObjUrl
= aURLNoPar
.startsWith( XML_EMBEDDEDOBJECT_URL_BASE
);
286 bool bGrUrl
= !bObjUrl
&&
287 aURLNoPar
.startsWith( XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE
);
288 if( !(bObjUrl
|| bGrUrl
) )
291 sal_Int32 nPathStart
= nPos
+ 1;
292 nPos
= aURLNoPar
.lastIndexOf( '/' );
295 rContainerStorageName
= OUString();
296 rObjectStorageName
= aURLNoPar
.copy( nPathStart
);
298 else if( nPos
> nPathStart
)
300 rContainerStorageName
= aURLNoPar
.copy( nPathStart
, nPos
-nPathStart
);
301 rObjectStorageName
= aURLNoPar
.copy( nPos
+1 );
308 bool bOASIS
= mxRootStorage
.is() &&
309 ( SotStorage::GetVersion( mxRootStorage
) > SOFFICE_FILEFORMAT_60
);
310 rContainerStorageName
= bOASIS
311 ? maReplacementGraphicsContainerStorageName
312 : maReplacementGraphicsContainerStorageName60
;
315 *pGraphicRepl
= sal_True
;
322 splitObjectURL(aURLNoPar
, rContainerStorageName
, rObjectStorageName
);
325 if( -1 != rContainerStorageName
.indexOf( '/' ) )
327 OSL_FAIL( "SvXMLEmbeddedObjectHelper: invalid path name" );
334 uno::Reference
< embed::XStorage
> SvXMLEmbeddedObjectHelper::ImplGetContainerStorage(
335 const OUString
& rStorageName
)
337 DBG_ASSERT( -1 == rStorageName
.indexOf( '/' ) &&
338 -1 == rStorageName
.indexOf( '\\' ),
339 "nested embedded storages aren't supported" );
340 if( !mxContainerStorage
.is() ||
341 ( rStorageName
!= maCurContainerStorageName
) )
343 if( mxContainerStorage
.is() &&
344 !maCurContainerStorageName
.isEmpty() &&
345 EMBEDDEDOBJECTHELPER_MODE_WRITE
== meCreateMode
)
347 uno::Reference
< embed::XTransactedObject
> xTrans( mxContainerStorage
, uno::UNO_QUERY
);
352 if( !rStorageName
.isEmpty() && mxRootStorage
.is() )
354 sal_Int32 nMode
= EMBEDDEDOBJECTHELPER_MODE_WRITE
== meCreateMode
355 ? ::embed::ElementModes::READWRITE
356 : ::embed::ElementModes::READ
;
357 mxContainerStorage
= mxRootStorage
->openStorageElement( rStorageName
,
362 mxContainerStorage
= mxRootStorage
;
364 maCurContainerStorageName
= rStorageName
;
367 return mxContainerStorage
;
370 sal_Bool
SvXMLEmbeddedObjectHelper::ImplReadObject(
371 const OUString
& rContainerStorageName
,
373 const SvGlobalName
*pClassId
,
378 uno::Reference
< embed::XStorage
> xDocStor( mpDocPersist
->getStorage() );
379 uno::Reference
< embed::XStorage
> xCntnrStor( ImplGetContainerStorage( rContainerStorageName
) );
381 if( !xCntnrStor
.is() && !pTemp
)
384 String
aSrcObjName( rObjName
);
385 comphelper::EmbeddedObjectContainer
& rContainer
= mpDocPersist
->getEmbeddedObjectContainer();
387 // Is the object name unique?
388 // if the object is already instantiated by GetEmbeddedObject
389 // that means that the duplication is being loaded
390 sal_Bool bDuplicate
= rContainer
.HasInstantiatedEmbeddedObject( rObjName
);
391 DBG_ASSERT( !bDuplicate
, "An object in the document is referenced twice!" );
393 if( xDocStor
!= xCntnrStor
|| pTemp
|| bDuplicate
)
395 // TODO/LATER: make this alltogether a method in the EmbeddedObjectContainer
397 // create a unique name for the duplicate object
399 rObjName
= rContainer
.CreateUniqueObjectName();
406 uno::Reference
< io::XStream
> xStm
= xDocStor
->openStreamElement( rObjName
,
407 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
408 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( xStm
);
412 // TODO/LATER: what to do when other types of objects are based on substream persistence?
413 // This is an ole object
414 uno::Reference
< beans::XPropertySet
> xProps( xStm
, uno::UNO_QUERY_THROW
);
415 xProps
->setPropertyValue(
416 OUString( "MediaType" ),
417 uno::makeAny( OUString( "application/vnd.sun.star.oleobject" ) ) );
419 xStm
->getOutputStream()->closeOutput();
421 catch ( uno::Exception
& )
430 xCntnrStor
->copyElementTo( aSrcObjName
, xDocStor
, rObjName
);
432 catch ( uno::Exception
& )
439 // make object known to the container
440 // TODO/LATER: could be done a little bit more efficient!
441 OUString
aName( rObjName
);
443 // TODO/LATER: The provided pClassId is ignored for now.
444 // The stream contains OLE storage internally and this storage already has a class id specifying the
445 // server that was used to create the object. pClassId could be used to specify the server that should
446 // be used for the next opening, but this information seems to be out of the file format responsibility
448 rContainer
.GetEmbeddedObject( aName
);
453 OUString
SvXMLEmbeddedObjectHelper::ImplInsertEmbeddedObjectURL(
454 const OUString
& rURLStr
)
458 OUString aContainerStorageName
, aObjectStorageName
;
459 if( !ImplGetStorageNames( rURLStr
, aContainerStorageName
,
461 EMBEDDEDOBJECTHELPER_MODE_WRITE
== meCreateMode
) )
464 if( EMBEDDEDOBJECTHELPER_MODE_READ
== meCreateMode
)
466 OutputStorageWrapper_Impl
*pOut
= 0;
467 SvXMLEmbeddedObjectHelper_Impl::iterator aIter
;
471 aIter
= mpStreamMap
->find( rURLStr
);
472 if( aIter
!= mpStreamMap
->end() && aIter
->second
)
473 pOut
= aIter
->second
;
476 SvGlobalName aClassId
, *pClassId
= 0;
477 sal_Int32 nPos
= aObjectStorageName
.lastIndexOf( '!' );
478 if( -1 != nPos
&& aClassId
.MakeId( aObjectStorageName
.copy( nPos
+1 ) ) )
480 aObjectStorageName
= aObjectStorageName
.copy( 0, nPos
);
481 pClassId
= &aClassId
;
484 ImplReadObject( aContainerStorageName
, aObjectStorageName
, pClassId
, pOut
? pOut
->GetStream() : 0 );
485 sRetURL
= OUString( XML_EMBEDDEDOBJECT_URL_BASE
);
486 sRetURL
+= aObjectStorageName
;
490 mpStreamMap
->erase( aIter
);
496 // Objects are written using ::comphelper::IEmbeddedHelper::SaveAs
497 sRetURL
= OUString("./");
498 if( !aContainerStorageName
.isEmpty() )
500 sRetURL
+= aContainerStorageName
;
501 sRetURL
+= OUString( '/' );
503 sRetURL
+= aObjectStorageName
;
509 uno::Reference
< io::XInputStream
> SvXMLEmbeddedObjectHelper::ImplGetReplacementImage(
510 const uno::Reference
< embed::XEmbeddedObject
>& xObj
)
512 uno::Reference
< io::XInputStream
> xStream
;
518 bool bSwitchBackToLoaded
= false;
519 sal_Int32 nCurState
= xObj
->getCurrentState();
520 if ( nCurState
== embed::EmbedStates::LOADED
|| nCurState
== embed::EmbedStates::RUNNING
)
522 // means that the object is not active
523 // copy replacement image from old to new container
525 xStream
= mpDocPersist
->getEmbeddedObjectContainer().GetGraphicStream( xObj
, &aMediaType
);
530 // the image must be regenerated
531 // TODO/LATER: another aspect could be used
532 if ( nCurState
== embed::EmbedStates::LOADED
)
533 bSwitchBackToLoaded
= true;
536 xStream
= svt::EmbeddedObjectRef::GetGraphicReplacementStream(
537 embed::Aspects::MSOLE_CONTENT
,
542 if ( bSwitchBackToLoaded
)
543 // switch back to loaded state; that way we have a minimum cache confusion
544 xObj
->changeState( embed::EmbedStates::LOADED
);
546 catch( uno::Exception
& )
553 void SvXMLEmbeddedObjectHelper::Init(
554 const uno::Reference
< embed::XStorage
>& rRootStorage
,
555 ::comphelper::IEmbeddedHelper
& rPersist
,
556 SvXMLEmbeddedObjectHelperMode eCreateMode
)
558 mxRootStorage
= rRootStorage
;
559 mpDocPersist
= &rPersist
;
560 meCreateMode
= eCreateMode
;
563 SvXMLEmbeddedObjectHelper
* SvXMLEmbeddedObjectHelper::Create(
564 const uno::Reference
< embed::XStorage
>& rRootStorage
,
565 ::comphelper::IEmbeddedHelper
& rDocPersist
,
566 SvXMLEmbeddedObjectHelperMode eCreateMode
,
571 SvXMLEmbeddedObjectHelper
* pThis
= new SvXMLEmbeddedObjectHelper
;
574 pThis
->Init( rRootStorage
, rDocPersist
, eCreateMode
);
579 SvXMLEmbeddedObjectHelper
* SvXMLEmbeddedObjectHelper::Create(
580 ::comphelper::IEmbeddedHelper
& rDocPersist
,
581 SvXMLEmbeddedObjectHelperMode eCreateMode
)
583 SvXMLEmbeddedObjectHelper
* pThis
= new SvXMLEmbeddedObjectHelper
;
586 pThis
->Init( 0, rDocPersist
, eCreateMode
);
591 void SvXMLEmbeddedObjectHelper::Destroy(
592 SvXMLEmbeddedObjectHelper
* pSvXMLEmbeddedObjectHelper
)
594 if( pSvXMLEmbeddedObjectHelper
)
596 pSvXMLEmbeddedObjectHelper
->dispose();
597 pSvXMLEmbeddedObjectHelper
->release();
601 void SvXMLEmbeddedObjectHelper::Flush()
603 if( mxTempStorage
.is() )
605 Reference
< XComponent
> xComp( mxTempStorage
, UNO_QUERY
);
610 // XGraphicObjectResolver: alien objects!
611 OUString SAL_CALL
SvXMLEmbeddedObjectHelper::resolveEmbeddedObjectURL( const OUString
& aURL
)
612 throw(RuntimeException
)
614 MutexGuard
aGuard( maMutex
);
616 return ImplInsertEmbeddedObjectURL( aURL
);
619 // XNameAccess: alien objects!
620 Any SAL_CALL
SvXMLEmbeddedObjectHelper::getByName(
621 const OUString
& rURLStr
)
622 throw (NoSuchElementException
, WrappedTargetException
, RuntimeException
)
624 MutexGuard
aGuard( maMutex
);
626 if( EMBEDDEDOBJECTHELPER_MODE_READ
== meCreateMode
)
628 Reference
< XOutputStream
> xStrm
;
631 SvXMLEmbeddedObjectHelper_Impl::iterator aIter
=
632 mpStreamMap
->find( rURLStr
);
633 if( aIter
!= mpStreamMap
->end() && aIter
->second
)
634 xStrm
= aIter
->second
;
638 OutputStorageWrapper_Impl
*pOut
= new OutputStorageWrapper_Impl
;
641 mpStreamMap
= new SvXMLEmbeddedObjectHelper_Impl
;
642 (*mpStreamMap
)[rURLStr
] = pOut
;
650 sal_Bool bGraphicRepl
= sal_False
;
651 sal_Bool bOasisFormat
= sal_True
;
652 Reference
< XInputStream
> xStrm
;
653 OUString aContainerStorageName
, aObjectStorageName
;
654 if( ImplGetStorageNames( rURLStr
, aContainerStorageName
,
662 comphelper::EmbeddedObjectContainer
& rContainer
=
663 mpDocPersist
->getEmbeddedObjectContainer();
665 Reference
< embed::XEmbeddedObject
> xObj
= rContainer
.GetEmbeddedObject( aObjectStorageName
);
666 DBG_ASSERT( xObj
.is(), "Didn't get object" );
672 xStrm
= ImplGetReplacementImage( xObj
);
676 Reference
< embed::XEmbedPersist
> xPersist( xObj
, UNO_QUERY
);
679 if( !mxTempStorage
.is() )
681 comphelper::OStorageHelper::GetTemporaryStorage();
682 Sequence
< beans::PropertyValue
> aDummy( 0 ), aEmbDescr( 1 );
683 aEmbDescr
[0].Name
= OUString( "StoreVisualReplacement" );
684 aEmbDescr
[0].Value
<<= (sal_Bool
)(!bOasisFormat
);
687 uno::Reference
< io::XInputStream
> xGrInStream
= ImplGetReplacementImage( xObj
);
688 if ( xGrInStream
.is() )
690 aEmbDescr
.realloc( 2 );
691 aEmbDescr
[1].Name
= OUString( "VisualReplacement" );
692 aEmbDescr
[1].Value
<<= xGrInStream
;
696 xPersist
->storeToEntry( mxTempStorage
, aObjectStorageName
,
698 Reference
< io::XStream
> xStream
=
699 mxTempStorage
->openStreamElement(
701 embed::ElementModes::READ
);
703 xStrm
= xStream
->getInputStream();
708 catch ( uno::Exception
& )
719 Sequence
< OUString
> SAL_CALL
SvXMLEmbeddedObjectHelper::getElementNames()
720 throw (RuntimeException
)
722 MutexGuard
aGuard( maMutex
);
723 return Sequence
< OUString
>(0);
726 sal_Bool SAL_CALL
SvXMLEmbeddedObjectHelper::hasByName( const OUString
& rURLStr
)
727 throw (RuntimeException
)
729 MutexGuard
aGuard( maMutex
);
730 if( EMBEDDEDOBJECTHELPER_MODE_READ
== meCreateMode
)
736 OUString aContainerStorageName
, aObjectStorageName
;
737 if( !ImplGetStorageNames( rURLStr
, aContainerStorageName
,
742 comphelper::EmbeddedObjectContainer
& rContainer
= mpDocPersist
->getEmbeddedObjectContainer();
743 return !aObjectStorageName
.isEmpty() &&
744 rContainer
.HasEmbeddedObject( aObjectStorageName
);
749 Type SAL_CALL
SvXMLEmbeddedObjectHelper::getElementType()
750 throw (RuntimeException
)
752 MutexGuard
aGuard( maMutex
);
753 if( EMBEDDEDOBJECTHELPER_MODE_READ
== meCreateMode
)
754 return ::getCppuType((const Reference
<XOutputStream
>*)0);
756 return ::getCppuType((const Reference
<XInputStream
>*)0);
759 sal_Bool SAL_CALL
SvXMLEmbeddedObjectHelper::hasElements()
760 throw (RuntimeException
)
762 MutexGuard
aGuard( maMutex
);
763 if( EMBEDDEDOBJECTHELPER_MODE_READ
== meCreateMode
)
769 comphelper::EmbeddedObjectContainer
& rContainer
= mpDocPersist
->getEmbeddedObjectContainer();
770 return rContainer
.HasEmbeddedObjects();
774 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */