1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <oleembobj.hxx>
21 #include "olepersist.hxx"
22 #include <com/sun/star/embed/EmbedStates.hpp>
23 #include <com/sun/star/embed/EmbedVerbs.hpp>
24 #include <com/sun/star/embed/EntryInitModes.hpp>
25 #include <com/sun/star/embed/WrongStateException.hpp>
26 #include <com/sun/star/embed/XStorage.hpp>
27 #include <com/sun/star/embed/XTransactedObject.hpp>
28 #include <com/sun/star/embed/ElementModes.hpp>
29 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
30 #include <com/sun/star/embed/Aspects.hpp>
31 #include <com/sun/star/embed/XOptimizedStorage.hpp>
32 #include <com/sun/star/lang/XComponent.hpp>
33 #include <com/sun/star/lang/DisposedException.hpp>
34 #include <com/sun/star/container/XNameAccess.hpp>
35 #include <com/sun/star/container/XNameContainer.hpp>
36 #include <com/sun/star/io/TempFile.hpp>
37 #include <com/sun/star/io/XSeekable.hpp>
38 #include <com/sun/star/io/XTruncate.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/packages/WrongPasswordException.hpp>
41 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
42 #include <com/sun/star/io/IOException.hpp>
44 #include <comphelper/processfactory.hxx>
45 #include <comphelper/storagehelper.hxx>
46 #include <comphelper/mimeconfighelper.hxx>
47 #include <comphelper/classids.hxx>
48 #include <osl/diagnose.h>
49 #include <osl/thread.hxx>
50 #include <sal/log.hxx>
52 #include <closepreventer.hxx>
55 #include "olecomponent.hxx"
58 using namespace ::com::sun::star
;
59 using namespace ::comphelper
;
62 bool KillFile_Impl( const OUString
& aURL
, const uno::Reference
< uno::XComponentContext
>& xContext
)
71 uno::Reference
< ucb::XSimpleFileAccess3
> xAccess(
72 ucb::SimpleFileAccess::create( xContext
) );
74 xAccess
->kill( aURL
);
77 catch( const uno::Exception
& )
85 OUString
GetNewTempFileURL_Impl( const uno::Reference
< uno::XComponentContext
>& xContext
)
87 SAL_WARN_IF( !xContext
.is(), "embeddedobj.ole", "No factory is provided!" );
91 uno::Reference
< beans::XPropertySet
> xTempFile(
92 io::TempFile::create(xContext
),
93 uno::UNO_QUERY_THROW
);
96 xTempFile
->setPropertyValue("RemoveFile", uno::makeAny( false ) );
97 uno::Any aUrl
= xTempFile
->getPropertyValue("Uri");
100 catch ( const uno::Exception
& )
104 if ( aResult
.isEmpty() )
105 throw uno::RuntimeException(); // TODO: can not create tempfile
111 OUString
GetNewFilledTempFile_Impl( const uno::Reference
< io::XInputStream
>& xInStream
,
112 const uno::Reference
< uno::XComponentContext
>& xContext
)
114 OSL_ENSURE( xInStream
.is() && xContext
.is(), "Wrong parameters are provided!" );
116 OUString aResult
= GetNewTempFileURL_Impl( xContext
);
118 if ( !aResult
.isEmpty() )
121 uno::Reference
< ucb::XSimpleFileAccess3
> xTempAccess(
122 ucb::SimpleFileAccess::create( xContext
) );
124 uno::Reference
< io::XOutputStream
> xTempOutStream
= xTempAccess
->openFileWrite( aResult
);
125 if ( !xTempOutStream
.is() )
126 throw io::IOException(); // TODO:
127 // copy stream contents to the file
128 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream
, xTempOutStream
);
129 xTempOutStream
->closeOutput();
130 xTempOutStream
.clear();
132 catch( const packages::WrongPasswordException
& )
134 KillFile_Impl( aResult
, xContext
);
135 throw io::IOException(); //TODO:
137 catch( const io::IOException
& )
139 KillFile_Impl( aResult
, xContext
);
142 catch( const uno::RuntimeException
& )
144 KillFile_Impl( aResult
, xContext
);
147 catch( const uno::Exception
& )
149 KillFile_Impl( aResult
, xContext
);
157 /// @throws io::IOException
158 /// @throws uno::RuntimeException
159 static OUString
GetNewFilledTempFile_Impl( const uno::Reference
< embed::XOptimizedStorage
>& xParentStorage
, const OUString
& aEntryName
, const uno::Reference
< uno::XComponentContext
>& xContext
)
165 uno::Reference
< beans::XPropertySet
> xTempFile(
166 io::TempFile::create(xContext
),
168 uno::Reference
< io::XStream
> xTempStream( xTempFile
, uno::UNO_QUERY_THROW
);
170 xParentStorage
->copyStreamElementData( aEntryName
, xTempStream
);
172 xTempFile
->setPropertyValue("RemoveFile", uno::makeAny( false ) );
173 uno::Any aUrl
= xTempFile
->getPropertyValue("Uri");
176 catch( const uno::RuntimeException
& )
180 catch( const uno::Exception
& )
184 if ( aResult
.isEmpty() )
185 throw io::IOException();
191 static void SetStreamMediaType_Impl( const uno::Reference
< io::XStream
>& xStream
, const OUString
& aMediaType
)
193 uno::Reference
< beans::XPropertySet
> xPropSet( xStream
, uno::UNO_QUERY_THROW
);
194 xPropSet
->setPropertyValue("MediaType", uno::makeAny( aMediaType
) );
198 static void LetCommonStoragePassBeUsed_Impl( const uno::Reference
< io::XStream
>& xStream
)
200 uno::Reference
< beans::XPropertySet
> xPropSet( xStream
, uno::UNO_QUERY_THROW
);
201 xPropSet
->setPropertyValue("UseCommonStoragePasswordEncryption",
202 uno::makeAny( true ) );
206 void VerbExecutionController::StartControlExecution()
208 osl::MutexGuard
aGuard( m_aVerbExecutionMutex
);
210 // the class is used to detect STAMPIT object, that can never be active
211 if ( !m_bVerbExecutionInProgress
&& !m_bWasEverActive
)
213 m_bVerbExecutionInProgress
= true;
214 m_nVerbExecutionThreadIdentifier
= osl::Thread::getCurrentIdentifier();
215 m_bChangedOnVerbExecution
= false;
220 bool VerbExecutionController::EndControlExecution_WasModified()
222 osl::MutexGuard
aGuard( m_aVerbExecutionMutex
);
224 bool bResult
= false;
225 if ( m_bVerbExecutionInProgress
&& m_nVerbExecutionThreadIdentifier
== osl::Thread::getCurrentIdentifier() )
227 bResult
= m_bChangedOnVerbExecution
;
228 m_bVerbExecutionInProgress
= false;
235 void VerbExecutionController::ModificationNotificationIsDone()
237 osl::MutexGuard
aGuard( m_aVerbExecutionMutex
);
239 if ( m_bVerbExecutionInProgress
&& osl::Thread::getCurrentIdentifier() == m_nVerbExecutionThreadIdentifier
)
240 m_bChangedOnVerbExecution
= true;
244 void VerbExecutionController::LockNotification()
246 osl::MutexGuard
aGuard( m_aVerbExecutionMutex
);
247 if ( m_nNotificationLock
< SAL_MAX_INT32
)
248 m_nNotificationLock
++;
252 void VerbExecutionController::UnlockNotification()
254 osl::MutexGuard
aGuard( m_aVerbExecutionMutex
);
255 if ( m_nNotificationLock
> 0 )
256 m_nNotificationLock
--;
260 uno::Reference
< io::XStream
> OleEmbeddedObject::GetNewFilledTempStream_Impl( const uno::Reference
< io::XInputStream
>& xInStream
)
262 SAL_WARN_IF( !xInStream
.is(), "embeddedobj.ole", "Wrong parameter is provided!" );
264 uno::Reference
< io::XStream
> xTempFile(
265 io::TempFile::create(m_xContext
),
266 uno::UNO_QUERY_THROW
);
268 uno::Reference
< io::XOutputStream
> xTempOutStream
= xTempFile
->getOutputStream();
269 if ( !xTempOutStream
.is() )
270 throw io::IOException(); // TODO:
271 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream
, xTempOutStream
);
272 xTempOutStream
->flush();
277 uno::Reference
< io::XStream
> OleEmbeddedObject::TryToGetAcceptableFormat_Impl( const uno::Reference
< io::XStream
>& xStream
)
279 // TODO/LATER: Actually this should be done by a centralized component ( may be a graphical filter )
280 if ( !m_xContext
.is() )
281 throw uno::RuntimeException();
283 uno::Reference
< io::XInputStream
> xInStream
= xStream
->getInputStream();
284 if ( !xInStream
.is() )
285 throw uno::RuntimeException();
287 uno::Reference
< io::XSeekable
> xSeek( xStream
, uno::UNO_QUERY_THROW
);
290 uno::Sequence
< sal_Int8
> aData( 8 );
291 sal_Int32 nRead
= xInStream
->readBytes( aData
, 8 );
294 if ( ( nRead
>= 2 && aData
[0] == 'B' && aData
[1] == 'M' )
295 || ( nRead
>= 4 && aData
[0] == 1 && aData
[1] == 0 && aData
[2] == 9 && aData
[3] == 0 ) )
297 // it should be a bitmap or a Metafile
302 sal_uInt32 nHeaderOffset
= 0;
303 if ( ( nRead
>= 8 && aData
[0] == -1 && aData
[1] == -1 && aData
[2] == -1 && aData
[3] == -1 )
304 && ( aData
[4] == 2 || aData
[4] == 3 || aData
[4] == 14 ) && aData
[5] == 0 && aData
[6] == 0 && aData
[7] == 0 )
309 // TargetDevice might be used in future, currently the cache has specified NULL
310 uno::Sequence
< sal_Int8
> aHeadData( 4 );
311 nRead
= xInStream
->readBytes( aHeadData
, 4 );
313 if ( nRead
== 4 && aHeadData
.getLength() == 4 )
314 nLen
= ( ( ( static_cast<sal_uInt32
>(aHeadData
[3]) * 0x100 + static_cast<sal_uInt32
>(aHeadData
[2]) ) * 0x100 ) + static_cast<sal_uInt32
>(aHeadData
[1]) ) * 0x100 + static_cast<sal_uInt32
>(aHeadData
[0]);
317 xInStream
->skipBytes( nLen
- 4 );
318 nHeaderOffset
+= nLen
- 4;
322 else if ( nRead
> 4 )
324 // check whether the first bytes represent the size
325 sal_uInt32 nSize
= 0;
326 for ( sal_Int32 nInd
= 3; nInd
>= 0; nInd
-- )
327 nSize
= ( nSize
<< 8 ) + static_cast<sal_uInt8
>(aData
[nInd
]);
329 if ( nSize
== xSeek
->getLength() - 4 )
335 // this is either a bitmap or a metafile clipboard format, retrieve the pure stream
336 uno::Reference
< io::XStream
> xResult(
337 io::TempFile::create(m_xContext
),
338 uno::UNO_QUERY_THROW
);
339 uno::Reference
< io::XSeekable
> xResultSeek( xResult
, uno::UNO_QUERY_THROW
);
340 uno::Reference
< io::XOutputStream
> xResultOut
= xResult
->getOutputStream();
341 uno::Reference
< io::XInputStream
> xResultIn
= xResult
->getInputStream();
342 if ( !xResultOut
.is() || !xResultIn
.is() )
343 throw uno::RuntimeException();
345 xSeek
->seek( nHeaderOffset
); // header size for these formats
346 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream
, xResultOut
);
347 xResultOut
->closeOutput();
348 xResultSeek
->seek( 0 );
354 return uno::Reference
< io::XStream
>();
358 void OleEmbeddedObject::InsertVisualCache_Impl( const uno::Reference
< io::XStream
>& xTargetStream
,
359 const uno::Reference
< io::XStream
>& xCachedVisualRepresentation
)
361 OSL_ENSURE( xTargetStream
.is() && xCachedVisualRepresentation
.is(), "Invalid arguments!" );
363 if ( !xTargetStream
.is() || !xCachedVisualRepresentation
.is() )
364 throw uno::RuntimeException();
366 uno::Sequence
< uno::Any
> aArgs( 2 );
367 aArgs
[0] <<= xTargetStream
;
368 aArgs
[1] <<= true; // do not create copy
370 uno::Reference
< container::XNameContainer
> xNameContainer(
371 m_xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
372 "com.sun.star.embed.OLESimpleStorage",
374 uno::UNO_QUERY_THROW
);
376 uno::Reference
< io::XSeekable
> xCachedSeek( xCachedVisualRepresentation
, uno::UNO_QUERY_THROW
);
377 xCachedSeek
->seek( 0 );
379 uno::Reference
< io::XStream
> xTempFile(
380 io::TempFile::create(m_xContext
),
381 uno::UNO_QUERY_THROW
);
383 uno::Reference
< io::XSeekable
> xTempSeek( xTempFile
, uno::UNO_QUERY_THROW
);
384 uno::Reference
< io::XOutputStream
> xTempOutStream
= xTempFile
->getOutputStream();
385 if ( !xTempOutStream
.is() )
386 throw io::IOException(); // TODO:
388 // the OlePres stream must have additional header
389 // TODO/LATER: might need to be extended in future (actually makes sense only for SO7 format)
390 uno::Reference
< io::XInputStream
> xInCacheStream
= xCachedVisualRepresentation
->getInputStream();
391 if ( !xInCacheStream
.is() )
392 throw uno::RuntimeException();
394 // write 0xFFFFFFFF at the beginning
395 uno::Sequence
< sal_Int8
> aData( 4 );
396 * reinterpret_cast<sal_uInt32
*>(aData
.getArray()) = 0xFFFFFFFF;
398 xTempOutStream
->writeBytes( aData
);
400 // write clipboard format
401 uno::Sequence
< sal_Int8
> aSigData( 2 );
402 xInCacheStream
->readBytes( aSigData
, 2 );
403 if ( aSigData
.getLength() < 2 )
404 throw io::IOException();
406 if ( aSigData
[0] == 'B' && aSigData
[1] == 'M' )
409 aData
[0] = 0x02; aData
[1] = 0; aData
[2] = 0; aData
[3] = 0;
413 // treat it as a metafile
414 aData
[0] = 0x03; aData
[1] = 0; aData
[2] = 0; aData
[3] = 0;
416 xTempOutStream
->writeBytes( aData
);
418 // write job related information
419 aData
[0] = 0x04; aData
[1] = 0; aData
[2] = 0; aData
[3] = 0;
420 xTempOutStream
->writeBytes( aData
);
423 aData
[0] = 0x01; aData
[1] = 0; aData
[2] = 0; aData
[3] = 0;
424 xTempOutStream
->writeBytes( aData
);
427 * reinterpret_cast<sal_uInt32
*>(aData
.getArray()) = 0xFFFFFFFF;
428 xTempOutStream
->writeBytes( aData
);
431 aData
[0] = 0x02; aData
[1] = 0; aData
[2] = 0; aData
[3] = 0;
432 xTempOutStream
->writeBytes( aData
);
435 * reinterpret_cast<sal_uInt32
*>(aData
.getArray()) = 0x0;
436 xTempOutStream
->writeBytes( aData
);
439 awt::Size aSize
= getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
440 sal_Int32 nIndex
= 0;
443 for ( nIndex
= 0; nIndex
< 4; nIndex
++ )
445 aData
[nIndex
] = static_cast<sal_Int8
>( aSize
.Width
% 0x100 );
446 aSize
.Width
/= 0x100;
448 xTempOutStream
->writeBytes( aData
);
451 for ( nIndex
= 0; nIndex
< 4; nIndex
++ )
453 aData
[nIndex
] = static_cast<sal_Int8
>( aSize
.Height
% 0x100 );
454 aSize
.Height
/= 0x100;
456 xTempOutStream
->writeBytes( aData
);
458 // write garbage, it will be overwritten by the size
459 xTempOutStream
->writeBytes( aData
);
461 // write first bytes that was used to detect the type
462 xTempOutStream
->writeBytes( aSigData
);
464 // write the rest of the stream
465 ::comphelper::OStorageHelper::CopyInputToOutput( xInCacheStream
, xTempOutStream
);
467 // write the size of the stream
468 sal_Int64 nLength
= xTempSeek
->getLength() - 40;
469 if ( nLength
< 0 || nLength
>= 0xFFFFFFFF )
471 SAL_WARN( "embeddedobj.ole", "Length is not acceptable!" );
474 for ( sal_Int32 nInd
= 0; nInd
< 4; nInd
++ )
476 aData
[nInd
] = static_cast<sal_Int8
>( static_cast<sal_uInt64
>(nLength
) % 0x100 );
479 xTempSeek
->seek( 36 );
480 xTempOutStream
->writeBytes( aData
);
482 xTempOutStream
->flush();
484 xTempSeek
->seek( 0 );
485 if ( xCachedSeek
.is() )
486 xCachedSeek
->seek( 0 );
488 // insert the result file as replacement image
489 OUString aCacheName
= "\002OlePres000";
490 if ( xNameContainer
->hasByName( aCacheName
) )
491 xNameContainer
->replaceByName( aCacheName
, uno::makeAny( xTempFile
) );
493 xNameContainer
->insertByName( aCacheName
, uno::makeAny( xTempFile
) );
495 uno::Reference
< embed::XTransactedObject
> xTransacted( xNameContainer
, uno::UNO_QUERY_THROW
);
496 xTransacted
->commit();
500 void OleEmbeddedObject::RemoveVisualCache_Impl( const uno::Reference
< io::XStream
>& xTargetStream
)
502 OSL_ENSURE( xTargetStream
.is(), "Invalid argument!" );
503 if ( !xTargetStream
.is() )
504 throw uno::RuntimeException();
506 uno::Sequence
< uno::Any
> aArgs( 2 );
507 aArgs
[0] <<= xTargetStream
;
508 aArgs
[1] <<= true; // do not create copy
509 uno::Reference
< container::XNameContainer
> xNameContainer(
510 m_xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
511 "com.sun.star.embed.OLESimpleStorage",
513 uno::UNO_QUERY_THROW
);
515 for ( sal_uInt8 nInd
= 0; nInd
< 10; nInd
++ )
517 OUString aStreamName
= "\002OlePres00" + OUString::number( nInd
);
518 if ( xNameContainer
->hasByName( aStreamName
) )
519 xNameContainer
->removeByName( aStreamName
);
522 uno::Reference
< embed::XTransactedObject
> xTransacted( xNameContainer
, uno::UNO_QUERY_THROW
);
523 xTransacted
->commit();
527 void OleEmbeddedObject::SetVisReplInStream( bool bExists
)
529 m_bVisReplInitialized
= true;
530 m_bVisReplInStream
= bExists
;
534 bool OleEmbeddedObject::HasVisReplInStream()
536 if ( !m_bVisReplInitialized
)
538 if ( m_xCachedVisualRepresentation
.is() )
539 SetVisReplInStream( true );
542 SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::HasVisualReplInStream, analyzing" );
544 uno::Reference
< io::XInputStream
> xStream
;
546 OSL_ENSURE( !m_pOleComponent
|| !m_aTempURL
.isEmpty(), "The temporary file must exist if there is a component!" );
547 if ( !m_aTempURL
.isEmpty() )
551 // open temporary file for reading
552 uno::Reference
< ucb::XSimpleFileAccess3
> xTempAccess(
553 ucb::SimpleFileAccess::create( m_xContext
) );
555 xStream
= xTempAccess
->openFileRead( m_aTempURL
);
557 catch( const uno::Exception
& )
562 xStream
= m_xObjectStream
->getInputStream();
566 bool bExists
= false;
568 uno::Sequence
< uno::Any
> aArgs( 2 );
569 aArgs
[0] <<= xStream
;
570 aArgs
[1] <<= true; // do not create copy
571 uno::Reference
< container::XNameContainer
> xNameContainer(
572 m_xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
573 "com.sun.star.embed.OLESimpleStorage",
577 if ( xNameContainer
.is() )
579 for ( sal_uInt8 nInd
= 0; nInd
< 10 && !bExists
; nInd
++ )
581 OUString aStreamName
= "\002OlePres00" + OUString::number( nInd
);
584 bExists
= xNameContainer
->hasByName( aStreamName
);
586 catch( const uno::Exception
& )
591 SetVisReplInStream( bExists
);
596 return m_bVisReplInStream
;
600 uno::Reference
< io::XStream
> OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation_Impl(
601 const uno::Reference
< io::XStream
>& xStream
,
602 bool bAllowToRepair50
)
605 uno::Reference
< io::XStream
> xResult
;
609 SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation, retrieving" );
611 uno::Reference
< container::XNameContainer
> xNameContainer
;
612 uno::Sequence
< uno::Any
> aArgs( 2 );
613 aArgs
[0] <<= xStream
;
614 aArgs
[1] <<= true; // do not create copy
618 m_xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
619 "com.sun.star.embed.OLESimpleStorage",
623 catch( const uno::Exception
& )
626 if ( xNameContainer
.is() )
628 for ( sal_uInt8 nInd
= 0; nInd
< 10; nInd
++ )
630 OUString aStreamName
= "\002OlePres00" + OUString::number( nInd
);
631 uno::Reference
< io::XStream
> xCachedCopyStream
;
634 if ( ( xNameContainer
->getByName( aStreamName
) >>= xCachedCopyStream
) && xCachedCopyStream
.is() )
636 xResult
= TryToGetAcceptableFormat_Impl( xCachedCopyStream
);
641 catch( const uno::Exception
& )
646 // to be compatible with the old versions Ole10Native is checked after OlePress000
647 aStreamName
= "\001Ole10Native";
650 if ( ( xNameContainer
->getByName( aStreamName
) >>= xCachedCopyStream
) && xCachedCopyStream
.is() )
652 xResult
= TryToGetAcceptableFormat_Impl( xCachedCopyStream
);
657 catch( const uno::Exception
& )
664 if ( bAllowToRepair50
&& !xResult
.is() )
666 OUString
aOrigContName( "Ole-Object" );
667 if ( xNameContainer
->hasByName( aOrigContName
) )
669 uno::Reference
< embed::XClassifiedObject
> xClassified( xNameContainer
, uno::UNO_QUERY_THROW
);
670 if ( MimeConfigurationHelper::ClassIDsEqual( xClassified
->getClassID(), MimeConfigurationHelper::GetSequenceClassID( SO3_OUT_CLASSID
) ) )
672 // this is an OLE object wrongly stored in 5.0 format
673 // this object must be repaired since SO7 has done it
675 uno::Reference
< io::XOutputStream
> xOutputStream
= xStream
->getOutputStream();
676 uno::Reference
< io::XTruncate
> xTruncate( xOutputStream
, uno::UNO_QUERY_THROW
);
678 uno::Reference
< io::XInputStream
> xOrigInputStream
;
679 if ( ( xNameContainer
->getByName( aOrigContName
) >>= xOrigInputStream
)
680 && xOrigInputStream
.is() )
682 // the provided input stream must be based on temporary medium and must be independent
683 // from the stream the storage is based on
684 uno::Reference
< io::XSeekable
> xOrigSeekable( xOrigInputStream
, uno::UNO_QUERY
);
685 if ( xOrigSeekable
.is() )
686 xOrigSeekable
->seek( 0 );
688 uno::Reference
< lang::XComponent
> xNameContDisp( xNameContainer
, uno::UNO_QUERY_THROW
);
689 xNameContDisp
->dispose(); // free the original stream
691 xTruncate
->truncate();
692 ::comphelper::OStorageHelper::CopyInputToOutput( xOrigInputStream
, xOutputStream
);
693 xOutputStream
->flush();
695 if ( xStream
== m_xObjectStream
)
697 if ( !m_aTempURL
.isEmpty() )
699 // this is the own stream, so the temporary URL must be cleaned if it exists
700 KillFile_Impl( m_aTempURL
, m_xContext
);
705 // retry to create the component after recovering
710 CreateOleComponentAndLoad_Impl();
711 m_aClassID
= m_pOleComponent
->GetCLSID(); // was not set during construction
713 catch( const uno::Exception
& )
720 xResult
= TryToRetrieveCachedVisualRepresentation_Impl( xStream
);
726 catch( const uno::Exception
& )
735 void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
736 const uno::Reference
< io::XStream
>& xNewObjectStream
,
737 const OUString
& aNewName
)
739 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
741 SAL_WARN_IF( xNewObjectStream
!= m_xObjectStream
, "embeddedobj.ole", "The streams must be the same!" );
746 uno::Reference
< lang::XComponent
> xComponent( m_xObjectStream
, uno::UNO_QUERY
);
747 OSL_ENSURE( !m_xObjectStream
.is() || xComponent
.is(), "Wrong stream implementation!" );
748 if ( xComponent
.is() )
749 xComponent
->dispose();
751 catch ( const uno::Exception
& )
755 m_xObjectStream
= xNewObjectStream
;
756 m_xParentStorage
= xNewParentStorage
;
757 m_aEntryName
= aNewName
;
761 void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference
< embed::XStorage
>& xNewParentStorage
,
762 const OUString
& aNewName
)
764 if ( xNewParentStorage
== m_xParentStorage
&& aNewName
== m_aEntryName
)
767 sal_Int32 nStreamMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
769 uno::Reference
< io::XStream
> xNewOwnStream
= xNewParentStorage
->openStreamElement( aNewName
, nStreamMode
);
770 SAL_WARN_IF( !xNewOwnStream
.is(), "embeddedobj.ole", "The method can not return empty reference!" );
772 SwitchOwnPersistence( xNewParentStorage
, xNewOwnStream
, aNewName
);
777 bool OleEmbeddedObject::SaveObject_Impl()
779 bool bResult
= false;
781 if ( m_xClientSite
.is() )
785 m_xClientSite
->saveObject();
788 catch( const uno::Exception
& )
797 bool OleEmbeddedObject::OnShowWindow_Impl( bool bShow
)
799 osl::ClearableMutexGuard
aGuard(m_aMutex
);
801 bool bResult
= false;
803 SAL_WARN_IF( m_nObjectState
== -1, "embeddedobj.ole", "The object has no persistence!" );
804 SAL_WARN_IF( m_nObjectState
== embed::EmbedStates::LOADED
, "embeddedobj.ole", "The object get OnShowWindow in loaded state!" );
805 if ( m_nObjectState
== -1 || m_nObjectState
== embed::EmbedStates::LOADED
)
808 // the object is either activated or deactivated
809 sal_Int32 nOldState
= m_nObjectState
;
810 if ( bShow
&& m_nObjectState
== embed::EmbedStates::RUNNING
)
812 m_nObjectState
= embed::EmbedStates::ACTIVE
;
813 m_aVerbExecutionController
.ObjectIsActive();
816 StateChangeNotification_Impl( false, nOldState
, m_nObjectState
);
818 else if ( !bShow
&& m_nObjectState
== embed::EmbedStates::ACTIVE
)
820 m_nObjectState
= embed::EmbedStates::RUNNING
;
822 StateChangeNotification_Impl( false, nOldState
, m_nObjectState
);
825 if ( m_xClientSite
.is() )
829 m_xClientSite
->visibilityChanged( bShow
);
832 catch( const uno::Exception
& )
841 void OleEmbeddedObject::OnIconChanged_Impl()
843 // TODO/LATER: currently this notification seems to be impossible
844 // MakeEventListenerNotification_Impl( OUString( "OnIconChanged" ) );
848 void OleEmbeddedObject::OnViewChanged_Impl()
851 throw lang::DisposedException();
853 // For performance reasons the notification currently is ignored, STAMPIT object is the exception,
854 // it can never be active and never call SaveObject, so it is the only way to detect that it is changed
856 // ==== the STAMPIT related solution =============================
857 // the following variable is used to detect whether the object was modified during verb execution
858 m_aVerbExecutionController
.ModificationNotificationIsDone();
860 // The following things are controlled by VerbExecutionController:
861 // - if the verb execution is in progress and the view is changed the object will be stored
862 // after the execution, so there is no need to send the notification.
863 // - the STAMPIT object can never be active.
864 if (m_aVerbExecutionController
.CanDoNotification() &&
865 m_pOleComponent
&& m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
&&
866 (MimeConfigurationHelper::ClassIDsEqual(m_aClassID
, MimeConfigurationHelper::GetSequenceClassID(0x852ee1c9, 0x9058, 0x44ba, 0x8c, 0x6c, 0x0c, 0x5f, 0xc6, 0x6b, 0xdb, 0x8d)) ||
867 MimeConfigurationHelper::ClassIDsEqual(m_aClassID
, MimeConfigurationHelper::GetSequenceClassID(0xcf1b4491, 0xbea3, 0x4c9f, 0xa7, 0x0f, 0x22, 0x1b, 0x1e, 0xca, 0xef, 0x3e)))
870 // The view is changed while the object is in running state, save the new object
871 m_xCachedVisualRepresentation
.clear();
873 MakeEventListenerNotification_Impl( "OnVisAreaChanged" );
879 void OleEmbeddedObject::OnClosed_Impl()
882 throw lang::DisposedException();
884 if ( m_nObjectState
!= embed::EmbedStates::LOADED
)
886 sal_Int32 nOldState
= m_nObjectState
;
887 m_nObjectState
= embed::EmbedStates::LOADED
;
888 StateChangeNotification_Impl( false, nOldState
, m_nObjectState
);
893 OUString
OleEmbeddedObject::CreateTempURLEmpty_Impl()
895 SAL_WARN_IF( !m_aTempURL
.isEmpty(), "embeddedobj.ole", "The object has already the temporary file!" );
896 m_aTempURL
= GetNewTempFileURL_Impl( m_xContext
);
902 OUString
OleEmbeddedObject::GetTempURL_Impl()
904 if ( m_aTempURL
.isEmpty() )
906 SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::GetTempURL_Impl, tempfile creation" );
908 // if there is no temporary file, it will be created from the own entry
909 uno::Reference
< embed::XOptimizedStorage
> xOptParStorage( m_xParentStorage
, uno::UNO_QUERY
);
910 if ( xOptParStorage
.is() )
912 m_aTempURL
= GetNewFilledTempFile_Impl( xOptParStorage
, m_aEntryName
, m_xContext
);
914 else if ( m_xObjectStream
.is() )
916 // load object from the stream
917 uno::Reference
< io::XInputStream
> xInStream
= m_xObjectStream
->getInputStream();
918 if ( !xInStream
.is() )
919 throw io::IOException(); // TODO: access denied
921 m_aTempURL
= GetNewFilledTempFile_Impl( xInStream
, m_xContext
);
929 void OleEmbeddedObject::CreateOleComponent_Impl( OleComponent
* pOleComponent
)
931 if ( !m_pOleComponent
)
933 m_pOleComponent
= pOleComponent
? pOleComponent
: new OleComponent( m_xContext
, this );
934 m_pOleComponent
->acquire(); // TODO: needs holder?
936 if ( !m_xClosePreventer
.is() )
937 m_xClosePreventer
.set( static_cast< ::cppu::OWeakObject
* >( new OClosePreventer
),
940 m_pOleComponent
->addCloseListener( m_xClosePreventer
);
945 void OleEmbeddedObject::CreateOleComponentAndLoad_Impl( OleComponent
* pOleComponent
)
947 if ( !m_pOleComponent
)
949 if ( !m_xObjectStream
.is() )
950 throw uno::RuntimeException();
952 CreateOleComponent_Impl( pOleComponent
);
954 // after the loading the object can appear as a link
955 // will be detected later by olecomponent
958 if ( m_aTempURL
.isEmpty() )
959 throw uno::RuntimeException(); // TODO
961 m_pOleComponent
->LoadEmbeddedObject( m_aTempURL
);
966 void OleEmbeddedObject::CreateOleComponentFromClipboard_Impl( OleComponent
* pOleComponent
)
968 if ( !m_pOleComponent
)
970 if ( !m_xObjectStream
.is() )
971 throw uno::RuntimeException();
973 CreateOleComponent_Impl( pOleComponent
);
975 // after the loading the object can appear as a link
976 // will be detected later by olecomponent
977 m_pOleComponent
->CreateObjectFromClipboard();
982 uno::Reference
< io::XOutputStream
> OleEmbeddedObject::GetStreamForSaving()
984 if ( !m_xObjectStream
.is() )
985 throw uno::RuntimeException(); //TODO:
987 uno::Reference
< io::XOutputStream
> xOutStream
= m_xObjectStream
->getOutputStream();
988 if ( !xOutStream
.is() )
989 throw io::IOException(); //TODO: access denied
991 uno::Reference
< io::XTruncate
> xTruncate( xOutStream
, uno::UNO_QUERY_THROW
);
992 xTruncate
->truncate();
998 void OleEmbeddedObject::StoreObjectToStream( uno::Reference
< io::XOutputStream
> const & xOutStream
)
1000 // this method should be used only on windows
1001 if ( m_pOleComponent
)
1002 m_pOleComponent
->StoreOwnTmpIfNecessary();
1004 // now all the changes should be in temporary location
1005 if ( m_aTempURL
.isEmpty() )
1006 throw uno::RuntimeException();
1008 // open temporary file for reading
1009 uno::Reference
< ucb::XSimpleFileAccess3
> xTempAccess(
1010 ucb::SimpleFileAccess::create( m_xContext
) );
1012 uno::Reference
< io::XInputStream
> xTempInStream
= xTempAccess
->openFileRead( m_aTempURL
);
1013 SAL_WARN_IF( !xTempInStream
.is(), "embeddedobj.ole", "The object's temporary file can not be reopened for reading!" );
1015 // TODO: use bStoreVisReplace
1017 if ( !xTempInStream
.is() )
1019 throw io::IOException(); // TODO:
1022 // write all the contents to XOutStream
1023 uno::Reference
< io::XTruncate
> xTrunc( xOutStream
, uno::UNO_QUERY_THROW
);
1026 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream
, xOutStream
);
1028 // TODO: should the view replacement be in the stream ???
1029 // probably it must be specified on storing
1033 void OleEmbeddedObject::StoreToLocation_Impl(
1034 const uno::Reference
< embed::XStorage
>& xStorage
,
1035 const OUString
& sEntName
,
1036 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
,
1039 // TODO: use lObjArgs
1040 // TODO: exchange StoreVisualReplacement by SO file format version?
1042 if ( m_nObjectState
== -1 )
1044 // the object is still not loaded
1045 throw embed::WrongStateException( "Can't store object without persistence!",
1046 static_cast< ::cppu::OWeakObject
* >(this) );
1049 if ( m_bWaitSaveCompleted
)
1050 throw embed::WrongStateException(
1051 "The object waits for saveCompleted() call!",
1052 static_cast< ::cppu::OWeakObject
* >(this) );
1054 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStream
.is(), "The object has no valid persistence!" );
1056 bool bVisReplIsStored
= false;
1058 bool bTryOptimization
= false;
1059 bool bStoreVis
= m_bStoreVisRepl
;
1060 uno::Reference
< io::XStream
> xCachedVisualRepresentation
;
1061 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1063 if ( prop
.Name
== "StoreVisualReplacement" )
1064 prop
.Value
>>= bStoreVis
;
1065 else if ( prop
.Name
== "VisualReplacement" )
1066 prop
.Value
>>= xCachedVisualRepresentation
;
1067 else if ( prop
.Name
== "CanTryOptimization" )
1068 prop
.Value
>>= bTryOptimization
;
1071 // ignore visual representation provided from outside if it should not be stored
1073 xCachedVisualRepresentation
.clear();
1075 if ( bStoreVis
&& !HasVisReplInStream() && !xCachedVisualRepresentation
.is() )
1076 throw io::IOException(); // TODO: there is no cached visual representation and nothing is provided from outside
1078 // if the representation is provided from outside it should be copied to a local stream
1079 bool bNeedLocalCache
= xCachedVisualRepresentation
.is();
1081 uno::Reference
< io::XStream
> xTargetStream
;
1083 bool bStoreLoaded
= false;
1084 if ( m_nObjectState
== embed::EmbedStates::LOADED
1086 // if the object was NOT modified after storing it can be just copied
1087 // as if it was in loaded state
1088 || ( m_pOleComponent
&& !m_pOleComponent
->IsDirty() )
1092 bool bOptimizedCopyingDone
= false;
1094 if ( bTryOptimization
&& bStoreVis
== HasVisReplInStream() )
1098 uno::Reference
< embed::XOptimizedStorage
> xSourceOptStor( m_xParentStorage
, uno::UNO_QUERY_THROW
);
1099 uno::Reference
< embed::XOptimizedStorage
> xTargetOptStor( xStorage
, uno::UNO_QUERY_THROW
);
1100 xSourceOptStor
->copyElementDirectlyTo( m_aEntryName
, xTargetOptStor
, sEntName
);
1101 bOptimizedCopyingDone
= true;
1103 catch( const uno::Exception
& )
1108 if ( !bOptimizedCopyingDone
)
1110 // if optimized copying fails a normal one should be tried
1111 m_xParentStorage
->copyElementTo( m_aEntryName
, xStorage
, sEntName
);
1114 // the locally retrieved representation is always preferable
1115 // since the object is in loaded state the representation is unchanged
1116 if ( m_xCachedVisualRepresentation
.is() )
1118 xCachedVisualRepresentation
= m_xCachedVisualRepresentation
;
1119 bNeedLocalCache
= false;
1122 bVisReplIsStored
= HasVisReplInStream();
1123 bStoreLoaded
= true;
1126 else if ( m_pOleComponent
)
1129 xStorage
->openStreamElement( sEntName
, embed::ElementModes::READWRITE
);
1130 if ( !xTargetStream
.is() )
1131 throw io::IOException(); //TODO: access denied
1133 SetStreamMediaType_Impl( xTargetStream
, "application/vnd.sun.star.oleobject" );
1134 uno::Reference
< io::XOutputStream
> xOutStream
= xTargetStream
->getOutputStream();
1135 if ( !xOutStream
.is() )
1136 throw io::IOException(); //TODO: access denied
1138 StoreObjectToStream( xOutStream
);
1139 bVisReplIsStored
= true;
1143 // no need to do it on StoreTo since in this case the replacement is in the stream
1144 // and there is no need to cache it even if it is thrown away because the object
1145 // is not changed by StoreTo action
1147 uno::Reference
< io::XStream
> xTmpCVRepresentation
=
1148 TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream
);
1150 // the locally retrieved representation is always preferable
1151 if ( xTmpCVRepresentation
.is() )
1153 xCachedVisualRepresentation
= xTmpCVRepresentation
;
1154 bNeedLocalCache
= false;
1159 else if (true) // loplugin:flatten
1161 throw io::IOException(); // TODO
1164 if ( !xTargetStream
.is() )
1167 xStorage
->openStreamElement( sEntName
, embed::ElementModes::READWRITE
);
1168 if ( !xTargetStream
.is() )
1169 throw io::IOException(); //TODO: access denied
1172 LetCommonStoragePassBeUsed_Impl( xTargetStream
);
1174 if ( bStoreVis
!= bVisReplIsStored
)
1178 if ( !xCachedVisualRepresentation
.is() )
1179 xCachedVisualRepresentation
= TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream
);
1181 SAL_WARN_IF( !xCachedVisualRepresentation
.is(), "embeddedobj.ole", "No representation is available!" );
1183 // the following copying will be done in case it is SaveAs anyway
1184 // if it is not SaveAs the seekable access is not required currently
1185 // TODO/LATER: may be required in future
1188 uno::Reference
< io::XSeekable
> xCachedSeek( xCachedVisualRepresentation
, uno::UNO_QUERY
);
1189 if ( !xCachedSeek
.is() )
1191 xCachedVisualRepresentation
1192 = GetNewFilledTempStream_Impl( xCachedVisualRepresentation
->getInputStream() );
1193 bNeedLocalCache
= false;
1197 InsertVisualCache_Impl( xTargetStream
, xCachedVisualRepresentation
);
1201 // the removed representation could be cached by this method
1202 if ( !xCachedVisualRepresentation
.is() )
1203 xCachedVisualRepresentation
= TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream
);
1205 if (!m_bStreamReadOnly
)
1206 RemoveVisualCache_Impl(xTargetStream
);
1212 m_bWaitSaveCompleted
= true;
1213 m_xNewObjectStream
= xTargetStream
;
1214 m_xNewParentStorage
= xStorage
;
1215 m_aNewEntryName
= sEntName
;
1216 m_bNewVisReplInStream
= bStoreVis
;
1217 m_bStoreLoaded
= bStoreLoaded
;
1219 if ( xCachedVisualRepresentation
.is() )
1221 if ( bNeedLocalCache
)
1222 m_xNewCachedVisRepl
= GetNewFilledTempStream_Impl( xCachedVisualRepresentation
->getInputStream() );
1224 m_xNewCachedVisRepl
= xCachedVisualRepresentation
;
1227 // TODO: register listeners for storages above, in case they are disposed
1228 // an exception will be thrown on saveCompleted( true )
1232 uno::Reference
< lang::XComponent
> xComp( xTargetStream
, uno::UNO_QUERY
);
1237 } catch( const uno::Exception
& )
1245 void SAL_CALL
OleEmbeddedObject::setPersistentEntry(
1246 const uno::Reference
< embed::XStorage
>& xStorage
,
1247 const OUString
& sEntName
,
1248 sal_Int32 nEntryConnectionMode
,
1249 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1250 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1252 // begin wrapping related part ====================
1253 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1254 if ( xWrappedObject
.is() )
1256 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1257 xWrappedObject
->setPersistentEntry( xStorage
, sEntName
, nEntryConnectionMode
, lArguments
, lObjArgs
);
1260 // end wrapping related part ====================
1262 // TODO: use lObjArgs
1264 // the type of the object must be already set
1265 // a kind of typedetection should be done in the factory;
1266 // the only exception is object initialized from a stream,
1267 // the class ID will be detected from the stream
1269 ::osl::MutexGuard
aGuard( m_aMutex
);
1271 throw lang::DisposedException(); // TODO
1273 if ( !xStorage
.is() )
1274 throw lang::IllegalArgumentException( "No parent storage is provided!",
1275 static_cast< ::cppu::OWeakObject
* >(this),
1278 if ( sEntName
.isEmpty() )
1279 throw lang::IllegalArgumentException( "Empty element name is provided!",
1280 static_cast< ::cppu::OWeakObject
* >(this),
1283 // May be LOADED should be forbidden here ???
1284 if ( ( m_nObjectState
!= -1 || nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
1285 && ( m_nObjectState
== -1 || nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
) )
1287 // if the object is not loaded
1288 // it can not get persistent representation without initialization
1290 // if the object is loaded
1291 // it can switch persistent representation only without initialization
1293 throw embed::WrongStateException(
1294 "Can't change persistent representation of activated object!",
1295 static_cast< ::cppu::OWeakObject
* >(this) );
1298 if ( m_bWaitSaveCompleted
)
1300 if ( nEntryConnectionMode
!= embed::EntryInitModes::NO_INIT
)
1301 throw embed::WrongStateException(
1302 "The object waits for saveCompleted() call!",
1303 static_cast< ::cppu::OWeakObject
* >(this) );
1304 saveCompleted( m_xParentStorage
!= xStorage
|| m_aEntryName
!= sEntName
);
1307 uno::Reference
< container::XNameAccess
> xNameAccess( xStorage
, uno::UNO_QUERY_THROW
);
1309 // detect entry existence
1310 bool bElExists
= xNameAccess
->hasByName( sEntName
);
1312 m_bReadOnly
= false;
1313 for ( beans::PropertyValue
const & prop
: lArguments
)
1314 if ( prop
.Name
== "ReadOnly" )
1315 prop
.Value
>>= m_bReadOnly
;
1318 sal_Int32 nStorageMode
= m_bReadOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
;
1321 SwitchOwnPersistence( xStorage
, sEntName
);
1323 for ( beans::PropertyValue
const & prop
: lObjArgs
)
1324 if ( prop
.Name
== "StoreVisualReplacement" )
1325 prop
.Value
>>= m_bStoreVisRepl
;
1328 if ( nEntryConnectionMode
== embed::EntryInitModes::DEFAULT_INIT
)
1330 if ( m_bFromClipboard
)
1332 // the object should be initialized from clipboard
1333 // impossibility to initialize the object means error here
1334 CreateOleComponentFromClipboard_Impl();
1335 m_aClassID
= m_pOleComponent
->GetCLSID(); // was not set during construction
1336 m_pOleComponent
->RunObject();
1337 m_nObjectState
= embed::EmbedStates::RUNNING
;
1339 else if ( bElExists
)
1341 // load object from the stream
1342 // after the loading the object can appear as a link
1343 // will be detected by olecomponent
1346 CreateOleComponentAndLoad_Impl();
1347 m_aClassID
= m_pOleComponent
->GetCLSID(); // was not set during construction
1349 catch( const uno::Exception
& )
1351 // TODO/LATER: detect classID of the object if possible
1352 // means that the object inprocess server could not be successfully instantiated
1353 GetRidOfComponent();
1356 m_nObjectState
= embed::EmbedStates::LOADED
;
1360 // create a new object
1361 CreateOleComponent_Impl();
1362 m_pOleComponent
->CreateNewEmbeddedObject( m_aClassID
);
1363 m_pOleComponent
->RunObject();
1364 m_nObjectState
= embed::EmbedStates::RUNNING
;
1369 if ( ( nStorageMode
& embed::ElementModes::READWRITE
) != embed::ElementModes::READWRITE
)
1370 throw io::IOException();
1372 if ( nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
1374 // the document just already changed its stream to store to;
1375 // the links to OLE documents switch their persistence in the same way
1376 // as normal embedded objects
1378 else if ( nEntryConnectionMode
== embed::EntryInitModes::TRUNCATE_INIT
)
1380 // create a new object, that will be stored in specified stream
1381 CreateOleComponent_Impl();
1383 m_pOleComponent
->CreateNewEmbeddedObject( m_aClassID
);
1384 m_pOleComponent
->RunObject();
1385 m_nObjectState
= embed::EmbedStates::RUNNING
;
1387 else if ( nEntryConnectionMode
== embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT
)
1389 // use URL ( may be content or stream later ) from MediaDescriptor to initialize object
1391 for ( beans::PropertyValue
const & prop
: lArguments
)
1392 if ( prop
.Name
== "URL" )
1393 prop
.Value
>>= aURL
;
1395 if ( aURL
.isEmpty() )
1396 throw lang::IllegalArgumentException(
1397 "Empty URL is provided in the media descriptor!",
1398 static_cast< ::cppu::OWeakObject
* >(this),
1401 CreateOleComponent_Impl();
1403 // TODO: the m_bIsLink value must be set already
1405 m_pOleComponent
->CreateObjectFromFile( aURL
);
1407 m_pOleComponent
->CreateLinkFromFile( aURL
);
1409 m_pOleComponent
->RunObject();
1410 m_aClassID
= m_pOleComponent
->GetCLSID(); // was not set during construction
1412 m_nObjectState
= embed::EmbedStates::RUNNING
;
1414 //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1419 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1420 static_cast< ::cppu::OWeakObject
* >(this),
1424 // On Unix the OLE object can not do anything except storing itself somewhere
1425 if ( nEntryConnectionMode
== embed::EntryInitModes::DEFAULT_INIT
&& bElExists
)
1427 // TODO/LATER: detect classID of the object
1428 // can be a real problem for the links
1430 m_nObjectState
= embed::EmbedStates::LOADED
;
1432 else if ( nEntryConnectionMode
== embed::EntryInitModes::NO_INIT
)
1434 // do nothing, the object has already switched it's persistence
1437 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1438 static_cast< ::cppu::OWeakObject
* >(this),
1445 void SAL_CALL
OleEmbeddedObject::storeToEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1446 const OUString
& sEntName
,
1447 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1448 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1450 // begin wrapping related part ====================
1451 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1452 if ( xWrappedObject
.is() )
1454 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1455 xWrappedObject
->storeToEntry( xStorage
, sEntName
, lArguments
, lObjArgs
);
1458 // end wrapping related part ====================
1460 ::osl::MutexGuard
aGuard( m_aMutex
);
1462 throw lang::DisposedException(); // TODO
1464 VerbExecutionControllerGuard
aVerbGuard( m_aVerbExecutionController
);
1466 StoreToLocation_Impl( xStorage
, sEntName
, lObjArgs
, false );
1468 // TODO: should the listener notification be done?
1472 void SAL_CALL
OleEmbeddedObject::storeAsEntry( const uno::Reference
< embed::XStorage
>& xStorage
,
1473 const OUString
& sEntName
,
1474 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1475 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1477 // begin wrapping related part ====================
1478 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1479 if ( xWrappedObject
.is() )
1481 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1482 xWrappedObject
->storeAsEntry( xStorage
, sEntName
, lArguments
, lObjArgs
);
1485 // end wrapping related part ====================
1487 ::osl::MutexGuard
aGuard( m_aMutex
);
1489 throw lang::DisposedException(); // TODO
1491 VerbExecutionControllerGuard
aVerbGuard( m_aVerbExecutionController
);
1493 StoreToLocation_Impl( xStorage
, sEntName
, lObjArgs
, true );
1495 // TODO: should the listener notification be done here or in saveCompleted?
1499 void SAL_CALL
OleEmbeddedObject::saveCompleted( sal_Bool bUseNew
)
1501 // begin wrapping related part ====================
1502 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1503 if ( xWrappedObject
.is() )
1505 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1506 xWrappedObject
->saveCompleted( bUseNew
);
1509 // end wrapping related part ====================
1511 osl::ClearableMutexGuard
aGuard(m_aMutex
);
1513 throw lang::DisposedException(); // TODO
1515 if ( m_nObjectState
== -1 )
1517 // the object is still not loaded
1518 throw embed::WrongStateException( "Can't store object without persistence!",
1519 static_cast< ::cppu::OWeakObject
* >(this) );
1522 // it is allowed to call saveCompleted( false ) for nonstored objects
1523 if ( !m_bWaitSaveCompleted
&& !bUseNew
)
1526 SAL_WARN_IF( !m_bWaitSaveCompleted
, "embeddedobj.ole", "Unexpected saveCompleted() call!" );
1527 if ( !m_bWaitSaveCompleted
)
1528 throw io::IOException(); // TODO: illegal call
1530 OSL_ENSURE( m_xNewObjectStream
.is() && m_xNewParentStorage
.is() , "Internal object information is broken!" );
1531 if ( !m_xNewObjectStream
.is() || !m_xNewParentStorage
.is() )
1532 throw uno::RuntimeException(); // TODO: broken internal information
1536 SwitchOwnPersistence( m_xNewParentStorage
, m_xNewObjectStream
, m_aNewEntryName
);
1537 m_bStoreVisRepl
= m_bNewVisReplInStream
;
1538 SetVisReplInStream( m_bNewVisReplInStream
);
1539 m_xCachedVisualRepresentation
= m_xNewCachedVisRepl
;
1543 // close remembered stream
1545 uno::Reference
< lang::XComponent
> xComponent( m_xNewObjectStream
, uno::UNO_QUERY
);
1546 SAL_WARN_IF( !xComponent
.is(), "embeddedobj.ole", "Wrong storage implementation!" );
1547 if ( xComponent
.is() )
1548 xComponent
->dispose();
1550 catch ( const uno::Exception
& )
1555 bool bStoreLoaded
= m_bStoreLoaded
;
1557 m_xNewObjectStream
.clear();
1558 m_xNewParentStorage
.clear();
1559 m_aNewEntryName
.clear();
1560 m_bWaitSaveCompleted
= false;
1561 m_bNewVisReplInStream
= false;
1562 m_xNewCachedVisRepl
.clear();
1563 m_bStoreLoaded
= false;
1565 if ( bUseNew
&& m_pOleComponent
&& m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
&& !bStoreLoaded
1566 && m_nObjectState
!= embed::EmbedStates::LOADED
)
1568 // the object replacement image should be updated, so the cached size as well
1569 m_bHasCachedSize
= false;
1572 // the call will cache the size in case of success
1573 // probably it might need to be done earlier, while the object is in active state
1574 getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
1576 catch( const uno::Exception
& )
1583 MakeEventListenerNotification_Impl( "OnSaveAsDone");
1585 // the object can be changed only on windows
1586 // the notification should be done only if the object is not in loaded state
1587 if ( m_pOleComponent
&& m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
&& !bStoreLoaded
)
1589 MakeEventListenerNotification_Impl( "OnVisAreaChanged");
1595 sal_Bool SAL_CALL
OleEmbeddedObject::hasEntry()
1597 // begin wrapping related part ====================
1598 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1599 if ( xWrappedObject
.is() )
1601 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1602 return xWrappedObject
->hasEntry();
1604 // end wrapping related part ====================
1606 ::osl::MutexGuard
aGuard( m_aMutex
);
1608 throw lang::DisposedException(); // TODO
1610 if ( m_bWaitSaveCompleted
)
1611 throw embed::WrongStateException(
1612 "The object waits for saveCompleted() call!",
1613 static_cast< ::cppu::OWeakObject
* >(this) );
1615 if ( m_xObjectStream
.is() )
1622 OUString SAL_CALL
OleEmbeddedObject::getEntryName()
1624 // begin wrapping related part ====================
1625 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1626 if ( xWrappedObject
.is() )
1628 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1629 return xWrappedObject
->getEntryName();
1631 // end wrapping related part ====================
1633 ::osl::MutexGuard
aGuard( m_aMutex
);
1635 throw lang::DisposedException(); // TODO
1637 if ( m_nObjectState
== -1 )
1639 // the object is still not loaded
1640 throw embed::WrongStateException( "The object persistence is not initialized!",
1641 static_cast< ::cppu::OWeakObject
* >(this) );
1644 if ( m_bWaitSaveCompleted
)
1645 throw embed::WrongStateException(
1646 "The object waits for saveCompleted() call!",
1647 static_cast< ::cppu::OWeakObject
* >(this) );
1649 return m_aEntryName
;
1653 void SAL_CALL
OleEmbeddedObject::storeOwn()
1655 // begin wrapping related part ====================
1656 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1657 if ( xWrappedObject
.is() )
1659 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1660 xWrappedObject
->storeOwn();
1663 // end wrapping related part ====================
1665 // during switching from Activated to Running and from Running to Loaded states the object will
1666 // ask container to store the object, the container has to make decision
1669 osl::ClearableMutexGuard
aGuard(m_aMutex
);
1671 throw lang::DisposedException(); // TODO
1673 VerbExecutionControllerGuard
aVerbGuard( m_aVerbExecutionController
);
1675 if ( m_nObjectState
== -1 )
1677 // the object is still not loaded
1678 throw embed::WrongStateException( "Can't store object without persistence!",
1679 static_cast< ::cppu::OWeakObject
* >(this) );
1682 if ( m_bWaitSaveCompleted
)
1683 throw embed::WrongStateException(
1684 "The object waits for saveCompleted() call!",
1685 static_cast< ::cppu::OWeakObject
* >(this) );
1688 throw io::IOException(); // TODO: access denied
1690 LetCommonStoragePassBeUsed_Impl( m_xObjectStream
);
1692 bool bStoreLoaded
= true;
1695 if ( m_nObjectState
!= embed::EmbedStates::LOADED
&& m_pOleComponent
&& m_pOleComponent
->IsDirty() )
1697 bStoreLoaded
= false;
1699 OSL_ENSURE( m_xParentStorage
.is() && m_xObjectStream
.is(), "The object has no valid persistence!" );
1701 if ( !m_xObjectStream
.is() )
1702 throw io::IOException(); //TODO: access denied
1704 SetStreamMediaType_Impl( m_xObjectStream
, "application/vnd.sun.star.oleobject" );
1705 uno::Reference
< io::XOutputStream
> xOutStream
= m_xObjectStream
->getOutputStream();
1706 if ( !xOutStream
.is() )
1707 throw io::IOException(); //TODO: access denied
1709 // TODO: does this work for links too?
1710 StoreObjectToStream( GetStreamForSaving() );
1712 // the replacement is changed probably, and it must be in the object stream
1713 if ( !m_pOleComponent
->IsWorkaroundActive() )
1714 m_xCachedVisualRepresentation
.clear();
1715 SetVisReplInStream( true );
1719 if ( m_bStoreVisRepl
!= HasVisReplInStream() )
1721 if ( m_bStoreVisRepl
)
1723 // the m_xCachedVisualRepresentation must be set or it should be already stored
1724 if ( m_xCachedVisualRepresentation
.is() )
1725 InsertVisualCache_Impl( m_xObjectStream
, m_xCachedVisualRepresentation
);
1728 m_xCachedVisualRepresentation
= TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream
);
1729 SAL_WARN_IF( !m_xCachedVisualRepresentation
.is(), "embeddedobj.ole", "No representation is available!" );
1734 if ( !m_xCachedVisualRepresentation
.is() )
1735 m_xCachedVisualRepresentation
= TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream
);
1736 RemoveVisualCache_Impl( m_xObjectStream
);
1739 SetVisReplInStream( m_bStoreVisRepl
);
1742 if ( m_pOleComponent
&& m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
&& !bStoreLoaded
)
1744 // the object replacement image should be updated, so the cached size as well
1745 m_bHasCachedSize
= false;
1748 // the call will cache the size in case of success
1749 // probably it might need to be done earlier, while the object is in active state
1750 getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
1752 catch( const uno::Exception
& )
1758 MakeEventListenerNotification_Impl( "OnSaveDone");
1760 // the object can be changed only on Windows
1761 // the notification should be done only if the object is not in loaded state
1762 if ( m_pOleComponent
&& m_nUpdateMode
== embed::EmbedUpdateModes::ALWAYS_UPDATE
&& !bStoreLoaded
)
1763 MakeEventListenerNotification_Impl( "OnVisAreaChanged");
1767 sal_Bool SAL_CALL
OleEmbeddedObject::isReadonly()
1769 // begin wrapping related part ====================
1770 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1771 if ( xWrappedObject
.is() )
1773 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1774 return xWrappedObject
->isReadonly();
1776 // end wrapping related part ====================
1778 ::osl::MutexGuard
aGuard( m_aMutex
);
1780 throw lang::DisposedException(); // TODO
1782 if ( m_nObjectState
== -1 )
1784 // the object is still not loaded
1785 throw embed::WrongStateException( "The object persistence is not initialized!",
1786 static_cast< ::cppu::OWeakObject
* >(this) );
1789 if ( m_bWaitSaveCompleted
)
1790 throw embed::WrongStateException(
1791 "The object waits for saveCompleted() call!",
1792 static_cast< ::cppu::OWeakObject
* >(this) );
1798 void SAL_CALL
OleEmbeddedObject::reload(
1799 const uno::Sequence
< beans::PropertyValue
>& lArguments
,
1800 const uno::Sequence
< beans::PropertyValue
>& lObjArgs
)
1802 // begin wrapping related part ====================
1803 uno::Reference
< embed::XEmbedPersist
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1804 if ( xWrappedObject
.is() )
1806 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1807 xWrappedObject
->reload( lArguments
, lObjArgs
);
1810 // end wrapping related part ====================
1812 // TODO: use lObjArgs
1814 ::osl::MutexGuard
aGuard( m_aMutex
);
1816 throw lang::DisposedException(); // TODO
1818 if ( m_nObjectState
== -1 )
1820 // the object is still not loaded
1821 throw embed::WrongStateException( "The object persistence is not initialized!",
1822 static_cast< ::cppu::OWeakObject
* >(this) );
1825 if ( m_bWaitSaveCompleted
)
1826 throw embed::WrongStateException(
1827 "The object waits for saveCompleted() call!",
1828 static_cast< ::cppu::OWeakObject
* >(this) );
1831 // throw away current document
1832 // load new document from current storage
1833 // use meaningful part of lArguments
1837 void SAL_CALL
OleEmbeddedObject::breakLink( const uno::Reference
< embed::XStorage
>& xStorage
,
1838 const OUString
& sEntName
)
1840 // begin wrapping related part ====================
1841 uno::Reference
< embed::XLinkageSupport
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1842 if ( xWrappedObject
.is() )
1844 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1845 xWrappedObject
->breakLink( xStorage
, sEntName
);
1848 // end wrapping related part ====================
1850 ::osl::MutexGuard
aGuard( m_aMutex
);
1852 throw lang::DisposedException(); // TODO
1854 if ( !xStorage
.is() )
1855 throw lang::IllegalArgumentException( "No parent storage is provided!",
1856 static_cast< ::cppu::OWeakObject
* >(this),
1859 if ( sEntName
.isEmpty() )
1860 throw lang::IllegalArgumentException( "Empty element name is provided!",
1861 static_cast< ::cppu::OWeakObject
* >(this),
1864 // TODO: The object must be at least in Running state;
1865 if ( !m_bIsLink
|| m_nObjectState
== -1 || !m_pOleComponent
)
1867 // it must be a linked initialized object
1868 throw embed::WrongStateException(
1869 "The object is not a valid linked object!",
1870 static_cast< ::cppu::OWeakObject
* >(this) );
1874 throw io::IOException(); // TODO: Access denied
1876 if ( m_bWaitSaveCompleted
)
1877 throw embed::WrongStateException(
1878 "The object waits for saveCompleted() call!",
1879 static_cast< ::cppu::OWeakObject
* >(this) );
1883 // TODO: create an object based on the link
1885 // disconnect the old temporary URL
1886 OUString aOldTempURL
= m_aTempURL
;
1889 OleComponent
* pNewOleComponent
= new OleComponent(m_xContext
, this);
1891 pNewOleComponent
->InitEmbeddedCopyOfLink(m_pOleComponent
);
1893 catch (const uno::Exception
&)
1895 delete pNewOleComponent
;
1896 if (!m_aTempURL
.isEmpty())
1897 KillFile_Impl(m_aTempURL
, m_xContext
);
1898 m_aTempURL
= aOldTempURL
;
1903 GetRidOfComponent();
1905 catch (const uno::Exception
&)
1907 delete pNewOleComponent
;
1908 if (!m_aTempURL
.isEmpty())
1909 KillFile_Impl(m_aTempURL
, m_xContext
);
1910 m_aTempURL
= aOldTempURL
;
1914 KillFile_Impl(aOldTempURL
, m_xContext
);
1916 CreateOleComponent_Impl(pNewOleComponent
);
1918 if (m_xParentStorage
!= xStorage
|| !m_aEntryName
.equals(sEntName
))
1919 SwitchOwnPersistence(xStorage
, sEntName
);
1921 if (m_nObjectState
!= embed::EmbedStates::LOADED
)
1923 // TODO: should we activate the new object if the link was activated?
1925 const sal_Int32 nTargetState
= m_nObjectState
;
1926 m_nObjectState
= embed::EmbedStates::LOADED
;
1928 if (nTargetState
== embed::EmbedStates::RUNNING
)
1929 m_pOleComponent
->RunObject(); // the object already was in running state, the server must be installed
1930 else // nTargetState == embed::EmbedStates::ACTIVE
1932 m_pOleComponent
->RunObject(); // the object already was in running state, the server must be installed
1933 m_pOleComponent
->ExecuteVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN
);
1936 m_nObjectState
= nTargetState
;
1942 throw io::IOException(); //TODO:
1947 sal_Bool SAL_CALL
OleEmbeddedObject::isLink()
1949 // begin wrapping related part ====================
1950 uno::Reference
< embed::XLinkageSupport
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1951 if ( xWrappedObject
.is() )
1953 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1954 return xWrappedObject
->isLink();
1956 // end wrapping related part ====================
1958 ::osl::MutexGuard
aGuard( m_aMutex
);
1960 throw lang::DisposedException(); // TODO
1966 OUString SAL_CALL
OleEmbeddedObject::getLinkURL()
1968 // begin wrapping related part ====================
1969 uno::Reference
< embed::XLinkageSupport
> xWrappedObject( m_xWrappedObject
, uno::UNO_QUERY
);
1970 if ( xWrappedObject
.is() )
1972 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1973 return xWrappedObject
->getLinkURL();
1975 // end wrapping related part ====================
1977 ::osl::MutexGuard
aGuard( m_aMutex
);
1979 throw lang::DisposedException(); // TODO
1981 if ( m_bWaitSaveCompleted
)
1982 throw embed::WrongStateException(
1983 "The object waits for saveCompleted() call!",
1984 static_cast< ::cppu::OWeakObject
* >(this) );
1987 throw embed::WrongStateException(
1988 "The object is not a link object!",
1989 static_cast< ::cppu::OWeakObject
* >(this) );
1991 // TODO: probably the link URL can be retrieved from OLE
1996 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */