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/XSystemShellExecute.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  
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  {
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
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  //----------------------------------------------
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( m_xFactory->createInstance(
882                          ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.system.SystemShellExecute"))),
883                          uno::UNO_QUERY_THROW);
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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  //----------------------------------------------
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