1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_embeddedobj.hxx"
26 
27 #include <oleembobj.hxx>
28 #include <com/sun/star/embed/EmbedStates.hpp>
29 #include <com/sun/star/embed/EmbedVerbs.hpp>
30 #include <com/sun/star/embed/EntryInitModes.hpp>
31 #include <com/sun/star/embed/XStorage.hpp>
32 #include <com/sun/star/embed/ElementModes.hpp>
33 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
34 #include <com/sun/star/embed/Aspects.hpp>
35 #include <com/sun/star/embed/NeedsRunningStateException.hpp>
36 #include <com/sun/star/embed/StateChangeInProgressException.hpp>
37 #include <com/sun/star/embed/EmbedMisc.hpp>
38 #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
39 #include <com/sun/star/io/XSeekable.hpp>
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include <com/sun/star/beans/NamedValue.hpp>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/frame/XLoadable.hpp>
44 #include <com/sun/star/document/XStorageBasedDocument.hpp>
45 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
46 #include <com/sun/star/container/XNameAccess.hpp>
47 #include <com/sun/star/container/XNameContainer.hpp>
48 #include <com/sun/star/system/SystemShellExecute.hpp>
49 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
50 
51 #include <rtl/logfile.hxx>
52 #include <cppuhelper/interfacecontainer.h>
53 #include <comphelper/mimeconfighelper.hxx>
54 #include <comphelper/storagehelper.hxx>
55 #include <comphelper/processfactory.hxx>
56 
57 #include <targetstatecontrol.hxx>
58 
59 #include <olecomponent.hxx>
60 
61 #include "ownview.hxx"
62 
63 using namespace ::com::sun::star;
64 
65 #ifdef WNT
66 //----------------------------------------------
SwitchComponentToRunningState_Impl()67 void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
68 {
69 	if ( m_pOleComponent )
70 	{
71 		try
72 		{
73 			m_pOleComponent->RunObject();
74 		}
75 		catch( embed::UnreachableStateException& )
76 		{
77 			GetRidOfComponent();
78 			throw;
79 		}
80 		catch( embed::WrongStateException& )
81 		{
82 			GetRidOfComponent();
83 			throw;
84 		}
85 	}
86 	else
87 	{
88 		throw embed::UnreachableStateException();
89 	}
90 }
91 
92 //----------------------------------------------
GetReachableStatesList_Impl(const uno::Sequence<embed::VerbDescriptor> & aVerbList)93 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl(
94 														const uno::Sequence< embed::VerbDescriptor >& aVerbList )
95 {
96 	uno::Sequence< sal_Int32 > aStates(2);
97 	aStates[0] = embed::EmbedStates::LOADED;
98 	aStates[1] = embed::EmbedStates::RUNNING;
99 	for ( sal_Int32 nInd = 0; nInd < aVerbList.getLength(); nInd++ )
100 		if ( aVerbList[nInd].VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
101 		{
102 			aStates.realloc(3);
103 			aStates[2] = embed::EmbedStates::ACTIVE;
104 		}
105 
106 	return aStates;
107 }
108 
109 //----------------------------------------------
GetIntermediateVerbsSequence_Impl(sal_Int32 nNewState)110 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState )
111 {
112 	OSL_ENSURE( m_nObjectState != embed::EmbedStates::LOADED, "Loaded object is switched to running state without verbs using!" );
113 
114 	// actually there will be only one verb
115 	if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
116 	{
117 		uno::Sequence< sal_Int32 > aVerbs( 1 );
118 		aVerbs[0] = embed::EmbedVerbs::MS_OLEVERB_OPEN;
119 	}
120 
121 	return uno::Sequence< sal_Int32 >();
122 }
123 #endif
124 //----------------------------------------------
MoveListeners()125 void OleEmbeddedObject::MoveListeners()
126 {
127 	if ( m_pInterfaceContainer )
128 	{
129         // move state change listeners
130         {
131             ::cppu::OInterfaceContainerHelper* pStateChangeContainer =
132                 m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< embed::XStateChangeListener >*) NULL ) );
133             if ( pStateChangeContainer != NULL )
134             {
135                 uno::Reference< embed::XStateChangeBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
136                 if ( xWrappedObject.is() )
137                 {
138                     ::cppu::OInterfaceIteratorHelper pIterator( *pStateChangeContainer );
139                     while ( pIterator.hasMoreElements() )
140                     {
141                         try
142                         {
143                             xWrappedObject->addStateChangeListener( (embed::XStateChangeListener*)pIterator.next() );
144                         }
145                         catch( uno::RuntimeException& )
146                         {
147                             pIterator.remove();
148                         }
149                     }
150                 }
151             }
152         }
153 
154         // move event listeners
155         {
156             ::cppu::OInterfaceContainerHelper* pEventContainer =
157                 m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< document::XEventListener >*) NULL ) );
158             if ( pEventContainer != NULL )
159             {
160                 uno::Reference< document::XEventBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
161                 if ( xWrappedObject.is() )
162                 {
163                     ::cppu::OInterfaceIteratorHelper pIterator( *pEventContainer );
164                     while ( pIterator.hasMoreElements() )
165                     {
166                         try
167                         {
168                             xWrappedObject->addEventListener( (document::XEventListener*)pIterator.next() );
169                         }
170                         catch( uno::RuntimeException& )
171                         {
172                             pIterator.remove();
173                         }
174                     }
175                 }
176             }
177         }
178 
179         // move close listeners
180         {
181             ::cppu::OInterfaceContainerHelper* pCloseContainer =
182                 m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< util::XCloseListener >*) NULL ) );
183             if ( pCloseContainer != NULL )
184             {
185                 uno::Reference< util::XCloseBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
186                 if ( xWrappedObject.is() )
187                 {
188                     ::cppu::OInterfaceIteratorHelper pIterator( *pCloseContainer );
189                     while ( pIterator.hasMoreElements() )
190                     {
191                         try
192                         {
193                             xWrappedObject->addCloseListener( (util::XCloseListener*)pIterator.next() );
194                         }
195                         catch( uno::RuntimeException& )
196                         {
197                             pIterator.remove();
198                         }
199                     }
200                 }
201             }
202         }
203 
204         delete m_pInterfaceContainer;
205         m_pInterfaceContainer = NULL;
206     }
207 }
208 
209 //----------------------------------------------
CreateTemporarySubstorage(::rtl::OUString & o_aStorageName)210 uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( ::rtl::OUString& o_aStorageName )
211 {
212     uno::Reference< embed::XStorage > xResult;
213 
214     for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ )
215     {
216         ::rtl::OUString aName = ::rtl::OUString::valueOf( nInd );
217         aName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TMPSTOR" ) );
218         aName += m_aEntryName;
219         if ( !m_xParentStorage->hasByName( aName ) )
220         {
221             xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE );
222             o_aStorageName = aName;
223         }
224     }
225 
226     if ( !xResult.is() )
227     {
228         o_aStorageName = ::rtl::OUString();
229         throw uno::RuntimeException();
230     }
231 
232     return xResult;
233 }
234 
235 //----------------------------------------------
MoveToTemporarySubstream()236 ::rtl::OUString OleEmbeddedObject::MoveToTemporarySubstream()
237 {
238     ::rtl::OUString aResult;
239     for ( sal_Int32 nInd = 0; nInd < 32000 && !aResult.getLength(); nInd++ )
240     {
241         ::rtl::OUString aName = ::rtl::OUString::valueOf( nInd );
242         aName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TMPSTREAM" ) );
243         aName += m_aEntryName;
244         if ( !m_xParentStorage->hasByName( aName ) )
245         {
246             m_xParentStorage->renameElement( m_aEntryName, aName );
247             aResult = aName;
248         }
249     }
250 
251     if ( !aResult.getLength() )
252         throw uno::RuntimeException();
253 
254     return aResult;
255 }
256 
257 //----------------------------------------------
TryToConvertToOOo()258 sal_Bool OleEmbeddedObject::TryToConvertToOOo()
259 {
260     sal_Bool bResult = sal_False;
261 
262     ::rtl::OUString aStorageName;
263     ::rtl::OUString aTmpStreamName;
264     sal_Int32 nStep = 0;
265 
266     if ( m_pOleComponent || m_bReadOnly )
267         return sal_False;
268 
269     try
270     {
271         changeState( embed::EmbedStates::LOADED );
272 
273         // the stream must be seekable
274         uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY_THROW );
275         xSeekable->seek( 0 );
276         ::rtl::OUString aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xFactory, ::rtl::OUString(), m_xObjectStream->getInputStream() );
277 
278         // use the solution only for OOXML format currently
279         if ( aFilterName.getLength()
280           && ( aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "Calc MS Excel 2007 XML" ) ) )
281             || aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "Impress MS PowerPoint 2007 XML" ) ) )
282             || aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "MS Word 2007 XML" ) ) ) ) )
283         {
284             uno::Reference< container::XNameAccess > xFilterFactory(
285 			    m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ),
286 			    uno::UNO_QUERY_THROW );
287 
288             ::rtl::OUString aDocServiceName;
289 		    uno::Any aFilterAnyData = xFilterFactory->getByName( aFilterName );
290 		    uno::Sequence< beans::PropertyValue > aFilterData;
291 		    if ( aFilterAnyData >>= aFilterData )
292 		    {
293 			    for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
294 				    if ( aFilterData[nInd].Name.equalsAscii( "DocumentService" ) )
295 					    aFilterData[nInd].Value >>= aDocServiceName;
296 		    }
297 
298             if ( aDocServiceName.getLength() )
299             {
300                 // create the model
301                 uno::Sequence< uno::Any > aArguments(1);
302                 aArguments[0] <<= beans::NamedValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EmbeddedObject" ) ), uno::makeAny( (sal_Bool)sal_True ));
303 
304                 uno::Reference< util::XCloseable > xDocument( m_xFactory->createInstanceWithArguments( aDocServiceName, aArguments ), uno::UNO_QUERY_THROW );
305                 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
306                 uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW );
307 
308                 // let the model behave as embedded one
309                 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW );
310 		        uno::Sequence< beans::PropertyValue > aSeq( 1 );
311 		        aSeq[0].Name = ::rtl::OUString::createFromAscii( "SetEmbedded" );
312 		        aSeq[0].Value <<= sal_True;
313 		        xModel->attachResource( ::rtl::OUString(), aSeq );
314 
315                 // load the model from the stream
316 	            uno::Sequence< beans::PropertyValue > aArgs( 5 );
317                 aArgs[0].Name = ::rtl::OUString::createFromAscii( "HierarchicalDocumentName" );
318                 aArgs[0].Value <<= m_aEntryName;
319 	            aArgs[1].Name = ::rtl::OUString::createFromAscii( "ReadOnly" );
320 	            aArgs[1].Value <<= sal_True;
321 	            aArgs[2].Name = ::rtl::OUString::createFromAscii( "FilterName" );
322 	            aArgs[2].Value <<= aFilterName;
323                 aArgs[3].Name = ::rtl::OUString::createFromAscii( "URL" );
324                 aArgs[3].Value <<= ::rtl::OUString::createFromAscii( "private:stream" );
325                 aArgs[4].Name = ::rtl::OUString::createFromAscii( "InputStream" );
326                 aArgs[4].Value <<= m_xObjectStream->getInputStream();
327 
328                 xSeekable->seek( 0 );
329                 xLoadable->load( aArgs );
330 
331                 // the model is successfuly loaded, create a new storage and store the model to the storage
332                 uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName );
333                 xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() );
334                 xDocument->close( sal_True );
335                 uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW );
336                 ::rtl::OUString aMediaType;
337                 xStorProps->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ) >>= aMediaType;
338                 xTmpStorage->dispose();
339 
340                 // look for the related embedded object factory
341                 ::comphelper::MimeConfigurationHelper aConfigHelper( m_xFactory );
342                 ::rtl::OUString aEmbedFactory;
343 	            if ( aMediaType.getLength() )
344 		            aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType );
345 
346 	            if ( !aEmbedFactory.getLength() )
347                     throw uno::RuntimeException();
348 
349                 uno::Reference< uno::XInterface > xFact = m_xFactory->createInstance( aEmbedFactory );
350 
351 		        uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW );
352 
353                 // now the object should be adjusted to become the wrapper
354                 nStep = 1;
355 		        uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW );
356 				xComp->dispose();
357 		        m_xObjectStream = uno::Reference< io::XStream >();
358                 m_nObjectState = -1;
359 
360                 nStep = 2;
361                 aTmpStreamName = MoveToTemporarySubstream();
362 
363                 nStep = 3;
364                 m_xParentStorage->renameElement( aStorageName, m_aEntryName );
365 
366                 nStep = 4;
367 		        m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW );
368 
369                 bResult = sal_True; // the change is no more revertable
370                 try
371                 {
372                     m_xParentStorage->removeElement( aTmpStreamName );
373                 }
374                 catch( uno::Exception& )
375                 {
376                     // the success of the removing is not so important
377                 }
378             }
379         }
380     }
381     catch( uno::Exception& )
382     {
383         // repair the object if necessary
384         switch( nStep )
385         {
386             case 4:
387             case 3:
388             if ( aTmpStreamName.getLength() && aTmpStreamName != m_aEntryName )
389                 try
390                 {
391                     if ( m_xParentStorage->hasByName( m_aEntryName ) )
392                         m_xParentStorage->removeElement( m_aEntryName );
393                     m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName );
394                 }
395                 catch ( uno::Exception& )
396                 {
397                     try {
398                         close( sal_True );
399                     } catch( uno::Exception& ) {}
400 
401                     m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without commiting!
402                     throw uno::RuntimeException(); // the repairing is not possible
403                 }
404             case 2:
405                 try
406                 {
407                     m_xObjectStream = m_xParentStorage->openStreamElement( m_aEntryName, m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
408                     m_nObjectState = embed::EmbedStates::LOADED;
409                 }
410                 catch( uno::Exception& )
411                 {
412                     try {
413                         close( sal_True );
414                     } catch( uno::Exception& ) {}
415 
416                     throw uno::RuntimeException(); // the repairing is not possible
417                 }
418                 // no break as designed!
419 
420             case 1:
421             case 0:
422                 if ( aStorageName.getLength() )
423                     try {
424                         m_xParentStorage->removeElement( aStorageName );
425                     } catch( uno::Exception& ) { OSL_ASSERT( "Can not remove temporary storage!" ); }
426                 break;
427         }
428     }
429 
430     if ( bResult )
431     {
432         // the conversion was done successfuly, now the additional initializations should happen
433 
434         MoveListeners();
435         m_xWrappedObject->setClientSite( m_xClientSite );
436         if ( m_xParent.is() )
437         {
438             uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY );
439             if ( xChild.is() )
440                 xChild->setParent( m_xParent );
441         }
442 
443     }
444 
445     return bResult;
446 }
447 
448 //----------------------------------------------
changeState(sal_Int32 nNewState)449 void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState )
450 		throw ( embed::UnreachableStateException,
451 				embed::WrongStateException,
452 				uno::Exception,
453 				uno::RuntimeException )
454 {
455 	RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::changeState" );
456 
457     // begin wrapping related part ====================
458     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
459     if ( xWrappedObject.is() )
460     {
461         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
462         xWrappedObject->changeState( nNewState );
463         return;
464     }
465     // end wrapping related part ====================
466 
467 	::osl::ResettableMutexGuard aGuard( m_aMutex );
468 
469 	if ( m_bDisposed )
470 		throw lang::DisposedException(); // TODO
471 
472 	if ( m_nObjectState == -1 )
473 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
474 										uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
475 
476 	// in case the object is already in requested state
477 	if ( m_nObjectState == nNewState )
478 		return;
479 
480 #ifdef WNT
481 	if ( m_pOleComponent )
482 	{
483 		if ( m_nTargetState != -1 )
484 		{
485 			// means that the object is currently trying to reach the target state
486 			throw embed::StateChangeInProgressException( ::rtl::OUString(),
487 														uno::Reference< uno::XInterface >(),
488 														m_nTargetState );
489 		}
490 
491 		TargetStateControl_Impl aControl( m_nTargetState, nNewState );
492 
493 		// TODO: additional verbs can be a problem, since nobody knows how the object
494 		//		 will behave after activation
495 
496 		sal_Int32 nOldState = m_nObjectState;
497 		aGuard.clear();
498 		StateChangeNotification_Impl( sal_True, nOldState, nNewState );
499 		aGuard.reset();
500 
501 		try
502 		{
503 			if ( nNewState == embed::EmbedStates::LOADED )
504 			{
505 				// This means just closing of the current object
506 				// If component can not be closed the object stays in loaded state
507 				// and it holds reference to "incomplete" component
508 				// If the object is switched to running state later
509 				// the component will become "complete"
510 
511 				// the loaded state must be set before, because of notifications!
512 				m_nObjectState = nNewState;
513 
514 				{
515 					VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
516 					m_pOleComponent->CloseObject();
517 				}
518 
519 				// GetRidOfComponent();
520 				aGuard.clear();
521 				StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
522 				aGuard.reset();
523 			}
524 			else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
525 			{
526 				if ( m_nObjectState == embed::EmbedStates::LOADED )
527 				{
528 					// if the target object is in loaded state and a different state is specified
529 					// as a new one the object first must be switched to running state.
530 
531 					// the component can exist already in nonrunning state
532 					// it can be created during loading to detect type of object
533 					CreateOleComponentAndLoad_Impl( m_pOleComponent );
534 
535 					SwitchComponentToRunningState_Impl();
536 					m_nObjectState = embed::EmbedStates::RUNNING;
537 					aGuard.clear();
538 					StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
539 					aGuard.reset();
540 
541 					if ( m_pOleComponent && m_bHasSizeToSet )
542 					{
543 						aGuard.clear();
544 						try {
545 							m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
546 							m_bHasSizeToSet = sal_False;
547 						}
548 						catch( uno::Exception& ) {}
549 						aGuard.reset();
550 					}
551 
552 					if ( m_nObjectState == nNewState )
553 						return;
554 				}
555 
556 				// so now the object is either switched from Active to Running state or vise versa
557 				// the notification about object state change will be done asynchronously
558 				if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
559 				{
560 					// execute OPEN verb, if object does not reach active state it is an object's problem
561 					aGuard.clear();
562 					m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
563 					aGuard.reset();
564 
565 					// some objects do not allow to set the size even in running state
566 					if ( m_pOleComponent && m_bHasSizeToSet )
567 					{
568 						aGuard.clear();
569 						try {
570 							m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
571 							m_bHasSizeToSet = sal_False;
572 						}
573 						catch( uno::Exception& ) {}
574 						aGuard.reset();
575 					}
576 
577 					m_nObjectState = nNewState;
578 				}
579 				else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
580 				{
581 					aGuard.clear();
582 					m_pOleComponent->CloseObject();
583 					m_pOleComponent->RunObject(); // Should not fail, the object already was active
584 					aGuard.reset();
585 					m_nObjectState = nNewState;
586 				}
587 				else
588 				{
589 					throw embed::UnreachableStateException();
590 				}
591 			}
592 			else
593 				throw embed::UnreachableStateException();
594 		}
595 		catch( uno::Exception& )
596 		{
597 			aGuard.clear();
598 			StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
599 			throw;
600 		}
601 	}
602 	else
603 #endif
604 	{
605 		throw embed::UnreachableStateException();
606 	}
607 }
608 
609 //----------------------------------------------
getReachableStates()610 uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
611 		throw ( embed::WrongStateException,
612 				uno::RuntimeException )
613 {
614 	RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getReachableStates" );
615 
616     // begin wrapping related part ====================
617     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
618     if ( xWrappedObject.is() )
619     {
620         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
621         return xWrappedObject->getReachableStates();
622     }
623     // end wrapping related part ====================
624 
625 	::osl::MutexGuard aGuard( m_aMutex );
626 	if ( m_bDisposed )
627 		throw lang::DisposedException(); // TODO
628 
629 	if ( m_nObjectState == -1 )
630 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
631 										uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
632 
633 #ifdef WNT
634 	if ( m_pOleComponent )
635 	{
636 		if ( m_nObjectState == embed::EmbedStates::LOADED )
637 		{
638 			// the list of supported verbs can be retrieved only when object is in running state
639 			throw embed::NeedsRunningStateException(); // TODO:
640 		}
641 
642 		// the list of states can only be guessed based on standard verbs,
643 		// since there is no way to detect what additional verbs do
644 		return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
645 	}
646 	else
647 #endif
648 	{
649 		return uno::Sequence< sal_Int32 >();
650 	}
651 }
652 
653 //----------------------------------------------
getCurrentState()654 sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState()
655 		throw ( embed::WrongStateException,
656 				uno::RuntimeException )
657 {
658     // begin wrapping related part ====================
659     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
660     if ( xWrappedObject.is() )
661     {
662         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
663         return xWrappedObject->getCurrentState();
664     }
665     // end wrapping related part ====================
666 
667 	::osl::MutexGuard aGuard( m_aMutex );
668 	if ( m_bDisposed )
669 		throw lang::DisposedException(); // TODO
670 
671 	if ( m_nObjectState == -1 )
672 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
673 										uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
674 
675 	// TODO: Shouldn't we ask object? ( I guess no )
676 	return m_nObjectState;
677 }
678 
679 namespace
680 {
lcl_CopyStream(uno::Reference<io::XInputStream> xIn,uno::Reference<io::XOutputStream> xOut)681     bool lcl_CopyStream(uno::Reference<io::XInputStream> xIn, uno::Reference<io::XOutputStream> xOut)
682     {
683         const sal_Int32 nChunkSize = 4096;
684         uno::Sequence< sal_Int8 > aData(nChunkSize);
685         sal_Int32 nTotalRead = 0;
686         sal_Int32 nRead;
687         do
688         {
689             nRead = xIn->readBytes(aData, nChunkSize);
690             nTotalRead += nRead;
691             xOut->writeBytes(aData);
692         } while (nRead == nChunkSize);
693         return nTotalRead != 0;
694     }
695 
696     //Dump the objects content to a tempfile, just the "CONTENTS" stream if
697     //there is one for non-compound documents, otherwise the whole content.
698     //
699     //On success a file is returned which must be removed by the caller
lcl_ExtractObject(::com::sun::star::uno::Reference<::com::sun::star::lang::XMultiServiceFactory> xFactory,::com::sun::star::uno::Reference<::com::sun::star::io::XStream> xObjectStream)700     rtl::OUString lcl_ExtractObject(::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory,
701         ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > xObjectStream)
702     {
703         rtl::OUString sUrl;
704 
705         // the solution is only active for Unix systems
706 #ifndef WNT
707         uno::Reference <beans::XPropertySet> xNativeTempFile(
708             xFactory->createInstance(
709                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.io.TempFile"))), uno::UNO_QUERY_THROW);
710         uno::Reference < io::XStream > xStream(xNativeTempFile, uno::UNO_QUERY_THROW);
711 
712         uno::Sequence< uno::Any > aArgs( 2 );
713         aArgs[0] <<= xObjectStream;
714         aArgs[1] <<= (sal_Bool)sal_True; // do not create copy
715         uno::Reference< container::XNameContainer > xNameContainer(
716             xFactory->createInstanceWithArguments(
717                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.OLESimpleStorage")),
718                 aArgs ), uno::UNO_QUERY_THROW );
719 
720         uno::Reference< io::XStream > xCONTENTS;
721         xNameContainer->getByName(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CONTENTS"))) >>= xCONTENTS;
722 
723         sal_Bool bCopied = xCONTENTS.is() && lcl_CopyStream(xCONTENTS->getInputStream(), xStream->getOutputStream());
724 
725         uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
726         if (xSeekableStor.is())
727             xSeekableStor->seek(0);
728 
729         if (!bCopied)
730             bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
731 
732         if (bCopied)
733         {
734             xNativeTempFile->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RemoveFile")),
735                 uno::makeAny(sal_False));
736             uno::Any aUrl = xNativeTempFile->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Uri")));
737             aUrl >>= sUrl;
738 
739             xNativeTempFile = uno::Reference<beans::XPropertySet>();
740 
741             uno::Reference<ucb::XSimpleFileAccess> xSimpleFileAccess(
742                 xFactory->createInstance(
743                     ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SimpleFileAccess"))),
744                     uno::UNO_QUERY_THROW);
745 
746             xSimpleFileAccess->setReadOnly(sUrl, sal_True);
747         }
748         else
749         {
750             xNativeTempFile->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RemoveFile")),
751                 uno::makeAny(sal_True));
752         }
753 #endif
754         return sUrl;
755     }
756 }
757 
758 //----------------------------------------------
doVerb(sal_Int32 nVerbID)759 void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
760 		throw ( lang::IllegalArgumentException,
761 				embed::WrongStateException,
762 				embed::UnreachableStateException,
763 				uno::Exception,
764 				uno::RuntimeException )
765 {
766 	RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::doVerb" );
767 
768     // begin wrapping related part ====================
769     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
770     if ( xWrappedObject.is() )
771     {
772         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
773         xWrappedObject->doVerb( nVerbID );
774         return;
775     }
776     // end wrapping related part ====================
777 
778 	::osl::ResettableMutexGuard aGuard( m_aMutex );
779 	if ( m_bDisposed )
780 		throw lang::DisposedException(); // TODO
781 
782 	if ( m_nObjectState == -1 )
783 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
784 										uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
785 
786 #ifdef WNT
787 	if ( m_pOleComponent )
788 	{
789 		sal_Int32 nOldState = m_nObjectState;
790 
791 		// TODO/LATER detect target state here and do a notification
792 		// StateChangeNotification_Impl( sal_True, nOldState, nNewState );
793 		if ( m_nObjectState == embed::EmbedStates::LOADED )
794 		{
795 			// if the target object is in loaded state
796 			// it must be switched to running state to execute verb
797 			aGuard.clear();
798 			changeState( embed::EmbedStates::RUNNING );
799 			aGuard.reset();
800 		}
801 
802 		try {
803 			if ( !m_pOleComponent )
804 				throw uno::RuntimeException();
805 
806 			// ==== the STAMPIT related solution =============================
807 			m_aVerbExecutionController.StartControlExecution();
808 			// ===============================================================
809 
810 			m_pOleComponent->ExecuteVerb( nVerbID );
811 
812 			// ==== the STAMPIT related solution =============================
813 			sal_Bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
814 
815 			// this workaround is implemented for STAMPIT object
816 			// if object was modified during verb execution it is saved here
817 			if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
818 				SaveObject_Impl();
819 			// ===============================================================
820 		}
821 		catch( uno::Exception& )
822 		{
823 			// ==== the STAMPIT related solution =============================
824 			m_aVerbExecutionController.EndControlExecution_WasModified();
825 			// ===============================================================
826 
827 			aGuard.clear();
828 			StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
829 			throw;
830 		}
831 
832 		// the following notification will be done asynchronously
833 		// StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
834 	}
835 	else
836 #endif
837 	{
838 		if ( nVerbID == -9 )
839 		{
840 			// the workaround verb to show the object in case no server is available
841 
842             // if it is possible, the object will be converted to OOo format
843             if ( !m_bTriedConversion )
844             {
845                 m_bTriedConversion = sal_True;
846                 if ( TryToConvertToOOo() )
847                 {
848                     changeState( embed::EmbedStates::UI_ACTIVE );
849                     return;
850                 }
851             }
852 
853 			if ( !m_pOwnView && m_xObjectStream.is() )
854 			{
855 				try {
856 					uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
857 					if ( xSeekable.is() )
858 						xSeekable->seek( 0 );
859 
860 					m_pOwnView = new OwnView_Impl( m_xFactory, m_xObjectStream->getInputStream() );
861 					m_pOwnView->acquire();
862 				}
863 				catch( uno::RuntimeException& )
864 				{
865 					throw;
866 				}
867 				catch( uno::Exception& )
868 				{
869 				}
870 			}
871 
872             if ( !m_pOwnView || !m_pOwnView->Open() )
873             {
874                 //Make a RO copy and see if the OS can find something to at
875                 //least display the content for us
876                 if (!m_aTempDumpURL.getLength())
877                     m_aTempDumpURL = lcl_ExtractObject(m_xFactory, m_xObjectStream);
878 
879                 if (m_aTempDumpURL.getLength())
880                 {
881                     uno::Reference< ::com::sun::star::system::XSystemShellExecute > xSystemShellExecute(
882                         ::com::sun::star::system::SystemShellExecute::create(
883                             ::comphelper::getProcessComponentContext() ) );
884                     xSystemShellExecute->execute(m_aTempDumpURL, ::rtl::OUString(), ::com::sun::star::system::SystemShellExecuteFlags::DEFAULTS);
885                 }
886                 else
887                     throw embed::UnreachableStateException();
888             }
889 		}
890 		else
891 		{
892 
893 			throw embed::UnreachableStateException();
894 		}
895 	}
896 }
897 
898 //----------------------------------------------
getSupportedVerbs()899 uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
900 		throw ( embed::WrongStateException,
901 				uno::RuntimeException )
902 {
903 	RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getSupportedVerb" );
904 
905     // begin wrapping related part ====================
906     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
907     if ( xWrappedObject.is() )
908     {
909         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
910         return xWrappedObject->getSupportedVerbs();
911     }
912     // end wrapping related part ====================
913 
914 	::osl::MutexGuard aGuard( m_aMutex );
915 	if ( m_bDisposed )
916 		throw lang::DisposedException(); // TODO
917 
918 	if ( m_nObjectState == -1 )
919 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
920 										uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
921 #ifdef WNT
922 	if ( m_pOleComponent )
923 	{
924 		// registry could be used in this case
925 		// if ( m_nObjectState == embed::EmbedStates::LOADED )
926 		// {
927 		// 	// the list of supported verbs can be retrieved only when object is in running state
928 		// 	throw embed::NeedsRunningStateException(); // TODO:
929 		// }
930 
931 		return m_pOleComponent->GetVerbList();
932 	}
933 	else
934 #endif
935 	{
936 		return uno::Sequence< embed::VerbDescriptor >();
937 	}
938 }
939 
940 //----------------------------------------------
setClientSite(const uno::Reference<embed::XEmbeddedClient> & xClient)941 void SAL_CALL OleEmbeddedObject::setClientSite(
942 				const uno::Reference< embed::XEmbeddedClient >& xClient )
943 		throw ( embed::WrongStateException,
944 				uno::RuntimeException )
945 {
946     // begin wrapping related part ====================
947     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
948     if ( xWrappedObject.is() )
949     {
950         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
951         xWrappedObject->setClientSite( xClient );
952         return;
953     }
954     // end wrapping related part ====================
955 
956 	::osl::MutexGuard aGuard( m_aMutex );
957 	if ( m_bDisposed )
958 		throw lang::DisposedException(); // TODO
959 
960 	if ( m_xClientSite != xClient)
961 	{
962 		if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
963 			throw embed::WrongStateException(
964 									::rtl::OUString::createFromAscii( "The client site can not be set currently!\n" ),
965 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
966 
967 		m_xClientSite = xClient;
968 	}
969 }
970 
971 //----------------------------------------------
getClientSite()972 uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
973 		throw ( embed::WrongStateException,
974 				uno::RuntimeException )
975 {
976     // begin wrapping related part ====================
977     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
978     if ( xWrappedObject.is() )
979     {
980         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
981         return xWrappedObject->getClientSite();
982     }
983     // end wrapping related part ====================
984 
985 	::osl::MutexGuard aGuard( m_aMutex );
986 	if ( m_bDisposed )
987 		throw lang::DisposedException(); // TODO
988 
989 	if ( m_nObjectState == -1 )
990 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
991 										uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
992 
993 	return m_xClientSite;
994 }
995 
996 //----------------------------------------------
update()997 void SAL_CALL OleEmbeddedObject::update()
998 		throw ( embed::WrongStateException,
999 				uno::Exception,
1000 				uno::RuntimeException )
1001 {
1002     // begin wrapping related part ====================
1003     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1004     if ( xWrappedObject.is() )
1005     {
1006         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1007         xWrappedObject->update();
1008         return;
1009     }
1010     // end wrapping related part ====================
1011 
1012 	::osl::MutexGuard aGuard( m_aMutex );
1013 	if ( m_bDisposed )
1014 		throw lang::DisposedException(); // TODO
1015 
1016 	if ( m_nObjectState == -1 )
1017 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
1018 										uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1019 
1020 	if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
1021 	{
1022 		// TODO: update view representation
1023 	}
1024 	else
1025 	{
1026 		// the object must be up to date
1027 		OSL_ENSURE( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE, "Unknown update mode!\n" );
1028 	}
1029 }
1030 
1031 //----------------------------------------------
setUpdateMode(sal_Int32 nMode)1032 void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
1033 		throw ( embed::WrongStateException,
1034 				uno::RuntimeException )
1035 {
1036     // begin wrapping related part ====================
1037     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1038     if ( xWrappedObject.is() )
1039     {
1040         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1041         xWrappedObject->setUpdateMode( nMode );
1042         return;
1043     }
1044     // end wrapping related part ====================
1045 
1046 	::osl::MutexGuard aGuard( m_aMutex );
1047 	if ( m_bDisposed )
1048 		throw lang::DisposedException(); // TODO
1049 
1050 	if ( m_nObjectState == -1 )
1051 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
1052 										uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1053 
1054 	OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
1055 					|| nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
1056 				"Unknown update mode!\n" );
1057 	m_nUpdateMode = nMode;
1058 }
1059 
1060 //----------------------------------------------
getStatus(sal_Int64 nAspect)1061 sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
1062     nAspect
1063 )
1064 		throw ( embed::WrongStateException,
1065 				uno::RuntimeException )
1066 {
1067     // begin wrapping related part ====================
1068     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1069     if ( xWrappedObject.is() )
1070     {
1071         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1072         return xWrappedObject->getStatus( nAspect );
1073     }
1074     // end wrapping related part ====================
1075 
1076 	::osl::MutexGuard aGuard( m_aMutex );
1077 	if ( m_bDisposed )
1078 		throw lang::DisposedException(); // TODO
1079 
1080 	if ( m_nObjectState == -1 )
1081 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object must be in running state!\n" ),
1082 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1083 
1084 	sal_Int64 nResult = 0;
1085 
1086 #ifdef WNT
1087 	if ( m_bGotStatus && m_nStatusAspect == nAspect )
1088 		nResult = m_nStatus;
1089 	else if ( m_pOleComponent )
1090 	{
1091 		// OLE should allow to get status even in loaded state
1092 		// if ( m_nObjectState == embed::EmbedStates::LOADED )
1093 		//	changeState( m_nObjectState == embed::EmbedStates::RUNNING );
1094 
1095 		m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
1096 		m_nStatusAspect = nAspect;
1097 		m_bGotStatus = sal_True;
1098 		nResult = m_nStatus;
1099 	}
1100 #endif
1101 
1102 	// this implementation needs size to be provided after object loading/creating to work in optimal way
1103 	return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
1104 }
1105 
1106 //----------------------------------------------
setContainerName(const::rtl::OUString & sName)1107 void SAL_CALL OleEmbeddedObject::setContainerName( const ::rtl::OUString& sName )
1108 		throw ( uno::RuntimeException )
1109 {
1110     // begin wrapping related part ====================
1111     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1112     if ( xWrappedObject.is() )
1113     {
1114         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1115         xWrappedObject->setContainerName( sName );
1116         return;
1117     }
1118     // end wrapping related part ====================
1119 
1120 	::osl::MutexGuard aGuard( m_aMutex );
1121 	if ( m_bDisposed )
1122 		throw lang::DisposedException(); // TODO
1123 
1124 	m_aContainerName = sName;
1125 }
1126 
1127 
1128