nss: upgrade to release 3.73
[LibreOffice.git] / embeddedobj / source / msole / olepersist.cxx
blob2d5dfbf59a4d48266cb46529d52f198b058754cb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
54 #if defined(_WIN32)
55 #include "olecomponent.hxx"
56 #endif
58 using namespace ::com::sun::star;
59 using namespace ::comphelper;
62 bool KillFile_Impl( const OUString& aURL, const uno::Reference< uno::XComponentContext >& xContext )
64 if ( !xContext.is() )
65 return false;
67 bool bRet = false;
69 try
71 uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
72 ucb::SimpleFileAccess::create( xContext ) );
74 xAccess->kill( aURL );
75 bRet = true;
77 catch( const uno::Exception& )
81 return bRet;
85 OUString GetNewTempFileURL_Impl( const uno::Reference< uno::XComponentContext >& xContext )
87 SAL_WARN_IF( !xContext.is(), "embeddedobj.ole", "No factory is provided!" );
89 OUString aResult;
91 uno::Reference < beans::XPropertySet > xTempFile(
92 io::TempFile::create(xContext),
93 uno::UNO_QUERY_THROW );
95 try {
96 xTempFile->setPropertyValue("RemoveFile", uno::makeAny( false ) );
97 uno::Any aUrl = xTempFile->getPropertyValue("Uri");
98 aUrl >>= aResult;
100 catch ( const uno::Exception& )
104 if ( aResult.isEmpty() )
105 throw uno::RuntimeException(); // TODO: can not create tempfile
107 return aResult;
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() )
120 try {
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 );
140 throw;
142 catch( const uno::RuntimeException& )
144 KillFile_Impl( aResult, xContext );
145 throw;
147 catch( const uno::Exception& )
149 KillFile_Impl( aResult, xContext );
150 aResult.clear();
154 return aResult;
156 #ifdef _WIN32
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 )
161 OUString aResult;
165 uno::Reference < beans::XPropertySet > xTempFile(
166 io::TempFile::create(xContext),
167 uno::UNO_QUERY );
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");
174 aUrl >>= aResult;
176 catch( const uno::RuntimeException& )
178 throw;
180 catch( const uno::Exception& )
184 if ( aResult.isEmpty() )
185 throw io::IOException();
187 return aResult;
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 ) );
196 #endif
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 ) );
204 #ifdef _WIN32
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;
231 return bResult;
235 void VerbExecutionController::ModificationNotificationIsDone()
237 osl::MutexGuard aGuard( m_aVerbExecutionMutex );
239 if ( m_bVerbExecutionInProgress && osl::Thread::getCurrentIdentifier() == m_nVerbExecutionThreadIdentifier )
240 m_bChangedOnVerbExecution = true;
242 #endif
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();
273 return xTempFile;
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 );
288 xSeek->seek( 0 );
290 uno::Sequence< sal_Int8 > aData( 8 );
291 sal_Int32 nRead = xInStream->readBytes( aData, 8 );
292 xSeek->seek( 0 );
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
298 return xStream;
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 )
306 nHeaderOffset = 40;
307 xSeek->seek( 8 );
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 );
312 sal_uInt32 nLen = 0;
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]);
315 if ( nLen > 4 )
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 )
330 nHeaderOffset = 4;
333 if ( nHeaderOffset )
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 );
349 xSeek->seek( 0 );
351 return xResult;
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",
373 aArgs, m_xContext ),
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' )
408 // it's a bitmap
409 aData[0] = 0x02; aData[1] = 0; aData[2] = 0; aData[3] = 0;
411 else
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 );
422 // write aspect
423 aData[0] = 0x01; aData[1] = 0; aData[2] = 0; aData[3] = 0;
424 xTempOutStream->writeBytes( aData );
426 // write l-index
427 * reinterpret_cast<sal_uInt32*>(aData.getArray()) = 0xFFFFFFFF;
428 xTempOutStream->writeBytes( aData );
430 // write adv. flags
431 aData[0] = 0x02; aData[1] = 0; aData[2] = 0; aData[3] = 0;
432 xTempOutStream->writeBytes( aData );
434 // write compression
435 * reinterpret_cast<sal_uInt32*>(aData.getArray()) = 0x0;
436 xTempOutStream->writeBytes( aData );
438 // get the size
439 awt::Size aSize = getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
440 sal_Int32 nIndex = 0;
442 // write width
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 );
450 // write height
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!" );
472 return;
474 for ( sal_Int32 nInd = 0; nInd < 4; nInd++ )
476 aData[nInd] = static_cast<sal_Int8>( static_cast<sal_uInt64>(nLength) % 0x100 );
477 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 ) );
492 else
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",
512 aArgs, m_xContext ),
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 );
540 else
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& )
561 if ( !xStream.is() )
562 xStream = m_xObjectStream->getInputStream();
564 if ( xStream.is() )
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",
574 aArgs, m_xContext ),
575 uno::UNO_QUERY );
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 )
603 throw ()
605 uno::Reference< io::XStream > xResult;
607 if ( xStream.is() )
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
617 xNameContainer.set(
618 m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
619 "com.sun.star.embed.OLESimpleStorage",
620 aArgs, m_xContext ),
621 uno::UNO_QUERY );
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 );
637 if ( xResult.is() )
638 break;
641 catch( const uno::Exception& )
644 if ( nInd == 0 )
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 );
653 if ( xResult.is() )
654 break;
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 );
701 m_aTempURL.clear();
704 #ifdef _WIN32
705 // retry to create the component after recovering
706 GetRidOfComponent();
710 CreateOleComponentAndLoad_Impl();
711 m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
713 catch( const uno::Exception& )
715 GetRidOfComponent();
717 #endif
720 xResult = TryToRetrieveCachedVisualRepresentation_Impl( xStream );
726 catch( const uno::Exception& )
731 return xResult;
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!" );
742 return;
745 try {
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 )
765 return;
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 );
775 #ifdef _WIN32
777 bool OleEmbeddedObject::SaveObject_Impl()
779 bool bResult = false;
781 if ( m_xClientSite.is() )
785 m_xClientSite->saveObject();
786 bResult = true;
788 catch( const uno::Exception& )
793 return bResult;
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 )
806 return false;
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();
815 aGuard.clear();
816 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
818 else if ( !bShow && m_nObjectState == embed::EmbedStates::ACTIVE )
820 m_nObjectState = embed::EmbedStates::RUNNING;
821 aGuard.clear();
822 StateChangeNotification_Impl( false, nOldState, m_nObjectState );
825 if ( m_xClientSite.is() )
829 m_xClientSite->visibilityChanged( bShow );
830 bResult = true;
832 catch( const uno::Exception& )
837 return bResult;
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()
850 if ( m_bDisposed )
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();
872 SaveObject_Impl();
873 MakeEventListenerNotification_Impl( "OnVisAreaChanged" );
879 void OleEmbeddedObject::OnClosed_Impl()
881 if ( m_bDisposed )
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 );
898 return m_aTempURL;
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 );
925 return m_aTempURL;
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 ),
938 uno::UNO_QUERY );
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
957 GetTempURL_Impl();
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();
994 return xOutStream;
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 );
1024 xTrunc->truncate();
1026 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutStream );
1028 // TODO: should the view replacement be in the stream ???
1029 // probably it must be specified on storing
1031 #endif
1033 void OleEmbeddedObject::StoreToLocation_Impl(
1034 const uno::Reference< embed::XStorage >& xStorage,
1035 const OUString& sEntName,
1036 const uno::Sequence< beans::PropertyValue >& lObjArgs,
1037 bool bSaveAs )
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
1072 if ( !bStoreVis )
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
1085 #ifdef _WIN32
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() )
1089 #endif
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;
1125 #ifdef _WIN32
1126 else if ( m_pOleComponent )
1128 xTargetStream =
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;
1141 if ( bSaveAs )
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;
1158 #endif
1159 else if (true) // loplugin:flatten
1161 throw io::IOException(); // TODO
1164 if ( !xTargetStream.is() )
1166 xTargetStream =
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 )
1176 if ( bStoreVis )
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
1186 if ( bSaveAs )
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 );
1199 else
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);
1210 if ( bSaveAs )
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() );
1223 else
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 )
1230 else
1232 uno::Reference< lang::XComponent > xComp( xTargetStream, uno::UNO_QUERY );
1233 if ( xComp.is() )
1235 try {
1236 xComp->dispose();
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 );
1258 return;
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 );
1270 if ( m_bDisposed )
1271 throw lang::DisposedException(); // TODO
1273 if ( !xStorage.is() )
1274 throw lang::IllegalArgumentException( "No parent storage is provided!",
1275 static_cast< ::cppu::OWeakObject* >(this),
1276 1 );
1278 if ( sEntName.isEmpty() )
1279 throw lang::IllegalArgumentException( "Empty element name is provided!",
1280 static_cast< ::cppu::OWeakObject* >(this),
1281 2 );
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;
1317 #ifdef _WIN32
1318 sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1319 #endif
1321 SwitchOwnPersistence( xStorage, sEntName );
1323 for ( beans::PropertyValue const & prop : lObjArgs )
1324 if ( prop.Name == "StoreVisualReplacement" )
1325 prop.Value >>= m_bStoreVisRepl;
1327 #ifdef _WIN32
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;
1358 else
1360 // create a new object
1361 CreateOleComponent_Impl();
1362 m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
1363 m_pOleComponent->RunObject();
1364 m_nObjectState = embed::EmbedStates::RUNNING;
1367 else
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
1390 OUString aURL;
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),
1399 4 );
1401 CreateOleComponent_Impl();
1403 // TODO: the m_bIsLink value must be set already
1404 if ( !m_bIsLink )
1405 m_pOleComponent->CreateObjectFromFile( aURL );
1406 else
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 )
1416 //TODO:
1418 else
1419 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1420 static_cast< ::cppu::OWeakObject* >(this),
1421 3 );
1423 #else
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
1436 else
1437 throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1438 static_cast< ::cppu::OWeakObject* >(this),
1439 3 );
1441 #endif
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 );
1456 return;
1458 // end wrapping related part ====================
1460 ::osl::MutexGuard aGuard( m_aMutex );
1461 if ( m_bDisposed )
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 );
1483 return;
1485 // end wrapping related part ====================
1487 ::osl::MutexGuard aGuard( m_aMutex );
1488 if ( m_bDisposed )
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 );
1507 return;
1509 // end wrapping related part ====================
1511 osl::ClearableMutexGuard aGuard(m_aMutex);
1512 if ( m_bDisposed )
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 )
1524 return;
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
1534 if ( bUseNew )
1536 SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStream, m_aNewEntryName );
1537 m_bStoreVisRepl = m_bNewVisReplInStream;
1538 SetVisReplInStream( m_bNewVisReplInStream );
1539 m_xCachedVisualRepresentation = m_xNewCachedVisRepl;
1541 else
1543 // close remembered stream
1544 try {
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& )
1580 aGuard.clear();
1581 if ( bUseNew )
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 );
1607 if ( m_bDisposed )
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() )
1616 return true;
1618 return false;
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 );
1634 if ( m_bDisposed )
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();
1661 return;
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
1667 // to do so or not
1669 osl::ClearableMutexGuard aGuard(m_aMutex);
1670 if ( m_bDisposed )
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) );
1687 if ( m_bReadOnly )
1688 throw io::IOException(); // TODO: access denied
1690 LetCommonStoragePassBeUsed_Impl( m_xObjectStream );
1692 bool bStoreLoaded = true;
1694 #ifdef _WIN32
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 );
1717 #endif
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 );
1726 else
1728 m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
1729 SAL_WARN_IF( !m_xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
1732 else
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& )
1756 aGuard.clear();
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 );
1779 if ( m_bDisposed )
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) );
1794 return m_bReadOnly;
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 );
1808 return;
1810 // end wrapping related part ====================
1812 // TODO: use lObjArgs
1814 ::osl::MutexGuard aGuard( m_aMutex );
1815 if ( m_bDisposed )
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) );
1830 // TODO:
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 );
1846 return;
1848 // end wrapping related part ====================
1850 ::osl::MutexGuard aGuard( m_aMutex );
1851 if ( m_bDisposed )
1852 throw lang::DisposedException(); // TODO
1854 if ( !xStorage.is() )
1855 throw lang::IllegalArgumentException( "No parent storage is provided!",
1856 static_cast< ::cppu::OWeakObject* >(this),
1857 1 );
1859 if ( sEntName.isEmpty() )
1860 throw lang::IllegalArgumentException( "Empty element name is provided!",
1861 static_cast< ::cppu::OWeakObject* >(this),
1862 2 );
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) );
1873 if ( m_bReadOnly )
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) );
1882 #ifdef _WIN32
1883 // TODO: create an object based on the link
1885 // disconnect the old temporary URL
1886 OUString aOldTempURL = m_aTempURL;
1887 m_aTempURL.clear();
1889 OleComponent* pNewOleComponent = new OleComponent(m_xContext, this);
1890 try {
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;
1899 throw;
1902 try {
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;
1911 throw;
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;
1939 m_bIsLink = false;
1940 m_aLinkURL.clear();
1941 #else // ! _WIN32
1942 throw io::IOException(); //TODO:
1943 #endif // _WIN32
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 );
1959 if ( m_bDisposed )
1960 throw lang::DisposedException(); // TODO
1962 return m_bIsLink;
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 );
1978 if ( m_bDisposed )
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) );
1986 if ( !m_bIsLink )
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
1993 return m_aLinkURL;
1996 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */