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_DIBV5 == aFormatEtc.getClipformat() || CF_DIB == aFormatEtc.getClipformat()) 362 { 363 byteStream = WinDIBToOOBMP(byteStream); 364 } 365 else if(CF_METAFILEPICT == aFormatEtc.getClipformat()) 366 { 367 byteStream = WinMFPictToOOMFPict(byteStream); 368 } 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