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_dtrans.hxx"
26
27 //------------------------------------------------------------------------
28 // includes
29 //------------------------------------------------------------------------
30 #include <sal/types.h>
31 #include <rtl/process.h>
32
33 #ifndef _DOWRAPPERTRANSFERABLE_HXX_
34 #include "DOTransferable.hxx"
35 #endif
36 #include "..\misc\ImplHelper.hxx"
37 #include "..\misc\WinClip.hxx"
38 #include "DTransHelper.hxx"
39 #include "..\misc\ImplHelper.hxx"
40 #include "TxtCnvtHlp.hxx"
41 #include "MimeAttrib.hxx"
42 #include "FmtFilter.hxx"
43 #include "Fetc.hxx"
44
45
46 #if(_MSC_VER < 1300) && !defined(__MINGW32__)
47 #include <olestd.h>
48 #endif
49
50 #define STR2(x) #x
51 #define STR(x) STR2(x)
52 #define PRAGMA_MSG( msg ) message( __FILE__ "(" STR(__LINE__) "): " #msg )
53
54 //------------------------------------------------------------------------
55 // namespace directives
56 //------------------------------------------------------------------------
57
58 using namespace rtl;
59 using namespace std;
60 using namespace osl;
61 using namespace cppu;
62 using namespace com::sun::star::uno;
63 using namespace com::sun::star::datatransfer;
64 using namespace com::sun::star::io;
65 using namespace com::sun::star::lang;
66 using namespace com::sun::star::container;
67
68 //------------------------------------------------------------------------
69 //
70 //------------------------------------------------------------------------
71
72 namespace
73 {
74 const Type CPPUTYPE_SEQINT8 = getCppuType( ( Sequence< sal_Int8 >* )0 );
75 const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 );
76
77 inline
isValidFlavor(const DataFlavor & aFlavor)78 sal_Bool isValidFlavor( const DataFlavor& aFlavor )
79 {
80 return ( aFlavor.MimeType.getLength( ) &&
81 ( ( aFlavor.DataType == CPPUTYPE_SEQINT8 ) ||
82 ( aFlavor.DataType == CPPUTYPE_OUSTRING ) ) );
83 }
84
85 } // end namespace
86
87
88 //------------------------------------------------------------------------
89 // ctor
90 //------------------------------------------------------------------------
91
CDOTransferable(const Reference<XMultiServiceFactory> & ServiceManager,IDataObjectPtr rDataObject)92 CDOTransferable::CDOTransferable(
93 const Reference< XMultiServiceFactory >& ServiceManager, IDataObjectPtr rDataObject ) :
94 m_rDataObject( rDataObject ),
95 m_SrvMgr( ServiceManager ),
96 m_DataFormatTranslator( m_SrvMgr ),
97 m_bUnicodeRegistered( sal_False ),
98 m_TxtFormatOnClipboard( CF_INVALID )
99 {
100 }
101
102 //------------------------------------------------------------------------
103 //
104 //------------------------------------------------------------------------
105
getTransferData(const DataFlavor & aFlavor)106 Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor )
107 throw( UnsupportedFlavorException, IOException, RuntimeException )
108 {
109 OSL_ASSERT( isValidFlavor( aFlavor ) );
110
111 MutexGuard aGuard( m_aMutex );
112
113 //------------------------------------------------
114 // convert dataflavor to formatetc
115 //------------------------------------------------
116
117 CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
118 OSL_ASSERT( CF_INVALID != fetc.getClipformat() );
119
120 //------------------------------------------------
121 // get the data from clipboard in a byte stream
122 //------------------------------------------------
123
124 ByteSequence_t clipDataStream;
125
126 try
127 {
128 clipDataStream = getClipboardData( fetc );
129 }
130 catch( UnsupportedFlavorException& )
131 {
132 if ( m_DataFormatTranslator.isUnicodeTextFormat( fetc.getClipformat( ) ) &&
133 m_bUnicodeRegistered )
134 {
135 OUString aUnicodeText = synthesizeUnicodeText( );
136 Any aAny = makeAny( aUnicodeText );
137 return aAny;
138 }
139 // #124085# CF_DIBV5 should not be possible, but keep for reading from the
140 // clipboard for being on the safe side
141 else if(CF_DIBV5 == fetc.getClipformat())
142 {
143 // #123407# CF_DIBV5 has priority; if the try to fetch this failed,
144 // check CF_DIB availability as an alternative
145 fetc.setClipformat(CF_DIB);
146
147 try
148 {
149 clipDataStream = getClipboardData( fetc );
150 }
151 catch( UnsupportedFlavorException& )
152 {
153 throw; // pass through, tried all possibilities
154 }
155 }
156 else
157 throw; // pass through exception
158 }
159
160 //------------------------------------------------
161 // return the data as any
162 //------------------------------------------------
163
164 return byteStreamToAny( clipDataStream, aFlavor.DataType );
165 }
166
167 //------------------------------------------------------------------------
168 // getTransferDataFlavors
169 //------------------------------------------------------------------------
170
getTransferDataFlavors()171 Sequence< DataFlavor > SAL_CALL CDOTransferable::getTransferDataFlavors( )
172 throw( RuntimeException )
173 {
174 return m_FlavorList;
175 }
176
177 //------------------------------------------------------------------------
178 // isDataFlavorSupported
179 // returns true if we find a DataFlavor with the same MimeType and
180 // DataType
181 //------------------------------------------------------------------------
182
isDataFlavorSupported(const DataFlavor & aFlavor)183 sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
184 throw( RuntimeException )
185 {
186 OSL_ASSERT( isValidFlavor( aFlavor ) );
187
188 for ( sal_Int32 i = 0; i < m_FlavorList.getLength( ); i++ )
189 if ( compareDataFlavors( aFlavor, m_FlavorList[i] ) )
190 return sal_True;
191
192 return sal_False;
193 }
194
195 //------------------------------------------------------------------------
196 // helper function
197 // the list of datafalvors currently on the clipboard will be initialized
198 // only once; if the client of this Transferable will hold a reference
199 // to it und the underlying clipboard content changes, the client does
200 // possible operate on a invalid list
201 // if there is only text on the clipboard we will also offer unicode text
202 // an synthesize this format on the fly if requested, to accomplish this
203 // we save the first offered text format which we will later use for the
204 // conversion
205 //------------------------------------------------------------------------
206
initFlavorList()207 void SAL_CALL CDOTransferable::initFlavorList( )
208 {
209 IEnumFORMATETCPtr pEnumFormatEtc;
210 HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc );
211 if ( SUCCEEDED( hr ) )
212 {
213 pEnumFormatEtc->Reset( );
214
215 FORMATETC fetc;
216 while ( S_FALSE != pEnumFormatEtc->Next( 1, &fetc, NULL ) )
217 {
218 // we use locales only to determine the
219 // charset if there is text on the cliboard
220 // we don't offer this format
221 if ( CF_LOCALE == fetc.cfFormat )
222 continue;
223
224 DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
225
226 // if text or oemtext is offered we also pretend to have unicode text
227 if ( m_DataFormatTranslator.isOemOrAnsiTextFormat( fetc.cfFormat ) &&
228 !m_bUnicodeRegistered )
229 {
230 addSupportedFlavor( aFlavor );
231
232 m_TxtFormatOnClipboard = fetc.cfFormat;
233 m_bUnicodeRegistered = sal_True;
234
235 // register unicode text as accompany format
236 aFlavor = formatEtcToDataFlavor(
237 m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) );
238 addSupportedFlavor( aFlavor );
239 }
240 else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered )
241 {
242 addSupportedFlavor( aFlavor );
243 m_bUnicodeRegistered = sal_True;
244 }
245 else
246 addSupportedFlavor( aFlavor );
247
248 // see MSDN IEnumFORMATETC
249 CoTaskMemFree( fetc.ptd );
250 }
251 }
252 }
253
254 //------------------------------------------------------------------------
255 //
256 //------------------------------------------------------------------------
257
258 inline
addSupportedFlavor(const DataFlavor & aFlavor)259 void SAL_CALL CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor )
260 {
261 // we ignore all formats that couldn't be translated
262 if ( aFlavor.MimeType.getLength( ) )
263 {
264 OSL_ASSERT( isValidFlavor( aFlavor ) );
265
266 m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 );
267 m_FlavorList[m_FlavorList.getLength( ) - 1] = aFlavor;
268 }
269 }
270
271 //------------------------------------------------------------------------
272 // helper function
273 //------------------------------------------------------------------------
274
275 //inline
formatEtcToDataFlavor(const FORMATETC & aFormatEtc)276 DataFlavor SAL_CALL CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc )
277 {
278 DataFlavor aFlavor;
279 LCID lcid = 0;
280
281 // for non-unicode text format we must provid a locale to get
282 // the character-set of the text, if there is no locale on the
283 // clipboard we assume the text is in a charset appropriate for
284 // the current thread locale
285 if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) )
286 lcid = getLocaleFromClipboard( );
287
288 return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid );
289 }
290
291 //------------------------------------------------------------------------
292 // returns the current locale on clipboard; if there is no locale on
293 // clipboard the function returns the current thread locale
294 //------------------------------------------------------------------------
295
getLocaleFromClipboard()296 LCID SAL_CALL CDOTransferable::getLocaleFromClipboard( )
297 {
298 LCID lcid = GetThreadLocale( );
299
300 try
301 {
302 CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE );
303 ByteSequence_t aLCIDSeq = getClipboardData( fetc );
304 lcid = *(reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) ) );
305
306 // because of a Win95/98 Bug; there the high word
307 // of a locale has the same value as the
308 // low word e.g. 0x07040704 that's not right
309 // correct is 0x00000704
310 lcid &= 0x0000FFFF;
311 }
312 catch(...)
313 {
314 // we take the default locale
315 }
316
317 return lcid;
318 }
319
320 //------------------------------------------------------------------------
321 // i think it's not necessary to call ReleaseStgMedium
322 // in case of failures because nothing should have been
323 // allocated etc.
324 //------------------------------------------------------------------------
325
getClipboardData(CFormatEtc & aFormatEtc)326 CDOTransferable::ByteSequence_t SAL_CALL CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc )
327 {
328 STGMEDIUM stgmedium;
329 HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium );
330
331 // in case of failure to get a WMF metafile handle, try to get a memory block
332 if( FAILED( hr ) &&
333 ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) &&
334 ( TYMED_MFPICT == aFormatEtc.getTymed() ) )
335 {
336 CFormatEtc aTempFormat( aFormatEtc );
337 aTempFormat.setTymed( TYMED_HGLOBAL );
338 hr = m_rDataObject->GetData( aTempFormat, &stgmedium );
339 }
340
341 if ( FAILED( hr ) )
342 {
343 OSL_ASSERT( (hr != E_INVALIDARG) &&
344 (hr != DV_E_DVASPECT) &&
345 (hr != DV_E_LINDEX) &&
346 (hr != DV_E_TYMED) );
347
348 if ( DV_E_FORMATETC == hr )
349 throw UnsupportedFlavorException( );
350 else if ( STG_E_MEDIUMFULL == hr )
351 throw IOException( );
352 else
353 throw RuntimeException( );
354 }
355
356 ByteSequence_t byteStream;
357
358 try
359 {
360 if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() )
361 byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile );
362 else if (CF_HDROP == aFormatEtc.getClipformat())
363 byteStream = CF_HDROPToFileList(stgmedium.hGlobal);
364 else if ( CF_BITMAP == aFormatEtc.getClipformat() )
365 {
366 byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap);
367 if( aFormatEtc.getTymed() == TYMED_GDI &&
368 ! stgmedium.pUnkForRelease )
369 {
370 DeleteObject(stgmedium.hBitmap);
371 }
372 }
373 else
374 {
375 clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream );
376
377 // format conversion if necessary
378 // #124085# DIBV5 should not happen currently, but keep as a hint here
379 if(CF_DIBV5 == aFormatEtc.getClipformat() || CF_DIB == aFormatEtc.getClipformat())
380 {
381 byteStream = WinDIBToOOBMP(byteStream);
382 }
383 else if(CF_METAFILEPICT == aFormatEtc.getClipformat())
384 {
385 byteStream = WinMFPictToOOMFPict(byteStream);
386 }
387 }
388
389 ReleaseStgMedium( &stgmedium );
390 }
391 catch( CStgTransferHelper::CStgTransferException& )
392 {
393 ReleaseStgMedium( &stgmedium );
394 throw IOException( );
395 }
396
397 return byteStream;
398 }
399
400 //------------------------------------------------------------------------
401 //
402 //------------------------------------------------------------------------
403
synthesizeUnicodeText()404 OUString SAL_CALL CDOTransferable::synthesizeUnicodeText( )
405 {
406 ByteSequence_t aTextSequence;
407 CFormatEtc fetc;
408 LCID lcid = getLocaleFromClipboard( );
409 sal_uInt32 cpForTxtCnvt = 0;
410
411 if ( CF_TEXT == m_TxtFormatOnClipboard )
412 {
413 fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT );
414 aTextSequence = getClipboardData( fetc );
415
416 // determine the codepage used for text conversion
417 cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTANSICODEPAGE ).toInt32( );
418 }
419 else if ( CF_OEMTEXT == m_TxtFormatOnClipboard )
420 {
421 fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_OEMTEXT );
422 aTextSequence = getClipboardData( fetc );
423
424 // determine the codepage used for text conversion
425 cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTCODEPAGE ).toInt32( );
426 }
427 else
428 OSL_ASSERT( sal_False );
429
430 CStgTransferHelper stgTransferHelper;
431
432 // convert the text
433 MultiByteToWideCharEx( cpForTxtCnvt,
434 reinterpret_cast<char*>( aTextSequence.getArray( ) ),
435 sal::static_int_cast<sal_uInt32>(-1), // Huh ?
436 stgTransferHelper,
437 sal_False);
438
439 CRawHGlobalPtr ptrHGlob(stgTransferHelper);
440 sal_Unicode* pWChar = reinterpret_cast<sal_Unicode*>(ptrHGlob.GetMemPtr());
441
442 return OUString(pWChar);
443 }
444
445 //------------------------------------------------------------------------
446 //
447 //------------------------------------------------------------------------
448
clipDataToByteStream(CLIPFORMAT cf,STGMEDIUM stgmedium,ByteSequence_t & aByteSequence)449 void CDOTransferable::clipDataToByteStream( CLIPFORMAT cf, STGMEDIUM stgmedium, ByteSequence_t& aByteSequence )
450 {
451 CStgTransferHelper memTransferHelper;
452
453 switch( stgmedium.tymed )
454 {
455 case TYMED_HGLOBAL:
456 memTransferHelper.init( stgmedium.hGlobal );
457 break;
458
459 case TYMED_MFPICT:
460 memTransferHelper.init( stgmedium.hMetaFilePict );
461 break;
462
463 case TYMED_ENHMF:
464 memTransferHelper.init( stgmedium.hEnhMetaFile );
465 break;
466
467 case TYMED_ISTREAM:
468 #ifdef _MSC_VER
469 #pragma PRAGMA_MSG( Has to be implemented )
470 #endif
471 break;
472
473 default:
474 throw UnsupportedFlavorException( );
475 break;
476 }
477
478 int nMemSize = memTransferHelper.memSize( cf );
479 aByteSequence.realloc( nMemSize );
480 memTransferHelper.read( aByteSequence.getArray( ), nMemSize );
481 }
482
483 //------------------------------------------------------------------------
484 //
485 //------------------------------------------------------------------------
486
487 inline
byteStreamToAny(ByteSequence_t & aByteStream,const Type & aRequestedDataType)488 Any CDOTransferable::byteStreamToAny( ByteSequence_t& aByteStream, const Type& aRequestedDataType )
489 {
490 Any aAny;
491
492 if ( aRequestedDataType == CPPUTYPE_OUSTRING )
493 {
494 OUString str = byteStreamToOUString( aByteStream );
495 aAny = makeAny( str );
496 }
497 else
498 aAny = makeAny( aByteStream );
499
500 return aAny;
501 }
502
503 //------------------------------------------------------------------------
504 //
505 //------------------------------------------------------------------------
506
507 inline
byteStreamToOUString(ByteSequence_t & aByteStream)508 OUString CDOTransferable::byteStreamToOUString( ByteSequence_t& aByteStream )
509 {
510 sal_Int32 nWChars;
511 sal_Int32 nMemSize = aByteStream.getLength( );
512
513 // if there is a trailing L"\0" substract 1 from length
514 if ( 0 == aByteStream[ aByteStream.getLength( ) - 2 ] &&
515 0 == aByteStream[ aByteStream.getLength( ) - 1 ] )
516 nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) ) - 1;
517 else
518 nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) );
519
520 return OUString( reinterpret_cast< sal_Unicode* >( aByteStream.getArray( ) ), nWChars );
521 }
522
523 //------------------------------------------------------------------------
524 //
525 //------------------------------------------------------------------------
526
compareDataFlavors(const DataFlavor & lhs,const DataFlavor & rhs)527 sal_Bool SAL_CALL CDOTransferable::compareDataFlavors(
528 const DataFlavor& lhs, const DataFlavor& rhs )
529 {
530 if ( !m_rXMimeCntFactory.is( ) )
531 {
532 m_rXMimeCntFactory = Reference< XMimeContentTypeFactory >( m_SrvMgr->createInstance(
533 OUString::createFromAscii( "com.sun.star.datatransfer.MimeContentTypeFactory" ) ), UNO_QUERY );
534 }
535 OSL_ASSERT( m_rXMimeCntFactory.is( ) );
536
537 sal_Bool bRet = sal_False;
538
539 try
540 {
541 Reference< XMimeContentType > xLhs( m_rXMimeCntFactory->createMimeContentType( lhs.MimeType ) );
542 Reference< XMimeContentType > xRhs( m_rXMimeCntFactory->createMimeContentType( rhs.MimeType ) );
543
544 if ( cmpFullMediaType( xLhs, xRhs ) )
545 {
546 bRet = cmpAllContentTypeParameter( xLhs, xRhs );
547 }
548 }
549 catch( IllegalArgumentException& )
550 {
551 OSL_ENSURE( sal_False, "Invalid content type detected" );
552 bRet = sal_False;
553 }
554
555 return bRet;
556 }
557
558 //------------------------------------------------------------------------
559 //
560 //------------------------------------------------------------------------
561
cmpFullMediaType(const Reference<XMimeContentType> & xLhs,const Reference<XMimeContentType> & xRhs) const562 sal_Bool SAL_CALL CDOTransferable::cmpFullMediaType(
563 const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const
564 {
565 return xLhs->getFullMediaType().equalsIgnoreAsciiCase( xRhs->getFullMediaType( ) );
566 }
567
568 //------------------------------------------------------------------------
569 //
570 //------------------------------------------------------------------------
571
cmpAllContentTypeParameter(const Reference<XMimeContentType> & xLhs,const Reference<XMimeContentType> & xRhs) const572 sal_Bool SAL_CALL CDOTransferable::cmpAllContentTypeParameter(
573 const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const
574 {
575 Sequence< OUString > xLhsFlavors = xLhs->getParameters( );
576 Sequence< OUString > xRhsFlavors = xRhs->getParameters( );
577 sal_Bool bRet = sal_True;
578
579 try
580 {
581 if ( xLhsFlavors.getLength( ) == xRhsFlavors.getLength( ) )
582 {
583 OUString pLhs;
584 OUString pRhs;
585
586 for ( sal_Int32 i = 0; i < xLhsFlavors.getLength( ); i++ )
587 {
588 pLhs = xLhs->getParameterValue( xLhsFlavors[i] );
589 pRhs = xRhs->getParameterValue( xLhsFlavors[i] );
590
591 if ( !pLhs.equalsIgnoreAsciiCase( pRhs ) )
592 {
593 bRet = sal_False;
594 break;
595 }
596 }
597 }
598 else
599 bRet = sal_False;
600 }
601 catch( NoSuchElementException& )
602 {
603 bRet = sal_False;
604 }
605 catch( IllegalArgumentException& )
606 {
607 bRet = sal_False;
608 }
609
610 return bRet;
611 }
612
getData(const Sequence<sal_Int8> & aProcessId)613 ::com::sun::star::uno::Any SAL_CALL CDOTransferable::getData( const Sequence< sal_Int8>& aProcessId )
614 throw (::com::sun::star::uno::RuntimeException)
615 {
616 Any retVal;
617
618 sal_uInt8 * arProcCaller= (sal_uInt8*)(sal_Int8*) aProcessId.getConstArray();
619 sal_uInt8 arId[16];
620 rtl_getGlobalProcessId(arId);
621 if( ! memcmp( arId, arProcCaller,16))
622 {
623 if (m_rDataObject.is())
624 {
625 IDataObject* pObj= m_rDataObject.get();
626 pObj->AddRef();
627 retVal.setValue( &pObj, getCppuType((sal_uInt32*)0));
628 }
629 }
630 return retVal;
631 }
632
633