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