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