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