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 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/embed/EmbedStates.hpp>
28 #include <com/sun/star/embed/EmbedMapUnits.hpp>
29 #include <com/sun/star/embed/EmbedMisc.hpp>
30 #include <com/sun/star/embed/Aspects.hpp>
31 #include <com/sun/star/io/XSeekable.hpp>
32 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
33 
34 #include <rtl/logfile.hxx>
35 
36 #include <oleembobj.hxx>
37 #include <olecomponent.hxx>
38 #include <comphelper/mimeconfighelper.hxx>
39 #include <comphelper/seqstream.hxx>
40 
41 using namespace ::com::sun::star;
42 using namespace ::comphelper;
43 
GetVisualRepresentationInNativeFormat_Impl(const uno::Reference<io::XStream> xCachedVisRepr)44 embed::VisualRepresentation OleEmbeddedObject::GetVisualRepresentationInNativeFormat_Impl(
45 					const uno::Reference< io::XStream > xCachedVisRepr )
46 		throw ( uno::Exception )
47 {
48 	embed::VisualRepresentation aVisualRepr;
49 
50 	// TODO: detect the format in the future for now use workaround
51 	uno::Reference< io::XInputStream > xInStream = xCachedVisRepr->getInputStream();
52 	uno::Reference< io::XSeekable > xSeekable( xCachedVisRepr, uno::UNO_QUERY );
53 	if ( !xInStream.is() || !xSeekable.is() )
54 		throw uno::RuntimeException();
55 
56 	uno::Sequence< sal_Int8 > aSeq( 2 );
57 	xInStream->readBytes( aSeq, 2 );
58 	xSeekable->seek( 0 );
59 	if ( aSeq.getLength() == 2 && aSeq[0] == 'B' && aSeq[1] == 'M' )
60 	{
61 		// it's a bitmap
62 		aVisualRepr.Flavor = datatransfer::DataFlavor(
63             ::rtl::OUString::createFromAscii( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ),
64 			::rtl::OUString::createFromAscii( "Bitmap" ),
65 			::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) );
66 	}
67 	else
68 	{
69 		// it's a metafile
70 		aVisualRepr.Flavor = datatransfer::DataFlavor(
71             ::rtl::OUString::createFromAscii( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ),
72 			::rtl::OUString::createFromAscii( "Windows Metafile" ),
73 			::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) );
74 	}
75 
76 	sal_Int32 nStreamLength = (sal_Int32)xSeekable->getLength();
77 	uno::Sequence< sal_Int8 > aRepresent( nStreamLength );
78 	xInStream->readBytes( aRepresent, nStreamLength );
79 	aVisualRepr.Data <<= aRepresent;
80 
81 	return aVisualRepr;
82 }
83 
setVisualAreaSize(sal_Int64 nAspect,const awt::Size & aSize)84 void SAL_CALL OleEmbeddedObject::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize )
85 		throw ( lang::IllegalArgumentException,
86 				embed::WrongStateException,
87 				uno::Exception,
88 				uno::RuntimeException )
89 {
90 	RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::setVisualAreaSize" );
91 
92     // begin wrapping related part ====================
93     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
94     if ( xWrappedObject.is() )
95     {
96         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
97         xWrappedObject->setVisualAreaSize( nAspect, aSize );
98         return;
99     }
100     // end wrapping related part ====================
101 
102 	::osl::ResettableMutexGuard aGuard( m_aMutex );
103 	if ( m_bDisposed )
104 		throw lang::DisposedException(); // TODO
105 
106 	OSL_ENSURE( nAspect != embed::Aspects::MSOLE_ICON, "For iconified objects no graphical replacement is required!\n" );
107 	if ( nAspect == embed::Aspects::MSOLE_ICON )
108 		// no representation can be retrieved
109 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ),
110 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
111 
112 	if ( m_nObjectState == -1 )
113 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object is not loaded!\n" ),
114 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
115 
116 #ifdef WNT
117 	// RECOMPOSE_ON_RESIZE misc flag means that the object has to be switched to running state on resize.
118 	// SetExtent() is called only for objects that require it,
119 	// it should not be called for MSWord documents to workaround problem i49369
120 	// If cached size is not set, that means that this is the size initialization, so there is no need to set the real size
121 	sal_Bool bAllowToSetExtent =
122 	  ( ( getStatus( nAspect ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE )
123 	  && !MimeConfigurationHelper::ClassIDsEqual( m_aClassID, MimeConfigurationHelper::GetSequenceClassID( 0x00020906L, 0x0000, 0x0000,
124 	  													 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 ) )
125 	  && m_bHasCachedSize );
126 
127 	if ( m_nObjectState == embed::EmbedStates::LOADED && bAllowToSetExtent )
128 	{
129 		aGuard.clear();
130 		try {
131 			changeState( embed::EmbedStates::RUNNING );
132 		}
133 		catch( uno::Exception& )
134 		{
135 			OSL_ENSURE( sal_False, "The object should not be resized without activation!\n" );
136 		}
137 		aGuard.reset();
138 	}
139 
140 	if ( m_pOleComponent && m_nObjectState != embed::EmbedStates::LOADED && bAllowToSetExtent )
141 	{
142 		awt::Size aSizeToSet = aSize;
143 		aGuard.clear();
144 		try {
145 			m_pOleComponent->SetExtent( aSizeToSet, nAspect ); // will throw an exception in case of failure
146 			m_bHasSizeToSet = sal_False;
147 		}
148 		catch( uno::Exception& )
149 		{
150 			// some objects do not allow to set the size even in running state
151 			m_bHasSizeToSet = sal_True;
152 			m_aSizeToSet = aSizeToSet;
153 			m_nAspectToSet = nAspect;
154 		}
155 		aGuard.reset();
156 	}
157 #endif
158 
159 	// cache the values
160 	m_bHasCachedSize = sal_True;
161 	m_aCachedSize = aSize;
162 	m_nCachedAspect = nAspect;
163 }
164 
getVisualAreaSize(sal_Int64 nAspect)165 awt::Size SAL_CALL OleEmbeddedObject::getVisualAreaSize( sal_Int64 nAspect )
166 		throw ( lang::IllegalArgumentException,
167 				embed::WrongStateException,
168 				uno::Exception,
169 				uno::RuntimeException )
170 {
171 	RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getVisualAreaSize" );
172 
173     // begin wrapping related part ====================
174     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
175     if ( xWrappedObject.is() )
176     {
177         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
178         return xWrappedObject->getVisualAreaSize( nAspect );
179     }
180     // end wrapping related part ====================
181 
182 	::osl::ResettableMutexGuard aGuard( m_aMutex );
183 	if ( m_bDisposed )
184 		throw lang::DisposedException(); // TODO
185 
186 	OSL_ENSURE( nAspect != embed::Aspects::MSOLE_ICON, "For iconified objects no graphical replacement is required!\n" );
187 	if ( nAspect == embed::Aspects::MSOLE_ICON )
188 		// no representation can be retrieved
189 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ),
190 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
191 
192 	if ( m_nObjectState == -1 )
193 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object is not loaded!\n" ),
194 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
195 
196 	awt::Size aResult;
197 
198 #ifdef WNT
199 	// TODO/LATER: Support different aspects
200 	if ( m_pOleComponent && !m_bHasSizeToSet && nAspect == embed::Aspects::MSOLE_CONTENT )
201 	{
202 		try
203 		{
204 			// the cached size updated every time the object is stored
205 			if ( m_bHasCachedSize )
206 			{
207 				aResult = m_aCachedSize;
208 			}
209 			else
210 			{
211 				// there is no internal cache
212 				awt::Size aSize;
213 				aGuard.clear();
214 
215 				sal_Bool bSuccess = sal_False;
216 				if ( getCurrentState() == embed::EmbedStates::LOADED )
217 				{
218 					OSL_ENSURE( sal_False, "Loaded object has no cached size!\n" );
219 
220 					// try to switch the object to RUNNING state and request the value again
221 					try {
222 						changeState( embed::EmbedStates::RUNNING );
223 					}
224 					catch( uno::Exception )
225 					{
226 						throw embed::NoVisualAreaSizeException(
227 								::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No size available!\n" ) ),
228 								uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
229 					}
230 				}
231 
232 				try
233 				{
234 					// first try to get size using replacement image
235 					aSize = m_pOleComponent->GetExtent( nAspect ); // will throw an exception in case of failure
236 					bSuccess = sal_True;
237 				}
238 				catch( uno::Exception& )
239 				{
240 				}
241 
242 				if ( !bSuccess )
243 				{
244 					try
245 					{
246 						// second try the cached replacement image
247 						aSize = m_pOleComponent->GetCachedExtent( nAspect ); // will throw an exception in case of failure
248 						bSuccess = sal_True;
249 					}
250 					catch( uno::Exception& )
251 					{
252 					}
253 				}
254 
255 				if ( !bSuccess )
256 				{
257 					try
258 					{
259 						// third try the size reported by the object
260 						aSize = m_pOleComponent->GetReccomendedExtent( nAspect ); // will throw an exception in case of failure
261 						bSuccess = sal_True;
262 					}
263 					catch( uno::Exception& )
264 					{
265 					}
266 				}
267 
268 				if ( !bSuccess )
269 					throw embed::NoVisualAreaSizeException(
270 									::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No size available!\n" ) ),
271 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
272 
273 				aGuard.reset();
274 
275 				m_aCachedSize = aSize;
276 				m_nCachedAspect = nAspect;
277 				m_bHasCachedSize = sal_True;
278 
279 				aResult = m_aCachedSize;
280 			}
281 		}
282 		catch ( embed::NoVisualAreaSizeException& )
283 		{
284 			throw;
285 		}
286 		catch ( uno::Exception& )
287 		{
288 			throw embed::NoVisualAreaSizeException(
289 							::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No size available!\n" ) ),
290 							uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
291 		}
292 	}
293 	else
294 #endif
295 	{
296 		// return cached value
297 		if ( m_bHasCachedSize )
298 		{
299 			OSL_ENSURE( nAspect == m_nCachedAspect, "Unexpected aspect is requested!\n" );
300 			aResult = m_aCachedSize;
301 		}
302 		else
303 		{
304 			throw embed::NoVisualAreaSizeException(
305 							::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No size available!\n" ) ),
306 							uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
307 		}
308 	}
309 
310 	return aResult;
311 }
312 
getPreferredVisualRepresentation(sal_Int64 nAspect)313 embed::VisualRepresentation SAL_CALL OleEmbeddedObject::getPreferredVisualRepresentation( sal_Int64 nAspect )
314 		throw ( lang::IllegalArgumentException,
315 				embed::WrongStateException,
316 				uno::Exception,
317 				uno::RuntimeException )
318 {
319 	RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getPreferredVisualRepresentation" );
320 
321     // begin wrapping related part ====================
322     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
323     if ( xWrappedObject.is() )
324     {
325         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
326         return xWrappedObject->getPreferredVisualRepresentation( nAspect );
327     }
328     // end wrapping related part ====================
329 
330 	::osl::MutexGuard aGuard( m_aMutex );
331 	if ( m_bDisposed )
332 		throw lang::DisposedException(); // TODO
333 
334 	OSL_ENSURE( nAspect != embed::Aspects::MSOLE_ICON, "For iconified objects no graphical replacement is required!\n" );
335 	if ( nAspect == embed::Aspects::MSOLE_ICON )
336 		// no representation can be retrieved
337 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ),
338 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
339 
340 	// TODO: if the object has cached representation then it should be returned
341 	// TODO: if the object has no cached representation and is in loaded state it should switch itself to the running state
342 	if ( m_nObjectState == -1 )
343 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object is not loaded!\n" ),
344 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
345 
346 	embed::VisualRepresentation aVisualRepr;
347 
348 	// TODO: in case of different aspects they must be applied to the mediatype and XTransferable must be used
349 	// the cache is used only as a fallback if object is not in loaded state
350 	if ( !m_xCachedVisualRepresentation.is() && ( !m_bVisReplInitialized || m_bVisReplInStream )
351 	  && m_nObjectState == embed::EmbedStates::LOADED )
352 	{
353 		m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream, sal_True );
354 		SetVisReplInStream( m_xCachedVisualRepresentation.is() );
355 	}
356 
357 	if ( m_xCachedVisualRepresentation.is() )
358 	{
359 		return GetVisualRepresentationInNativeFormat_Impl( m_xCachedVisualRepresentation );
360 	}
361 #ifdef WNT
362 	else if ( m_pOleComponent )
363 	{
364 		try
365 		{
366 			if ( m_nObjectState == embed::EmbedStates::LOADED )
367 				changeState( embed::EmbedStates::RUNNING );
368 
369 			datatransfer::DataFlavor aDataFlavor(
370                 	::rtl::OUString::createFromAscii( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ),
371 					::rtl::OUString::createFromAscii( "Windows Metafile" ),
372 					::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) );
373 
374 			aVisualRepr.Data = m_pOleComponent->getTransferData( aDataFlavor );
375 			aVisualRepr.Flavor = aDataFlavor;
376 
377 			uno::Sequence< sal_Int8 > aVisReplSeq;
378 			aVisualRepr.Data >>= aVisReplSeq;
379 			if ( aVisReplSeq.getLength() )
380 			{
381 				m_xCachedVisualRepresentation = GetNewFilledTempStream_Impl(
382 						uno::Reference< io::XInputStream > ( static_cast< io::XInputStream* > (
383 							new ::comphelper::SequenceInputStream( aVisReplSeq ) ) ) );
384 			}
385 
386 			return aVisualRepr;
387 		}
388 		catch( uno::Exception& )
389 		{}
390 	}
391 #endif
392 
393 	// the cache is used only as a fallback if object is not in loaded state
394 	if ( !m_xCachedVisualRepresentation.is() && ( !m_bVisReplInitialized || m_bVisReplInStream ) )
395 	{
396 		m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
397 		SetVisReplInStream( m_xCachedVisualRepresentation.is() );
398 	}
399 
400 	if ( !m_xCachedVisualRepresentation.is() )
401 	{
402 		// no representation can be retrieved
403 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ),
404 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
405 	}
406 
407 	return GetVisualRepresentationInNativeFormat_Impl( m_xCachedVisualRepresentation );
408 }
409 
getMapUnit(sal_Int64 nAspect)410 sal_Int32 SAL_CALL OleEmbeddedObject::getMapUnit( sal_Int64 nAspect )
411 		throw ( uno::Exception,
412 				uno::RuntimeException)
413 {
414     // begin wrapping related part ====================
415     uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
416     if ( xWrappedObject.is() )
417     {
418         // the object was converted to OOo embedded object, the current implementation is now only a wrapper
419         return xWrappedObject->getMapUnit( nAspect );
420     }
421     // end wrapping related part ====================
422 
423 	::osl::MutexGuard aGuard( m_aMutex );
424 	if ( m_bDisposed )
425 		throw lang::DisposedException(); // TODO
426 
427 	OSL_ENSURE( nAspect != embed::Aspects::MSOLE_ICON, "For iconified objects no graphical replacement is required!\n" );
428 	if ( nAspect == embed::Aspects::MSOLE_ICON )
429 		// no representation can be retrieved
430 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ),
431 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
432 
433 	if ( m_nObjectState == -1 )
434 		throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object is not loaded!\n" ),
435 									uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
436 
437 	return embed::EmbedMapUnits::ONE_100TH_MM;
438 }
439 
440 
441