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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 559 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 569 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 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