1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
43 
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>
51 
52 #include <closepreventer.hxx>
53 
54 #if defined(_WIN32)
55 #include "olecomponent.hxx"
56 #endif
57 
58 using namespace ::com::sun::star;
59 using namespace ::comphelper;
60 
61 
KillFile_Impl(const OUString & aURL,const uno::Reference<lang::XMultiServiceFactory> & xFactory)62 bool KillFile_Impl( const OUString& aURL, const uno::Reference< lang::XMultiServiceFactory >& xFactory )
63 {
64     if ( !xFactory.is() )
65         return false;
66 
67     bool bRet = false;
68 
69     try
70     {
71         uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
72                 ucb::SimpleFileAccess::create( comphelper::getComponentContext(xFactory) ) );
73 
74         xAccess->kill( aURL );
75         bRet = true;
76     }
77     catch( const uno::Exception& )
78     {
79     }
80 
81     return bRet;
82 }
83 
84 
GetNewTempFileURL_Impl(const uno::Reference<lang::XMultiServiceFactory> & xFactory)85 OUString GetNewTempFileURL_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory )
86 {
87     SAL_WARN_IF( !xFactory.is(), "embeddedobj.ole", "No factory is provided!" );
88 
89     OUString aResult;
90 
91     uno::Reference < beans::XPropertySet > xTempFile(
92             io::TempFile::create(comphelper::getComponentContext(xFactory)),
93             uno::UNO_QUERY_THROW );
94 
95     try {
96         xTempFile->setPropertyValue("RemoveFile", uno::makeAny( false ) );
97         uno::Any aUrl = xTempFile->getPropertyValue("Uri");
98         aUrl >>= aResult;
99     }
100     catch ( const uno::Exception& )
101     {
102     }
103 
104     if ( aResult.isEmpty() )
105         throw uno::RuntimeException(); // TODO: can not create tempfile
106 
107     return aResult;
108 }
109 
110 
GetNewFilledTempFile_Impl(const uno::Reference<io::XInputStream> & xInStream,const uno::Reference<lang::XMultiServiceFactory> & xFactory)111 OUString GetNewFilledTempFile_Impl( const uno::Reference< io::XInputStream >& xInStream,
112                                       const uno::Reference< lang::XMultiServiceFactory >& xFactory )
113 {
114     OSL_ENSURE( xInStream.is() && xFactory.is(), "Wrong parameters are provided!" );
115 
116     OUString aResult = GetNewTempFileURL_Impl( xFactory );
117 
118     if ( !aResult.isEmpty() )
119     {
120         try {
121             uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
122                     ucb::SimpleFileAccess::create( comphelper::getComponentContext(xFactory) ) );
123 
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();
131         }
132         catch( const packages::WrongPasswordException& )
133         {
134             KillFile_Impl( aResult, xFactory );
135             throw io::IOException(); //TODO:
136         }
137         catch( const io::IOException& )
138         {
139             KillFile_Impl( aResult, xFactory );
140             throw;
141         }
142         catch( const uno::RuntimeException& )
143         {
144             KillFile_Impl( aResult, xFactory );
145             throw;
146         }
147         catch( const uno::Exception& )
148         {
149             KillFile_Impl( aResult, xFactory );
150             aResult.clear();
151         }
152     }
153 
154     return aResult;
155 }
156 #ifdef _WIN32
157 /// @throws io::IOException
158 /// @throws uno::RuntimeException
GetNewFilledTempFile_Impl(const uno::Reference<embed::XOptimizedStorage> & xParentStorage,const OUString & aEntryName,const uno::Reference<lang::XMultiServiceFactory> & xFactory)159 static OUString GetNewFilledTempFile_Impl( const uno::Reference< embed::XOptimizedStorage >& xParentStorage, const OUString& aEntryName, const uno::Reference< lang::XMultiServiceFactory >& xFactory )
160 {
161     OUString aResult;
162 
163     try
164     {
165         uno::Reference < beans::XPropertySet > xTempFile(
166                 io::TempFile::create(comphelper::getComponentContext(xFactory)),
167                 uno::UNO_QUERY );
168         uno::Reference < io::XStream > xTempStream( xTempFile, uno::UNO_QUERY_THROW );
169 
170         xParentStorage->copyStreamElementData( aEntryName, xTempStream );
171 
172         xTempFile->setPropertyValue("RemoveFile", uno::makeAny( false ) );
173         uno::Any aUrl = xTempFile->getPropertyValue("Uri");
174         aUrl >>= aResult;
175     }
176     catch( const uno::RuntimeException& )
177     {
178         throw;
179     }
180     catch( const uno::Exception& )
181     {
182     }
183 
184     if ( aResult.isEmpty() )
185         throw io::IOException();
186 
187     return aResult;
188 }
189 
190 
SetStreamMediaType_Impl(const uno::Reference<io::XStream> & xStream,const OUString & aMediaType)191 static void SetStreamMediaType_Impl( const uno::Reference< io::XStream >& xStream, const OUString& aMediaType )
192 {
193     uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY_THROW );
194     xPropSet->setPropertyValue("MediaType", uno::makeAny( aMediaType ) );
195 }
196 #endif
197 
LetCommonStoragePassBeUsed_Impl(const uno::Reference<io::XStream> & xStream)198 static void LetCommonStoragePassBeUsed_Impl( const uno::Reference< io::XStream >& xStream )
199 {
200     uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY_THROW );
201     xPropSet->setPropertyValue("UseCommonStoragePasswordEncryption",
202                                 uno::makeAny( true ) );
203 }
204 #ifdef _WIN32
205 
StartControlExecution()206 void VerbExecutionController::StartControlExecution()
207 {
208     osl::MutexGuard aGuard( m_aVerbExecutionMutex );
209 
210     // the class is used to detect STAMPIT object, that can never be active
211     if ( !m_bVerbExecutionInProgress && !m_bWasEverActive )
212     {
213         m_bVerbExecutionInProgress = true;
214         m_nVerbExecutionThreadIdentifier = osl::Thread::getCurrentIdentifier();
215         m_bChangedOnVerbExecution = false;
216     }
217 }
218 
219 
EndControlExecution_WasModified()220 bool VerbExecutionController::EndControlExecution_WasModified()
221 {
222     osl::MutexGuard aGuard( m_aVerbExecutionMutex );
223 
224     bool bResult = false;
225     if ( m_bVerbExecutionInProgress && m_nVerbExecutionThreadIdentifier == osl::Thread::getCurrentIdentifier() )
226     {
227         bResult = m_bChangedOnVerbExecution;
228         m_bVerbExecutionInProgress = false;
229     }
230 
231     return bResult;
232 }
233 
234 
ModificationNotificationIsDone()235 void VerbExecutionController::ModificationNotificationIsDone()
236 {
237     osl::MutexGuard aGuard( m_aVerbExecutionMutex );
238 
239     if ( m_bVerbExecutionInProgress && osl::Thread::getCurrentIdentifier() == m_nVerbExecutionThreadIdentifier )
240         m_bChangedOnVerbExecution = true;
241 }
242 #endif
243 
LockNotification()244 void VerbExecutionController::LockNotification()
245 {
246     osl::MutexGuard aGuard( m_aVerbExecutionMutex );
247     if ( m_nNotificationLock < SAL_MAX_INT32 )
248         m_nNotificationLock++;
249 }
250 
251 
UnlockNotification()252 void VerbExecutionController::UnlockNotification()
253 {
254     osl::MutexGuard aGuard( m_aVerbExecutionMutex );
255     if ( m_nNotificationLock > 0 )
256         m_nNotificationLock--;
257 }
258 
259 
GetNewFilledTempStream_Impl(const uno::Reference<io::XInputStream> & xInStream)260 uno::Reference< io::XStream > OleEmbeddedObject::GetNewFilledTempStream_Impl( const uno::Reference< io::XInputStream >& xInStream )
261 {
262     SAL_WARN_IF( !xInStream.is(), "embeddedobj.ole", "Wrong parameter is provided!" );
263 
264     uno::Reference < io::XStream > xTempFile(
265             io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
266             uno::UNO_QUERY_THROW );
267 
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;
274 }
275 
276 
TryToGetAcceptableFormat_Impl(const uno::Reference<io::XStream> & xStream)277 uno::Reference< io::XStream > OleEmbeddedObject::TryToGetAcceptableFormat_Impl( const uno::Reference< io::XStream >& xStream )
278 {
279     // TODO/LATER: Actually this should be done by a centralized component ( may be a graphical filter )
280     if ( !m_xFactory.is() )
281         throw uno::RuntimeException();
282 
283     uno::Reference< io::XInputStream > xInStream = xStream->getInputStream();
284     if ( !xInStream.is() )
285         throw uno::RuntimeException();
286 
287     uno::Reference< io::XSeekable > xSeek( xStream, uno::UNO_QUERY_THROW );
288     xSeek->seek( 0 );
289 
290     uno::Sequence< sal_Int8 > aData( 8 );
291     sal_Int32 nRead = xInStream->readBytes( aData, 8 );
292     xSeek->seek( 0 );
293 
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 ) )
296     {
297         // it should be a bitmap or a Metafile
298         return xStream;
299     }
300 
301 
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 )
305     {
306         nHeaderOffset = 40;
307         xSeek->seek( 8 );
308 
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 )
316         {
317             xInStream->skipBytes( nLen - 4 );
318             nHeaderOffset += nLen - 4;
319         }
320 
321     }
322     else if ( nRead > 4 )
323     {
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]);
328 
329         if ( nSize == xSeek->getLength() - 4 )
330             nHeaderOffset = 4;
331     }
332 
333     if ( nHeaderOffset )
334     {
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(comphelper::getComponentContext(m_xFactory)),
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();
344 
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 );
350 
351         return xResult;
352     }
353 
354     return uno::Reference< io::XStream >();
355 }
356 
357 
InsertVisualCache_Impl(const uno::Reference<io::XStream> & xTargetStream,const uno::Reference<io::XStream> & xCachedVisualRepresentation)358 void OleEmbeddedObject::InsertVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream,
359                                                 const uno::Reference< io::XStream >& xCachedVisualRepresentation )
360 {
361     OSL_ENSURE( xTargetStream.is() && xCachedVisualRepresentation.is(), "Invalid arguments!" );
362 
363     if ( !xTargetStream.is() || !xCachedVisualRepresentation.is() )
364         throw uno::RuntimeException();
365 
366     uno::Sequence< uno::Any > aArgs( 2 );
367     aArgs[0] <<= xTargetStream;
368     aArgs[1] <<= true; // do not create copy
369 
370     uno::Reference< container::XNameContainer > xNameContainer(
371             m_xFactory->createInstanceWithArguments(
372                     "com.sun.star.embed.OLESimpleStorage",
373                     aArgs ),
374             uno::UNO_QUERY_THROW );
375 
376     uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY_THROW );
377     xCachedSeek->seek( 0 );
378 
379     uno::Reference < io::XStream > xTempFile(
380             io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
381             uno::UNO_QUERY_THROW );
382 
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:
387 
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();
393 
394     // write 0xFFFFFFFF at the beginning
395     uno::Sequence< sal_Int8 > aData( 4 );
396     * reinterpret_cast<sal_uInt32*>(aData.getArray()) = 0xFFFFFFFF;
397 
398     xTempOutStream->writeBytes( aData );
399 
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();
405 
406     if ( aSigData[0] == 'B' && aSigData[1] == 'M' )
407     {
408         // it's a bitmap
409         aData[0] = 0x02; aData[1] = 0; aData[2] = 0; aData[3] = 0;
410     }
411     else
412     {
413         // treat it as a metafile
414         aData[0] = 0x03; aData[1] = 0; aData[2] = 0; aData[3] = 0;
415     }
416     xTempOutStream->writeBytes( aData );
417 
418     // write job related information
419     aData[0] = 0x04; aData[1] = 0; aData[2] = 0; aData[3] = 0;
420     xTempOutStream->writeBytes( aData );
421 
422     // write aspect
423     aData[0] = 0x01; aData[1] = 0; aData[2] = 0; aData[3] = 0;
424     xTempOutStream->writeBytes( aData );
425 
426     // write l-index
427     * reinterpret_cast<sal_uInt32*>(aData.getArray()) = 0xFFFFFFFF;
428     xTempOutStream->writeBytes( aData );
429 
430     // write adv. flags
431     aData[0] = 0x02; aData[1] = 0; aData[2] = 0; aData[3] = 0;
432     xTempOutStream->writeBytes( aData );
433 
434     // write compression
435     * reinterpret_cast<sal_uInt32*>(aData.getArray()) = 0x0;
436     xTempOutStream->writeBytes( aData );
437 
438     // get the size
439     awt::Size aSize = getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
440     sal_Int32 nIndex = 0;
441 
442     // write width
443     for ( nIndex = 0; nIndex < 4; nIndex++ )
444     {
445         aData[nIndex] = static_cast<sal_Int8>( aSize.Width % 0x100 );
446         aSize.Width /= 0x100;
447     }
448     xTempOutStream->writeBytes( aData );
449 
450     // write height
451     for ( nIndex = 0; nIndex < 4; nIndex++ )
452     {
453         aData[nIndex] = static_cast<sal_Int8>( aSize.Height % 0x100 );
454         aSize.Height /= 0x100;
455     }
456     xTempOutStream->writeBytes( aData );
457 
458     // write garbage, it will be overwritten by the size
459     xTempOutStream->writeBytes( aData );
460 
461     // write first bytes that was used to detect the type
462     xTempOutStream->writeBytes( aSigData );
463 
464     // write the rest of the stream
465     ::comphelper::OStorageHelper::CopyInputToOutput( xInCacheStream, xTempOutStream );
466 
467     // write the size of the stream
468     sal_Int64 nLength = xTempSeek->getLength() - 40;
469     if ( nLength < 0 || nLength >= 0xFFFFFFFF )
470     {
471         SAL_WARN( "embeddedobj.ole", "Length is not acceptable!" );
472         return;
473     }
474     for ( sal_Int32 nInd = 0; nInd < 4; nInd++ )
475     {
476         aData[nInd] = static_cast<sal_Int8>( static_cast<sal_uInt64>(nLength) % 0x100 );
477         nLength /= 0x100;
478     }
479     xTempSeek->seek( 36 );
480     xTempOutStream->writeBytes( aData );
481 
482     xTempOutStream->flush();
483 
484     xTempSeek->seek( 0 );
485     if ( xCachedSeek.is() )
486         xCachedSeek->seek( 0 );
487 
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 ) );
494 
495     uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY_THROW );
496     xTransacted->commit();
497 }
498 
499 
RemoveVisualCache_Impl(const uno::Reference<io::XStream> & xTargetStream)500 void OleEmbeddedObject::RemoveVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream )
501 {
502     OSL_ENSURE( xTargetStream.is(), "Invalid argument!" );
503     if ( !xTargetStream.is() )
504         throw uno::RuntimeException();
505 
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_xFactory->createInstanceWithArguments(
511                     "com.sun.star.embed.OLESimpleStorage",
512                     aArgs ),
513             uno::UNO_QUERY_THROW );
514 
515     for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
516     {
517         OUString aStreamName =  "\002OlePres00" + OUString::number( nInd );
518         if ( xNameContainer->hasByName( aStreamName ) )
519             xNameContainer->removeByName( aStreamName );
520     }
521 
522     uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY_THROW );
523     xTransacted->commit();
524 }
525 
526 
SetVisReplInStream(bool bExists)527 void OleEmbeddedObject::SetVisReplInStream( bool bExists )
528 {
529     m_bVisReplInitialized = true;
530     m_bVisReplInStream = bExists;
531 }
532 
533 
HasVisReplInStream()534 bool OleEmbeddedObject::HasVisReplInStream()
535 {
536     if ( !m_bVisReplInitialized )
537     {
538         if ( m_xCachedVisualRepresentation.is() )
539             SetVisReplInStream( true );
540         else
541         {
542             SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::HasVisualReplInStream, analyzing" );
543 
544             uno::Reference< io::XInputStream > xStream;
545 
546             OSL_ENSURE( !m_pOleComponent || !m_aTempURL.isEmpty(), "The temporary file must exist if there is a component!" );
547             if ( !m_aTempURL.isEmpty() )
548             {
549                 try
550                 {
551                     // open temporary file for reading
552                     uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
553                             ucb::SimpleFileAccess::create( comphelper::getComponentContext(m_xFactory) ) );
554 
555                     xStream = xTempAccess->openFileRead( m_aTempURL );
556                 }
557                 catch( const uno::Exception& )
558                 {}
559             }
560 
561             if ( !xStream.is() )
562                 xStream = m_xObjectStream->getInputStream();
563 
564             if ( xStream.is() )
565             {
566                 bool bExists = false;
567 
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_xFactory->createInstanceWithArguments(
573                                 "com.sun.star.embed.OLESimpleStorage",
574                                 aArgs ),
575                         uno::UNO_QUERY );
576 
577                 if ( xNameContainer.is() )
578                 {
579                     for ( sal_uInt8 nInd = 0; nInd < 10 && !bExists; nInd++ )
580                     {
581                         OUString aStreamName = "\002OlePres00" + OUString::number( nInd );
582                         try
583                         {
584                             bExists = xNameContainer->hasByName( aStreamName );
585                         }
586                         catch( const uno::Exception& )
587                         {}
588                     }
589                 }
590 
591                 SetVisReplInStream( bExists );
592             }
593         }
594     }
595 
596     return m_bVisReplInStream;
597 }
598 
599 
TryToRetrieveCachedVisualRepresentation_Impl(const uno::Reference<io::XStream> & xStream,bool bAllowToRepair50)600 uno::Reference< io::XStream > OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation_Impl(
601         const uno::Reference< io::XStream >& xStream,
602         bool bAllowToRepair50 )
603     throw ()
604 {
605     uno::Reference< io::XStream > xResult;
606 
607     if ( xStream.is() )
608     {
609         SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation, retrieving" );
610 
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
615         try
616         {
617             xNameContainer.set(
618                 m_xFactory->createInstanceWithArguments(
619                         "com.sun.star.embed.OLESimpleStorage",
620                         aArgs ),
621                 uno::UNO_QUERY );
622         }
623         catch( const uno::Exception& )
624         {}
625 
626         if ( xNameContainer.is() )
627         {
628             for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
629             {
630                 OUString aStreamName =  "\002OlePres00" + OUString::number( nInd );
631                 uno::Reference< io::XStream > xCachedCopyStream;
632                 try
633                 {
634                     if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
635                     {
636                         xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
637                         if ( xResult.is() )
638                             break;
639                     }
640                 }
641                 catch( const uno::Exception& )
642                 {}
643 
644                 if ( nInd == 0 )
645                 {
646                     // to be compatible with the old versions Ole10Native is checked after OlePress000
647                     aStreamName = "\001Ole10Native";
648                     try
649                     {
650                         if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
651                         {
652                             xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
653                             if ( xResult.is() )
654                                 break;
655                         }
656                     }
657                     catch( const uno::Exception& )
658                     {}
659                 }
660             }
661 
662             try
663             {
664                 if ( bAllowToRepair50 && !xResult.is() )
665                 {
666                     OUString aOrigContName( "Ole-Object" );
667                     if ( xNameContainer->hasByName( aOrigContName ) )
668                     {
669                         uno::Reference< embed::XClassifiedObject > xClassified( xNameContainer, uno::UNO_QUERY_THROW );
670                         if ( MimeConfigurationHelper::ClassIDsEqual( xClassified->getClassID(), MimeConfigurationHelper::GetSequenceClassID( SO3_OUT_CLASSID ) ) )
671                         {
672                             // this is an OLE object wrongly stored in 5.0 format
673                             // this object must be repaired since SO7 has done it
674 
675                             uno::Reference< io::XOutputStream > xOutputStream = xStream->getOutputStream();
676                             uno::Reference< io::XTruncate > xTruncate( xOutputStream, uno::UNO_QUERY_THROW );
677 
678                             uno::Reference< io::XInputStream > xOrigInputStream;
679                             if ( ( xNameContainer->getByName( aOrigContName ) >>= xOrigInputStream )
680                               && xOrigInputStream.is() )
681                             {
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 );
687 
688                                 uno::Reference< lang::XComponent > xNameContDisp( xNameContainer, uno::UNO_QUERY_THROW );
689                                 xNameContDisp->dispose(); // free the original stream
690 
691                                 xTruncate->truncate();
692                                 ::comphelper::OStorageHelper::CopyInputToOutput( xOrigInputStream, xOutputStream );
693                                 xOutputStream->flush();
694 
695                                 if ( xStream == m_xObjectStream )
696                                 {
697                                     if ( !m_aTempURL.isEmpty() )
698                                     {
699                                         // this is the own stream, so the temporary URL must be cleaned if it exists
700                                         KillFile_Impl( m_aTempURL, m_xFactory );
701                                         m_aTempURL.clear();
702                                     }
703 
704 #ifdef _WIN32
705                                     // retry to create the component after recovering
706                                     GetRidOfComponent();
707 
708                                     try
709                                     {
710                                         CreateOleComponentAndLoad_Impl();
711                                         m_aClassID = m_pOleComponent->GetCLSID(); // was not set during consruction
712                                     }
713                                     catch( const uno::Exception& )
714                                     {
715                                         GetRidOfComponent();
716                                     }
717 #endif
718                                 }
719 
720                                 xResult = TryToRetrieveCachedVisualRepresentation_Impl( xStream );
721                             }
722                         }
723                     }
724                 }
725             }
726             catch( const uno::Exception& )
727             {}
728         }
729     }
730 
731     return xResult;
732 }
733 
734 
SwitchOwnPersistence(const uno::Reference<embed::XStorage> & xNewParentStorage,const uno::Reference<io::XStream> & xNewObjectStream,const OUString & aNewName)735 void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
736                                               const uno::Reference< io::XStream >& xNewObjectStream,
737                                               const OUString& aNewName )
738 {
739     if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
740     {
741         SAL_WARN_IF( xNewObjectStream != m_xObjectStream, "embeddedobj.ole", "The streams must be the same!" );
742         return;
743     }
744 
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();
750     }
751     catch ( const uno::Exception& )
752     {
753     }
754 
755     m_xObjectStream = xNewObjectStream;
756     m_xParentStorage = xNewParentStorage;
757     m_aEntryName = aNewName;
758 }
759 
760 
SwitchOwnPersistence(const uno::Reference<embed::XStorage> & xNewParentStorage,const OUString & aNewName)761 void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
762                                               const OUString& aNewName )
763 {
764     if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
765         return;
766 
767     sal_Int32 nStreamMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
768 
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!" );
771 
772     SwitchOwnPersistence( xNewParentStorage, xNewOwnStream, aNewName );
773 }
774 
775 #ifdef _WIN32
776 
SaveObject_Impl()777 bool OleEmbeddedObject::SaveObject_Impl()
778 {
779     bool bResult = false;
780 
781     if ( m_xClientSite.is() )
782     {
783         try
784         {
785             m_xClientSite->saveObject();
786             bResult = true;
787         }
788         catch( const uno::Exception& )
789         {
790         }
791     }
792 
793     return bResult;
794 }
795 
796 
OnShowWindow_Impl(bool bShow)797 bool OleEmbeddedObject::OnShowWindow_Impl( bool bShow )
798 {
799     osl::ClearableMutexGuard aGuard(m_aMutex);
800 
801     bool bResult = false;
802 
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;
807 
808     // the object is either activated or deactivated
809     sal_Int32 nOldState = m_nObjectState;
810     if ( bShow && m_nObjectState == embed::EmbedStates::RUNNING )
811     {
812         m_nObjectState = embed::EmbedStates::ACTIVE;
813         m_aVerbExecutionController.ObjectIsActive();
814 
815         aGuard.clear();
816         StateChangeNotification_Impl( false, nOldState, m_nObjectState );
817     }
818     else if ( !bShow && m_nObjectState == embed::EmbedStates::ACTIVE )
819     {
820         m_nObjectState = embed::EmbedStates::RUNNING;
821         aGuard.clear();
822         StateChangeNotification_Impl( false, nOldState, m_nObjectState );
823     }
824 
825     if ( m_xClientSite.is() )
826     {
827         try
828         {
829             m_xClientSite->visibilityChanged( bShow );
830             bResult = true;
831         }
832         catch( const uno::Exception& )
833         {
834         }
835     }
836 
837     return bResult;
838 }
839 
840 
OnIconChanged_Impl()841 void OleEmbeddedObject::OnIconChanged_Impl()
842 {
843     // TODO/LATER: currently this notification seems to be impossible
844     // MakeEventListenerNotification_Impl( OUString( "OnIconChanged" ) );
845 }
846 
847 
OnViewChanged_Impl()848 void OleEmbeddedObject::OnViewChanged_Impl()
849 {
850     if ( m_bDisposed )
851         throw lang::DisposedException();
852 
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
855 
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();
859 
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)))
868        )
869     {
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" );
874     }
875 
876 }
877 
878 
OnClosed_Impl()879 void OleEmbeddedObject::OnClosed_Impl()
880 {
881     if ( m_bDisposed )
882         throw lang::DisposedException();
883 
884     if ( m_nObjectState != embed::EmbedStates::LOADED )
885     {
886         sal_Int32 nOldState = m_nObjectState;
887         m_nObjectState = embed::EmbedStates::LOADED;
888         StateChangeNotification_Impl( false, nOldState, m_nObjectState );
889     }
890 }
891 
892 
CreateTempURLEmpty_Impl()893 OUString OleEmbeddedObject::CreateTempURLEmpty_Impl()
894 {
895     SAL_WARN_IF( !m_aTempURL.isEmpty(), "embeddedobj.ole", "The object has already the temporary file!" );
896     m_aTempURL = GetNewTempFileURL_Impl( m_xFactory );
897 
898     return m_aTempURL;
899 }
900 
901 
GetTempURL_Impl()902 OUString OleEmbeddedObject::GetTempURL_Impl()
903 {
904     if ( m_aTempURL.isEmpty() )
905     {
906         SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::GetTempURL_Impl, tempfile creation" );
907 
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() )
911         {
912             m_aTempURL = GetNewFilledTempFile_Impl( xOptParStorage, m_aEntryName, m_xFactory );
913         }
914         else if ( m_xObjectStream.is() )
915         {
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
920 
921             m_aTempURL = GetNewFilledTempFile_Impl( xInStream, m_xFactory );
922         }
923     }
924 
925     return m_aTempURL;
926 }
927 
928 
CreateOleComponent_Impl(OleComponent * pOleComponent)929 void OleEmbeddedObject::CreateOleComponent_Impl( OleComponent* pOleComponent )
930 {
931     if ( !m_pOleComponent )
932     {
933         m_pOleComponent = pOleComponent ? pOleComponent : new OleComponent( m_xFactory, this );
934         m_pOleComponent->acquire(); // TODO: needs holder?
935 
936         if ( !m_xClosePreventer.is() )
937             m_xClosePreventer.set( static_cast< ::cppu::OWeakObject* >( new OClosePreventer ),
938                                    uno::UNO_QUERY );
939 
940         m_pOleComponent->addCloseListener( m_xClosePreventer );
941     }
942 }
943 
944 
CreateOleComponentAndLoad_Impl(OleComponent * pOleComponent)945 void OleEmbeddedObject::CreateOleComponentAndLoad_Impl( OleComponent* pOleComponent )
946 {
947     if ( !m_pOleComponent )
948     {
949         if ( !m_xObjectStream.is() )
950             throw uno::RuntimeException();
951 
952         CreateOleComponent_Impl( pOleComponent );
953 
954         // after the loading the object can appear as a link
955         // will be detected later by olecomponent
956 
957         GetTempURL_Impl();
958         if ( m_aTempURL.isEmpty() )
959             throw uno::RuntimeException(); // TODO
960 
961         m_pOleComponent->LoadEmbeddedObject( m_aTempURL );
962     }
963 }
964 
965 
CreateOleComponentFromClipboard_Impl(OleComponent * pOleComponent)966 void OleEmbeddedObject::CreateOleComponentFromClipboard_Impl( OleComponent* pOleComponent )
967 {
968     if ( !m_pOleComponent )
969     {
970         if ( !m_xObjectStream.is() )
971             throw uno::RuntimeException();
972 
973         CreateOleComponent_Impl( pOleComponent );
974 
975         // after the loading the object can appear as a link
976         // will be detected later by olecomponent
977         m_pOleComponent->CreateObjectFromClipboard();
978     }
979 }
980 
981 
GetStreamForSaving()982 uno::Reference< io::XOutputStream > OleEmbeddedObject::GetStreamForSaving()
983 {
984     if ( !m_xObjectStream.is() )
985         throw uno::RuntimeException(); //TODO:
986 
987     uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
988     if ( !xOutStream.is() )
989         throw io::IOException(); //TODO: access denied
990 
991     uno::Reference< io::XTruncate > xTruncate( xOutStream, uno::UNO_QUERY_THROW );
992     xTruncate->truncate();
993 
994     return xOutStream;
995 }
996 
997 
StoreObjectToStream(uno::Reference<io::XOutputStream> const & xOutStream)998 void OleEmbeddedObject::StoreObjectToStream( uno::Reference< io::XOutputStream > const & xOutStream )
999 {
1000     // this method should be used only on windows
1001     if ( m_pOleComponent )
1002         m_pOleComponent->StoreOwnTmpIfNecessary();
1003 
1004     // now all the changes should be in temporary location
1005     if ( m_aTempURL.isEmpty() )
1006         throw uno::RuntimeException();
1007 
1008     // open temporary file for reading
1009     uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
1010             ucb::SimpleFileAccess::create( comphelper::getComponentContext(m_xFactory) ) );
1011 
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!" );
1014 
1015     // TODO: use bStoreVisReplace
1016 
1017     if ( !xTempInStream.is() )
1018     {
1019         throw io::IOException(); // TODO:
1020     }
1021 
1022     // write all the contents to XOutStream
1023     uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY_THROW );
1024     xTrunc->truncate();
1025 
1026     ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutStream );
1027 
1028     // TODO: should the view replacement be in the stream ???
1029     //       probably it must be specified on storing
1030 }
1031 #endif
1032 
StoreToLocation_Impl(const uno::Reference<embed::XStorage> & xStorage,const OUString & sEntName,const uno::Sequence<beans::PropertyValue> & lObjArgs,bool bSaveAs)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 )
1038 {
1039     // TODO: use lObjArgs
1040     // TODO: exchange StoreVisualReplacement by SO file format version?
1041 
1042     if ( m_nObjectState == -1 )
1043     {
1044         // the object is still not loaded
1045         throw embed::WrongStateException( "Can't store object without persistence!",
1046                                         static_cast< ::cppu::OWeakObject* >(this) );
1047     }
1048 
1049     if ( m_bWaitSaveCompleted )
1050         throw embed::WrongStateException(
1051                     "The object waits for saveCompleted() call!",
1052                     static_cast< ::cppu::OWeakObject* >(this) );
1053 
1054     OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!" );
1055 
1056     bool bVisReplIsStored = false;
1057 
1058     bool bTryOptimization = false;
1059     bool bStoreVis = m_bStoreVisRepl;
1060     uno::Reference< io::XStream > xCachedVisualRepresentation;
1061     for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1062     {
1063         if ( lObjArgs[nInd].Name == "StoreVisualReplacement" )
1064             lObjArgs[nInd].Value >>= bStoreVis;
1065         else if ( lObjArgs[nInd].Name == "VisualReplacement" )
1066             lObjArgs[nInd].Value >>= xCachedVisualRepresentation;
1067         else if ( lObjArgs[nInd].Name == "CanTryOptimization" )
1068             lObjArgs[nInd].Value >>= bTryOptimization;
1069     }
1070 
1071     // ignore visual representation provided from outside if it should not be stored
1072     if ( !bStoreVis )
1073         xCachedVisualRepresentation.clear();
1074 
1075     if ( bStoreVis && !HasVisReplInStream() && !xCachedVisualRepresentation.is() )
1076         throw io::IOException(); // TODO: there is no cached visual representation and nothing is provided from outside
1077 
1078     // if the representation is provided from outside it should be copied to a local stream
1079     bool bNeedLocalCache = xCachedVisualRepresentation.is();
1080 
1081     uno::Reference< io::XStream > xTargetStream;
1082 
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
1090     )
1091     {
1092         bool bOptimizedCopyingDone = false;
1093 
1094         if ( bTryOptimization && bStoreVis == HasVisReplInStream() )
1095         {
1096             try
1097             {
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;
1102             }
1103             catch( const uno::Exception& )
1104             {
1105             }
1106         }
1107 
1108         if ( !bOptimizedCopyingDone )
1109         {
1110             // if optimized copying fails a normal one should be tried
1111             m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
1112         }
1113 
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() )
1117         {
1118             xCachedVisualRepresentation = m_xCachedVisualRepresentation;
1119             bNeedLocalCache = false;
1120         }
1121 
1122         bVisReplIsStored = HasVisReplInStream();
1123         bStoreLoaded = true;
1124     }
1125 #ifdef _WIN32
1126     else if ( m_pOleComponent )
1127     {
1128         xTargetStream =
1129                 xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
1130         if ( !xTargetStream.is() )
1131             throw io::IOException(); //TODO: access denied
1132 
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
1137 
1138         StoreObjectToStream( xOutStream );
1139         bVisReplIsStored = true;
1140 
1141         if ( bSaveAs )
1142         {
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
1146 
1147             uno::Reference< io::XStream > xTmpCVRepresentation =
1148                         TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
1149 
1150             // the locally retrieved representation is always preferable
1151             if ( xTmpCVRepresentation.is() )
1152             {
1153                 xCachedVisualRepresentation = xTmpCVRepresentation;
1154                 bNeedLocalCache = false;
1155             }
1156         }
1157     }
1158 #endif
1159     else if (true) // loplugin:flatten
1160     {
1161         throw io::IOException(); // TODO
1162     }
1163 
1164     if ( !xTargetStream.is() )
1165     {
1166         xTargetStream =
1167             xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
1168         if ( !xTargetStream.is() )
1169             throw io::IOException(); //TODO: access denied
1170     }
1171 
1172     LetCommonStoragePassBeUsed_Impl( xTargetStream );
1173 
1174     if ( bStoreVis != bVisReplIsStored )
1175     {
1176         if ( bStoreVis )
1177         {
1178             if ( !xCachedVisualRepresentation.is() )
1179                 xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
1180 
1181             SAL_WARN_IF( !xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
1182 
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 )
1187             {
1188                 uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY );
1189                 if ( !xCachedSeek.is() )
1190                 {
1191                     xCachedVisualRepresentation
1192                         = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
1193                     bNeedLocalCache = false;
1194                 }
1195             }
1196 
1197             InsertVisualCache_Impl( xTargetStream, xCachedVisualRepresentation );
1198         }
1199         else
1200         {
1201             // the removed representation could be cached by this method
1202             if ( !xCachedVisualRepresentation.is() )
1203                 xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
1204 
1205             if (!m_bStreamReadOnly)
1206                 RemoveVisualCache_Impl(xTargetStream);
1207         }
1208     }
1209 
1210     if ( bSaveAs )
1211     {
1212         m_bWaitSaveCompleted = true;
1213         m_xNewObjectStream = xTargetStream;
1214         m_xNewParentStorage = xStorage;
1215         m_aNewEntryName = sEntName;
1216         m_bNewVisReplInStream = bStoreVis;
1217         m_bStoreLoaded = bStoreLoaded;
1218 
1219         if ( xCachedVisualRepresentation.is() )
1220         {
1221             if ( bNeedLocalCache )
1222                 m_xNewCachedVisRepl = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
1223             else
1224                 m_xNewCachedVisRepl = xCachedVisualRepresentation;
1225         }
1226 
1227         // TODO: register listeners for storages above, in case they are disposed
1228         //       an exception will be thrown on saveCompleted( true )
1229     }
1230     else
1231     {
1232         uno::Reference< lang::XComponent > xComp( xTargetStream, uno::UNO_QUERY );
1233         if ( xComp.is() )
1234         {
1235             try {
1236                 xComp->dispose();
1237             } catch( const uno::Exception& )
1238             {
1239             }
1240         }
1241     }
1242 }
1243 
1244 
setPersistentEntry(const uno::Reference<embed::XStorage> & xStorage,const OUString & sEntName,sal_Int32 nEntryConnectionMode,const uno::Sequence<beans::PropertyValue> & lArguments,const uno::Sequence<beans::PropertyValue> & lObjArgs)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 )
1251 {
1252     // begin wrapping related part ====================
1253     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1254     if ( xWrappedObject.is() )
1255     {
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;
1259     }
1260     // end wrapping related part ====================
1261 
1262     // TODO: use lObjArgs
1263 
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
1268 
1269     ::osl::MutexGuard aGuard( m_aMutex );
1270     if ( m_bDisposed )
1271         throw lang::DisposedException(); // TODO
1272 
1273     if ( !xStorage.is() )
1274         throw lang::IllegalArgumentException( "No parent storage is provided!",
1275                                             static_cast< ::cppu::OWeakObject* >(this),
1276                                             1 );
1277 
1278     if ( sEntName.isEmpty() )
1279         throw lang::IllegalArgumentException( "Empty element name is provided!",
1280                                             static_cast< ::cppu::OWeakObject* >(this),
1281                                             2 );
1282 
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 ) )
1286     {
1287         // if the object is not loaded
1288         // it can not get persistent representation without initialization
1289 
1290         // if the object is loaded
1291         // it can switch persistent representation only without initialization
1292 
1293         throw embed::WrongStateException(
1294                     "Can't change persistent representation of activated object!",
1295                     static_cast< ::cppu::OWeakObject* >(this) );
1296     }
1297 
1298     if ( m_bWaitSaveCompleted )
1299     {
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 );
1305     }
1306 
1307     uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
1308 
1309     // detect entry existence
1310     bool bElExists = xNameAccess->hasByName( sEntName );
1311 
1312     m_bReadOnly = false;
1313     for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1314         if ( lArguments[nInd].Name == "ReadOnly" )
1315             lArguments[nInd].Value >>= m_bReadOnly;
1316 
1317 #ifdef _WIN32
1318     sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
1319 #endif
1320 
1321     SwitchOwnPersistence( xStorage, sEntName );
1322 
1323     for ( sal_Int32 nInd = 0; nInd < lObjArgs.getLength(); nInd++ )
1324         if ( lObjArgs[nInd].Name == "StoreVisualReplacement" )
1325             lObjArgs[nInd].Value >>= m_bStoreVisRepl;
1326 
1327 #ifdef _WIN32
1328     if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
1329     {
1330         if ( m_bFromClipboard )
1331         {
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 consruction
1336             m_pOleComponent->RunObject();
1337             m_nObjectState = embed::EmbedStates::RUNNING;
1338         }
1339         else if ( bElExists )
1340         {
1341             // load object from the stream
1342             // after the loading the object can appear as a link
1343             // will be detected by olecomponent
1344             try
1345             {
1346                 CreateOleComponentAndLoad_Impl();
1347                 m_aClassID = m_pOleComponent->GetCLSID(); // was not set during consruction
1348             }
1349             catch( const uno::Exception& )
1350             {
1351                 // TODO/LATER: detect classID of the object if possible
1352                 // means that the object inprocess server could not be successfully instantiated
1353                 GetRidOfComponent();
1354             }
1355 
1356             m_nObjectState = embed::EmbedStates::LOADED;
1357         }
1358         else
1359         {
1360             // create a new object
1361             CreateOleComponent_Impl();
1362             m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
1363             m_pOleComponent->RunObject();
1364             m_nObjectState = embed::EmbedStates::RUNNING;
1365         }
1366     }
1367     else
1368     {
1369         if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
1370             throw io::IOException();
1371 
1372         if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1373         {
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
1377         }
1378         else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
1379         {
1380             // create a new object, that will be stored in specified stream
1381             CreateOleComponent_Impl();
1382 
1383             m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
1384             m_pOleComponent->RunObject();
1385             m_nObjectState = embed::EmbedStates::RUNNING;
1386         }
1387         else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
1388         {
1389             // use URL ( may be content or stream later ) from MediaDescriptor to initialize object
1390             OUString aURL;
1391             for ( sal_Int32 nInd = 0; nInd < lArguments.getLength(); nInd++ )
1392                 if ( lArguments[nInd].Name == "URL" )
1393                     lArguments[nInd].Value >>= aURL;
1394 
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 );
1400 
1401             CreateOleComponent_Impl();
1402 
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 );
1408 
1409             m_pOleComponent->RunObject();
1410             m_aClassID = m_pOleComponent->GetCLSID(); // was not set during consruction
1411 
1412             m_nObjectState = embed::EmbedStates::RUNNING;
1413         }
1414         //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
1415         //{
1416             //TODO:
1417         //}
1418         else
1419             throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1420                                         static_cast< ::cppu::OWeakObject* >(this),
1421                                         3 );
1422     }
1423 #else
1424     // On Unix the OLE object can not do anything except storing itself somewhere
1425     if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT && bElExists )
1426     {
1427         // TODO/LATER: detect classID of the object
1428         // can be a real problem for the links
1429 
1430         m_nObjectState = embed::EmbedStates::LOADED;
1431     }
1432     else if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
1433     {
1434         // do nothing, the object has already switched it's persistence
1435     }
1436     else
1437         throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
1438                                     static_cast< ::cppu::OWeakObject* >(this),
1439                                     3 );
1440 
1441 #endif
1442 }
1443 
1444 
storeToEntry(const uno::Reference<embed::XStorage> & xStorage,const OUString & sEntName,const uno::Sequence<beans::PropertyValue> & lArguments,const uno::Sequence<beans::PropertyValue> & lObjArgs)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 )
1449 {
1450     // begin wrapping related part ====================
1451     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1452     if ( xWrappedObject.is() )
1453     {
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;
1457     }
1458     // end wrapping related part ====================
1459 
1460     ::osl::MutexGuard aGuard( m_aMutex );
1461     if ( m_bDisposed )
1462         throw lang::DisposedException(); // TODO
1463 
1464     VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1465 
1466     StoreToLocation_Impl( xStorage, sEntName, lObjArgs, false );
1467 
1468     // TODO: should the listener notification be done?
1469 }
1470 
1471 
storeAsEntry(const uno::Reference<embed::XStorage> & xStorage,const OUString & sEntName,const uno::Sequence<beans::PropertyValue> & lArguments,const uno::Sequence<beans::PropertyValue> & lObjArgs)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 )
1476 {
1477     // begin wrapping related part ====================
1478     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1479     if ( xWrappedObject.is() )
1480     {
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;
1484     }
1485     // end wrapping related part ====================
1486 
1487     ::osl::MutexGuard aGuard( m_aMutex );
1488     if ( m_bDisposed )
1489         throw lang::DisposedException(); // TODO
1490 
1491     VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1492 
1493     StoreToLocation_Impl( xStorage, sEntName, lObjArgs, true );
1494 
1495     // TODO: should the listener notification be done here or in saveCompleted?
1496 }
1497 
1498 
saveCompleted(sal_Bool bUseNew)1499 void SAL_CALL OleEmbeddedObject::saveCompleted( sal_Bool bUseNew )
1500 {
1501     // begin wrapping related part ====================
1502     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1503     if ( xWrappedObject.is() )
1504     {
1505         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1506         xWrappedObject->saveCompleted( bUseNew );
1507         return;
1508     }
1509     // end wrapping related part ====================
1510 
1511     osl::ClearableMutexGuard aGuard(m_aMutex);
1512     if ( m_bDisposed )
1513         throw lang::DisposedException(); // TODO
1514 
1515     if ( m_nObjectState == -1 )
1516     {
1517         // the object is still not loaded
1518         throw embed::WrongStateException( "Can't store object without persistence!",
1519                                         static_cast< ::cppu::OWeakObject* >(this) );
1520     }
1521 
1522     // it is allowed to call saveCompleted( false ) for nonstored objects
1523     if ( !m_bWaitSaveCompleted && !bUseNew )
1524         return;
1525 
1526     SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.ole", "Unexpected saveCompleted() call!" );
1527     if ( !m_bWaitSaveCompleted )
1528         throw io::IOException(); // TODO: illegal call
1529 
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
1533 
1534     if ( bUseNew )
1535     {
1536         SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStream, m_aNewEntryName );
1537         m_bStoreVisRepl = m_bNewVisReplInStream;
1538         SetVisReplInStream( m_bNewVisReplInStream );
1539         m_xCachedVisualRepresentation = m_xNewCachedVisRepl;
1540     }
1541     else
1542     {
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();
1549         }
1550         catch ( const uno::Exception& )
1551         {
1552         }
1553     }
1554 
1555     bool bStoreLoaded = m_bStoreLoaded;
1556 
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;
1564 
1565     if ( bUseNew && m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded
1566       && m_nObjectState != embed::EmbedStates::LOADED )
1567     {
1568         // the object replacement image should be updated, so the cached size as well
1569         m_bHasCachedSize = false;
1570         try
1571         {
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 );
1575         }
1576         catch( const uno::Exception& )
1577         {}
1578     }
1579 
1580     aGuard.clear();
1581     if ( bUseNew )
1582     {
1583         MakeEventListenerNotification_Impl( "OnSaveAsDone");
1584 
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 )
1588         {
1589             MakeEventListenerNotification_Impl( "OnVisAreaChanged");
1590         }
1591     }
1592 }
1593 
1594 
hasEntry()1595 sal_Bool SAL_CALL OleEmbeddedObject::hasEntry()
1596 {
1597     // begin wrapping related part ====================
1598     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1599     if ( xWrappedObject.is() )
1600     {
1601         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1602         return xWrappedObject->hasEntry();
1603     }
1604     // end wrapping related part ====================
1605 
1606     ::osl::MutexGuard aGuard( m_aMutex );
1607     if ( m_bDisposed )
1608         throw lang::DisposedException(); // TODO
1609 
1610     if ( m_bWaitSaveCompleted )
1611         throw embed::WrongStateException(
1612                     "The object waits for saveCompleted() call!",
1613                     static_cast< ::cppu::OWeakObject* >(this) );
1614 
1615     if ( m_xObjectStream.is() )
1616         return true;
1617 
1618     return false;
1619 }
1620 
1621 
getEntryName()1622 OUString SAL_CALL OleEmbeddedObject::getEntryName()
1623 {
1624     // begin wrapping related part ====================
1625     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1626     if ( xWrappedObject.is() )
1627     {
1628         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1629         return xWrappedObject->getEntryName();
1630     }
1631     // end wrapping related part ====================
1632 
1633     ::osl::MutexGuard aGuard( m_aMutex );
1634     if ( m_bDisposed )
1635         throw lang::DisposedException(); // TODO
1636 
1637     if ( m_nObjectState == -1 )
1638     {
1639         // the object is still not loaded
1640         throw embed::WrongStateException( "The object persistence is not initialized!",
1641                                         static_cast< ::cppu::OWeakObject* >(this) );
1642     }
1643 
1644     if ( m_bWaitSaveCompleted )
1645         throw embed::WrongStateException(
1646                     "The object waits for saveCompleted() call!",
1647                     static_cast< ::cppu::OWeakObject* >(this) );
1648 
1649     return m_aEntryName;
1650 }
1651 
1652 
storeOwn()1653 void SAL_CALL OleEmbeddedObject::storeOwn()
1654 {
1655     // begin wrapping related part ====================
1656     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1657     if ( xWrappedObject.is() )
1658     {
1659         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1660         xWrappedObject->storeOwn();
1661         return;
1662     }
1663     // end wrapping related part ====================
1664 
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
1668 
1669     osl::ClearableMutexGuard aGuard(m_aMutex);
1670     if ( m_bDisposed )
1671         throw lang::DisposedException(); // TODO
1672 
1673     VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
1674 
1675     if ( m_nObjectState == -1 )
1676     {
1677         // the object is still not loaded
1678         throw embed::WrongStateException( "Can't store object without persistence!",
1679                                     static_cast< ::cppu::OWeakObject* >(this) );
1680     }
1681 
1682     if ( m_bWaitSaveCompleted )
1683         throw embed::WrongStateException(
1684                     "The object waits for saveCompleted() call!",
1685                     static_cast< ::cppu::OWeakObject* >(this) );
1686 
1687     if ( m_bReadOnly )
1688         throw io::IOException(); // TODO: access denied
1689 
1690     LetCommonStoragePassBeUsed_Impl( m_xObjectStream );
1691 
1692     bool bStoreLoaded = true;
1693 
1694 #ifdef _WIN32
1695     if ( m_nObjectState != embed::EmbedStates::LOADED && m_pOleComponent && m_pOleComponent->IsDirty() )
1696     {
1697         bStoreLoaded = false;
1698 
1699         OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!" );
1700 
1701         if ( !m_xObjectStream.is() )
1702             throw io::IOException(); //TODO: access denied
1703 
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
1708 
1709         // TODO: does this work for links too?
1710         StoreObjectToStream( GetStreamForSaving() );
1711 
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 );
1716     }
1717 #endif
1718 
1719     if ( m_bStoreVisRepl != HasVisReplInStream() )
1720     {
1721         if ( m_bStoreVisRepl )
1722         {
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
1727             {
1728                 m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
1729                 SAL_WARN_IF( !m_xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
1730             }
1731         }
1732         else
1733         {
1734             if ( !m_xCachedVisualRepresentation.is() )
1735                 m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
1736             RemoveVisualCache_Impl( m_xObjectStream );
1737         }
1738 
1739         SetVisReplInStream( m_bStoreVisRepl );
1740     }
1741 
1742     if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
1743     {
1744         // the object replacement image should be updated, so the cached size as well
1745         m_bHasCachedSize = false;
1746         try
1747         {
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 );
1751         }
1752         catch( const uno::Exception& )
1753         {}
1754     }
1755 
1756     aGuard.clear();
1757 
1758     MakeEventListenerNotification_Impl( "OnSaveDone");
1759 
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");
1764 }
1765 
1766 
isReadonly()1767 sal_Bool SAL_CALL OleEmbeddedObject::isReadonly()
1768 {
1769     // begin wrapping related part ====================
1770     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1771     if ( xWrappedObject.is() )
1772     {
1773         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1774         return xWrappedObject->isReadonly();
1775     }
1776     // end wrapping related part ====================
1777 
1778     ::osl::MutexGuard aGuard( m_aMutex );
1779     if ( m_bDisposed )
1780         throw lang::DisposedException(); // TODO
1781 
1782     if ( m_nObjectState == -1 )
1783     {
1784         // the object is still not loaded
1785         throw embed::WrongStateException( "The object persistence is not initialized!",
1786                                         static_cast< ::cppu::OWeakObject* >(this) );
1787     }
1788 
1789     if ( m_bWaitSaveCompleted )
1790         throw embed::WrongStateException(
1791                     "The object waits for saveCompleted() call!",
1792                     static_cast< ::cppu::OWeakObject* >(this) );
1793 
1794     return m_bReadOnly;
1795 }
1796 
1797 
reload(const uno::Sequence<beans::PropertyValue> & lArguments,const uno::Sequence<beans::PropertyValue> & lObjArgs)1798 void SAL_CALL OleEmbeddedObject::reload(
1799                 const uno::Sequence< beans::PropertyValue >& lArguments,
1800                 const uno::Sequence< beans::PropertyValue >& lObjArgs )
1801 {
1802     // begin wrapping related part ====================
1803     uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1804     if ( xWrappedObject.is() )
1805     {
1806         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1807         xWrappedObject->reload( lArguments, lObjArgs );
1808         return;
1809     }
1810     // end wrapping related part ====================
1811 
1812     // TODO: use lObjArgs
1813 
1814     ::osl::MutexGuard aGuard( m_aMutex );
1815     if ( m_bDisposed )
1816         throw lang::DisposedException(); // TODO
1817 
1818     if ( m_nObjectState == -1 )
1819     {
1820         // the object is still not loaded
1821         throw embed::WrongStateException( "The object persistence is not initialized!",
1822                                         static_cast< ::cppu::OWeakObject* >(this) );
1823     }
1824 
1825     if ( m_bWaitSaveCompleted )
1826         throw embed::WrongStateException(
1827                     "The object waits for saveCompleted() call!",
1828                     static_cast< ::cppu::OWeakObject* >(this) );
1829 
1830     // TODO:
1831     // throw away current document
1832     // load new document from current storage
1833     // use meaningful part of lArguments
1834 }
1835 
1836 
breakLink(const uno::Reference<embed::XStorage> & xStorage,const OUString & sEntName)1837 void SAL_CALL OleEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
1838                                                 const OUString& sEntName )
1839 {
1840     // begin wrapping related part ====================
1841     uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1842     if ( xWrappedObject.is() )
1843     {
1844         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1845         xWrappedObject->breakLink( xStorage, sEntName );
1846         return;
1847     }
1848     // end wrapping related part ====================
1849 
1850     ::osl::MutexGuard aGuard( m_aMutex );
1851     if ( m_bDisposed )
1852         throw lang::DisposedException(); // TODO
1853 
1854     if ( !xStorage.is() )
1855         throw lang::IllegalArgumentException( "No parent storage is provided!",
1856                                             static_cast< ::cppu::OWeakObject* >(this),
1857                                             1 );
1858 
1859     if ( sEntName.isEmpty() )
1860         throw lang::IllegalArgumentException( "Empty element name is provided!",
1861                                             static_cast< ::cppu::OWeakObject* >(this),
1862                                             2 );
1863 
1864     // TODO: The object must be at least in Running state;
1865     if ( !m_bIsLink || m_nObjectState == -1 || !m_pOleComponent )
1866     {
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) );
1871     }
1872 
1873     if ( m_bReadOnly )
1874         throw io::IOException(); // TODO: Access denied
1875 
1876     if ( m_bWaitSaveCompleted )
1877         throw embed::WrongStateException(
1878                     "The object waits for saveCompleted() call!",
1879                     static_cast< ::cppu::OWeakObject* >(this) );
1880 
1881 
1882 #ifdef _WIN32
1883     // TODO: create an object based on the link
1884 
1885     // disconnect the old temporary URL
1886     OUString aOldTempURL = m_aTempURL;
1887     m_aTempURL.clear();
1888 
1889     OleComponent* pNewOleComponent = new OleComponent(m_xFactory, this);
1890     try {
1891         pNewOleComponent->InitEmbeddedCopyOfLink(m_pOleComponent);
1892     }
1893     catch (const uno::Exception&)
1894     {
1895         delete pNewOleComponent;
1896         if (!m_aTempURL.isEmpty())
1897             KillFile_Impl(m_aTempURL, m_xFactory);
1898         m_aTempURL = aOldTempURL;
1899         throw;
1900     }
1901 
1902     try {
1903         GetRidOfComponent();
1904     }
1905     catch (const uno::Exception&)
1906     {
1907         delete pNewOleComponent;
1908         if (!m_aTempURL.isEmpty())
1909             KillFile_Impl(m_aTempURL, m_xFactory);
1910         m_aTempURL = aOldTempURL;
1911         throw;
1912     }
1913 
1914     KillFile_Impl(aOldTempURL, m_xFactory);
1915 
1916     CreateOleComponent_Impl(pNewOleComponent);
1917 
1918     if (m_xParentStorage != xStorage || !m_aEntryName.equals(sEntName))
1919         SwitchOwnPersistence(xStorage, sEntName);
1920 
1921     if (m_nObjectState != embed::EmbedStates::LOADED)
1922     {
1923         // TODO: should we activate the new object if the link was activated?
1924 
1925         const sal_Int32 nTargetState = m_nObjectState;
1926         m_nObjectState = embed::EmbedStates::LOADED;
1927 
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
1931         {
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);
1934         }
1935 
1936         m_nObjectState = nTargetState;
1937     }
1938 
1939     m_bIsLink = false;
1940     m_aLinkURL.clear();
1941 #else // ! _WIN32
1942     throw io::IOException(); //TODO:
1943 #endif // _WIN32
1944 }
1945 
1946 
isLink()1947 sal_Bool SAL_CALL  OleEmbeddedObject::isLink()
1948 {
1949     // begin wrapping related part ====================
1950     uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1951     if ( xWrappedObject.is() )
1952     {
1953         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1954         return xWrappedObject->isLink();
1955     }
1956     // end wrapping related part ====================
1957 
1958     ::osl::MutexGuard aGuard( m_aMutex );
1959     if ( m_bDisposed )
1960         throw lang::DisposedException(); // TODO
1961 
1962     return m_bIsLink;
1963 }
1964 
1965 
getLinkURL()1966 OUString SAL_CALL OleEmbeddedObject::getLinkURL()
1967 {
1968     // begin wrapping related part ====================
1969     uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
1970     if ( xWrappedObject.is() )
1971     {
1972         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1973         return xWrappedObject->getLinkURL();
1974     }
1975     // end wrapping related part ====================
1976 
1977     ::osl::MutexGuard aGuard( m_aMutex );
1978     if ( m_bDisposed )
1979         throw lang::DisposedException(); // TODO
1980 
1981     if ( m_bWaitSaveCompleted )
1982         throw embed::WrongStateException(
1983                     "The object waits for saveCompleted() call!",
1984                     static_cast< ::cppu::OWeakObject* >(this) );
1985 
1986     if ( !m_bIsLink )
1987         throw embed::WrongStateException(
1988                     "The object is not a link object!",
1989                     static_cast< ::cppu::OWeakObject* >(this) );
1990 
1991     // TODO: probably the link URL can be retrieved from OLE
1992 
1993     return m_aLinkURL;
1994 }
1995 
1996 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1997