xref: /trunk/main/dtrans/source/win32/dtobj/DOTransferable.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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
isValidFlavor(const DataFlavor & aFlavor)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 
CDOTransferable(const Reference<XMultiServiceFactory> & ServiceManager,IDataObjectPtr rDataObject)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 
getTransferData(const DataFlavor & aFlavor)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 
getTransferDataFlavors()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 
isDataFlavorSupported(const DataFlavor & aFlavor)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 
initFlavorList()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
addSupportedFlavor(const DataFlavor & aFlavor)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
formatEtcToDataFlavor(const FORMATETC & aFormatEtc)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 
getLocaleFromClipboard()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 
getClipboardData(CFormatEtc & aFormatEtc)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 
synthesizeUnicodeText()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 
clipDataToByteStream(CLIPFORMAT cf,STGMEDIUM stgmedium,ByteSequence_t & aByteSequence)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
byteStreamToAny(ByteSequence_t & aByteStream,const Type & aRequestedDataType)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
byteStreamToOUString(ByteSequence_t & aByteStream)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 
compareDataFlavors(const DataFlavor & lhs,const DataFlavor & rhs)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 
cmpFullMediaType(const Reference<XMimeContentType> & xLhs,const Reference<XMimeContentType> & xRhs) const559 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 
cmpAllContentTypeParameter(const Reference<XMimeContentType> & xLhs,const Reference<XMimeContentType> & xRhs) const569 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 
getData(const Sequence<sal_Int8> & aProcessId)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