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 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 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 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 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 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 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 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 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 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 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 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 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 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 562 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 572 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 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