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 else if(CF_DIBV5 == fetc.getClipformat()) 140 { 141 // #123407# CF_DIBV5 has priority; if the try to fetch this failed, 142 // check CF_DIB availability as an alternative 143 fetc.setClipformat(CF_DIB); 144 145 try 146 { 147 clipDataStream = getClipboardData( fetc ); 148 } 149 catch( UnsupportedFlavorException& ) 150 { 151 throw; // pass through, tried all possibilities 152 } 153 } 154 else 155 throw; // pass through exception 156 } 157 158 //------------------------------------------------ 159 // return the data as any 160 //------------------------------------------------ 161 162 return byteStreamToAny( clipDataStream, aFlavor.DataType ); 163 } 164 165 //------------------------------------------------------------------------ 166 // getTransferDataFlavors 167 //------------------------------------------------------------------------ 168 169 Sequence< DataFlavor > SAL_CALL CDOTransferable::getTransferDataFlavors( ) 170 throw( RuntimeException ) 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 throw( RuntimeException ) 183 { 184 OSL_ASSERT( isValidFlavor( aFlavor ) ); 185 186 for ( sal_Int32 i = 0; i < m_FlavorList.getLength( ); i++ ) 187 if ( compareDataFlavors( aFlavor, m_FlavorList[i] ) ) 188 return sal_True; 189 190 return sal_False; 191 } 192 193 //------------------------------------------------------------------------ 194 // helper function 195 // the list of datafalvors currently on the clipboard will be initialized 196 // only once; if the client of this Transferable will hold a reference 197 // to it und the underlying clipboard content changes, the client does 198 // possible operate on a invalid list 199 // if there is only text on the clipboard we will also offer unicode text 200 // an synthesize this format on the fly if requested, to accomplish this 201 // we save the first offered text format which we will later use for the 202 // conversion 203 //------------------------------------------------------------------------ 204 205 void SAL_CALL CDOTransferable::initFlavorList( ) 206 { 207 IEnumFORMATETCPtr pEnumFormatEtc; 208 HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc ); 209 if ( SUCCEEDED( hr ) ) 210 { 211 pEnumFormatEtc->Reset( ); 212 213 FORMATETC fetc; 214 while ( S_FALSE != pEnumFormatEtc->Next( 1, &fetc, NULL ) ) 215 { 216 // we use locales only to determine the 217 // charset if there is text on the cliboard 218 // we don't offer this format 219 if ( CF_LOCALE == fetc.cfFormat ) 220 continue; 221 222 DataFlavor aFlavor = formatEtcToDataFlavor( fetc ); 223 224 // if text or oemtext is offered we also pretend to have unicode text 225 if ( m_DataFormatTranslator.isOemOrAnsiTextFormat( fetc.cfFormat ) && 226 !m_bUnicodeRegistered ) 227 { 228 addSupportedFlavor( aFlavor ); 229 230 m_TxtFormatOnClipboard = fetc.cfFormat; 231 m_bUnicodeRegistered = sal_True; 232 233 // register unicode text as accompany format 234 aFlavor = formatEtcToDataFlavor( 235 m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) ); 236 addSupportedFlavor( aFlavor ); 237 } 238 else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered ) 239 { 240 addSupportedFlavor( aFlavor ); 241 m_bUnicodeRegistered = sal_True; 242 } 243 else 244 addSupportedFlavor( aFlavor ); 245 246 // see MSDN IEnumFORMATETC 247 CoTaskMemFree( fetc.ptd ); 248 } 249 } 250 } 251 252 //------------------------------------------------------------------------ 253 // 254 //------------------------------------------------------------------------ 255 256 inline 257 void SAL_CALL CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor ) 258 { 259 // we ignore all formats that couldn't be translated 260 if ( aFlavor.MimeType.getLength( ) ) 261 { 262 OSL_ASSERT( isValidFlavor( aFlavor ) ); 263 264 m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 ); 265 m_FlavorList[m_FlavorList.getLength( ) - 1] = aFlavor; 266 } 267 } 268 269 //------------------------------------------------------------------------ 270 // helper function 271 //------------------------------------------------------------------------ 272 273 //inline 274 DataFlavor SAL_CALL CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) 275 { 276 DataFlavor aFlavor; 277 LCID lcid = 0; 278 279 // for non-unicode text format we must provid a locale to get 280 // the character-set of the text, if there is no locale on the 281 // clipboard we assume the text is in a charset appropriate for 282 // the current thread locale 283 if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) ) 284 lcid = getLocaleFromClipboard( ); 285 286 return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid ); 287 } 288 289 //------------------------------------------------------------------------ 290 // returns the current locale on clipboard; if there is no locale on 291 // clipboard the function returns the current thread locale 292 //------------------------------------------------------------------------ 293 294 LCID SAL_CALL CDOTransferable::getLocaleFromClipboard( ) 295 { 296 LCID lcid = GetThreadLocale( ); 297 298 try 299 { 300 CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE ); 301 ByteSequence_t aLCIDSeq = getClipboardData( fetc ); 302 lcid = *(reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) ) ); 303 304 // because of a Win95/98 Bug; there the high word 305 // of a locale has the same value as the 306 // low word e.g. 0x07040704 that's not right 307 // correct is 0x00000704 308 lcid &= 0x0000FFFF; 309 } 310 catch(...) 311 { 312 // we take the default locale 313 } 314 315 return lcid; 316 } 317 318 //------------------------------------------------------------------------ 319 // i think it's not necessary to call ReleaseStgMedium 320 // in case of failures because nothing should have been 321 // allocated etc. 322 //------------------------------------------------------------------------ 323 324 CDOTransferable::ByteSequence_t SAL_CALL CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc ) 325 { 326 STGMEDIUM stgmedium; 327 HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium ); 328 329 // in case of failure to get a WMF metafile handle, try to get a memory block 330 if( FAILED( hr ) && 331 ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) && 332 ( TYMED_MFPICT == aFormatEtc.getTymed() ) ) 333 { 334 CFormatEtc aTempFormat( aFormatEtc ); 335 aTempFormat.setTymed( TYMED_HGLOBAL ); 336 hr = m_rDataObject->GetData( aTempFormat, &stgmedium ); 337 } 338 339 if ( FAILED( hr ) ) 340 { 341 OSL_ASSERT( (hr != E_INVALIDARG) && 342 (hr != DV_E_DVASPECT) && 343 (hr != DV_E_LINDEX) && 344 (hr != DV_E_TYMED) ); 345 346 if ( DV_E_FORMATETC == hr ) 347 throw UnsupportedFlavorException( ); 348 else if ( STG_E_MEDIUMFULL == hr ) 349 throw IOException( ); 350 else 351 throw RuntimeException( ); 352 } 353 354 ByteSequence_t byteStream; 355 356 try 357 { 358 if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() ) 359 byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile ); 360 else if (CF_HDROP == aFormatEtc.getClipformat()) 361 byteStream = CF_HDROPToFileList(stgmedium.hGlobal); 362 else if ( CF_BITMAP == aFormatEtc.getClipformat() ) 363 { 364 byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap); 365 if( aFormatEtc.getTymed() == TYMED_GDI && 366 ! stgmedium.pUnkForRelease ) 367 { 368 DeleteObject(stgmedium.hBitmap); 369 } 370 } 371 else 372 { 373 clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream ); 374 375 // format conversion if necessary 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" substract 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 throw (::com::sun::star::uno::RuntimeException) 612 { 613 Any retVal; 614 615 sal_uInt8 * arProcCaller= (sal_uInt8*)(sal_Int8*) aProcessId.getConstArray(); 616 sal_uInt8 arId[16]; 617 rtl_getGlobalProcessId(arId); 618 if( ! memcmp( arId, arProcCaller,16)) 619 { 620 if (m_rDataObject.is()) 621 { 622 IDataObject* pObj= m_rDataObject.get(); 623 pObj->AddRef(); 624 retVal.setValue( &pObj, getCppuType((sal_uInt32*)0)); 625 } 626 } 627 return retVal; 628 } 629 630