xref: /trunk/main/dtrans/source/win32/dtobj/DOTransferable.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_dtrans.hxx"
30 
31 //------------------------------------------------------------------------
32 // includes
33 //------------------------------------------------------------------------
34 #include <sal/types.h>
35 #include <rtl/process.h>
36 
37 #ifndef _DOWRAPPERTRANSFERABLE_HXX_
38 #include "DOTransferable.hxx"
39 #endif
40 #include "..\misc\ImplHelper.hxx"
41 #include "..\misc\WinClip.hxx"
42 #include "DTransHelper.hxx"
43 #include "..\misc\ImplHelper.hxx"
44 #include "TxtCnvtHlp.hxx"
45 #include "MimeAttrib.hxx"
46 #include "FmtFilter.hxx"
47 #include "Fetc.hxx"
48 
49 
50 #if(_MSC_VER < 1300) && !defined(__MINGW32__)
51 #include <olestd.h>
52 #endif
53 
54 #define STR2(x) #x
55 #define STR(x) STR2(x)
56 #define PRAGMA_MSG( msg ) message( __FILE__ "(" STR(__LINE__) "): " #msg )
57 
58 //------------------------------------------------------------------------
59 // namespace directives
60 //------------------------------------------------------------------------
61 
62 using namespace rtl;
63 using namespace std;
64 using namespace osl;
65 using namespace cppu;
66 using namespace com::sun::star::uno;
67 using namespace com::sun::star::datatransfer;
68 using namespace com::sun::star::io;
69 using namespace com::sun::star::lang;
70 using namespace com::sun::star::container;
71 
72 //------------------------------------------------------------------------
73 //
74 //------------------------------------------------------------------------
75 
76 namespace
77 {
78     const Type CPPUTYPE_SEQINT8  = getCppuType( ( Sequence< sal_Int8 >* )0 );
79     const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 );
80 
81     inline
82     sal_Bool isValidFlavor( const DataFlavor& aFlavor )
83     {
84         return ( aFlavor.MimeType.getLength( ) &&
85                  ( ( aFlavor.DataType ==  CPPUTYPE_SEQINT8 ) ||
86                  ( aFlavor.DataType == CPPUTYPE_OUSTRING ) ) );
87     }
88 
89 } // end namespace
90 
91 
92 //------------------------------------------------------------------------
93 // ctor
94 //------------------------------------------------------------------------
95 
96 CDOTransferable::CDOTransferable(
97     const Reference< XMultiServiceFactory >& ServiceManager, IDataObjectPtr rDataObject ) :
98     m_rDataObject( rDataObject ),
99     m_SrvMgr( ServiceManager ),
100     m_DataFormatTranslator( m_SrvMgr ),
101     m_bUnicodeRegistered( sal_False ),
102     m_TxtFormatOnClipboard( CF_INVALID )
103 {
104 }
105 
106 //------------------------------------------------------------------------
107 //
108 //------------------------------------------------------------------------
109 
110 Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor )
111         throw( UnsupportedFlavorException, IOException, RuntimeException )
112 {
113     OSL_ASSERT( isValidFlavor( aFlavor ) );
114 
115     MutexGuard aGuard( m_aMutex );
116 
117     //------------------------------------------------
118     // convert dataflavor to formatetc
119     //------------------------------------------------
120 
121     CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
122     OSL_ASSERT( CF_INVALID != fetc.getClipformat() );
123 
124     //------------------------------------------------
125     //  get the data from clipboard in a byte stream
126     //------------------------------------------------
127 
128     ByteSequence_t clipDataStream;
129 
130     try
131     {
132         clipDataStream = getClipboardData( fetc );
133     }
134     catch( UnsupportedFlavorException& )
135     {
136         if ( m_DataFormatTranslator.isUnicodeTextFormat( fetc.getClipformat( ) ) &&
137              m_bUnicodeRegistered )
138         {
139              OUString aUnicodeText = synthesizeUnicodeText( );
140              Any aAny = makeAny( aUnicodeText );
141              return aAny;
142         }
143         else
144             throw; // pass through exception
145     }
146 
147     //------------------------------------------------
148     // return the data as any
149     //------------------------------------------------
150 
151     return byteStreamToAny( clipDataStream, aFlavor.DataType );
152 }
153 
154 //------------------------------------------------------------------------
155 // getTransferDataFlavors
156 //------------------------------------------------------------------------
157 
158 Sequence< DataFlavor > SAL_CALL CDOTransferable::getTransferDataFlavors(  )
159     throw( RuntimeException )
160 {
161     return m_FlavorList;
162 }
163 
164 //------------------------------------------------------------------------
165 // isDataFlavorSupported
166 // returns true if we find a DataFlavor with the same MimeType and
167 // DataType
168 //------------------------------------------------------------------------
169 
170 sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
171     throw( RuntimeException )
172 {
173     OSL_ASSERT( isValidFlavor( aFlavor ) );
174 
175     for ( sal_Int32 i = 0; i < m_FlavorList.getLength( ); i++ )
176         if ( compareDataFlavors( aFlavor, m_FlavorList[i] ) )
177             return sal_True;
178 
179     return sal_False;
180 }
181 
182 //------------------------------------------------------------------------
183 // helper function
184 // the list of datafalvors currently on the clipboard will be initialized
185 // only once; if the client of this Transferable will hold a reference
186 // to it und the underlying clipboard content changes, the client does
187 // possible operate on a invalid list
188 // if there is only text on the clipboard we will also offer unicode text
189 // an synthesize this format on the fly if requested, to accomplish this
190 // we save the first offered text format which we will later use for the
191 // conversion
192 //------------------------------------------------------------------------
193 
194 void SAL_CALL CDOTransferable::initFlavorList( )
195 {
196     IEnumFORMATETCPtr pEnumFormatEtc;
197     HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc );
198     if ( SUCCEEDED( hr ) )
199     {
200         pEnumFormatEtc->Reset( );
201 
202         FORMATETC fetc;
203         while ( S_FALSE != pEnumFormatEtc->Next( 1, &fetc, NULL ) )
204         {
205             // we use locales only to determine the
206             // charset if there is text on the cliboard
207             // we don't offer this format
208             if ( CF_LOCALE == fetc.cfFormat )
209                 continue;
210 
211             DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
212 
213             // if text or oemtext is offered we also pretend to have unicode text
214             if ( m_DataFormatTranslator.isOemOrAnsiTextFormat( fetc.cfFormat ) &&
215                  !m_bUnicodeRegistered )
216             {
217                 addSupportedFlavor( aFlavor );
218 
219                 m_TxtFormatOnClipboard = fetc.cfFormat;
220                 m_bUnicodeRegistered   = sal_True;
221 
222                 // register unicode text as accompany format
223                 aFlavor = formatEtcToDataFlavor(
224                     m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) );
225                 addSupportedFlavor( aFlavor );
226             }
227             else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered )
228             {
229                 addSupportedFlavor( aFlavor );
230                 m_bUnicodeRegistered = sal_True;
231             }
232             else
233                 addSupportedFlavor( aFlavor );
234 
235             // see MSDN IEnumFORMATETC
236             CoTaskMemFree( fetc.ptd );
237         }
238     }
239 }
240 
241 //------------------------------------------------------------------------
242 //
243 //------------------------------------------------------------------------
244 
245 inline
246 void SAL_CALL CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor )
247 {
248     // we ignore all formats that couldn't be translated
249     if ( aFlavor.MimeType.getLength( ) )
250     {
251         OSL_ASSERT( isValidFlavor( aFlavor ) );
252 
253         m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 );
254         m_FlavorList[m_FlavorList.getLength( ) - 1] = aFlavor;
255     }
256 }
257 
258 //------------------------------------------------------------------------
259 // helper function
260 //------------------------------------------------------------------------
261 
262 //inline
263 DataFlavor SAL_CALL CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc )
264 {
265     DataFlavor aFlavor;
266     LCID lcid = 0;
267 
268     // for non-unicode text format we must provid a locale to get
269     // the character-set of the text, if there is no locale on the
270     // clipboard we assume the text is in a charset appropriate for
271     // the current thread locale
272     if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) )
273         lcid = getLocaleFromClipboard( );
274 
275     return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid );
276 }
277 
278 //------------------------------------------------------------------------
279 // returns the current locale on clipboard; if there is no locale on
280 // clipboard the function returns the current thread locale
281 //------------------------------------------------------------------------
282 
283 LCID SAL_CALL CDOTransferable::getLocaleFromClipboard( )
284 {
285     LCID lcid = GetThreadLocale( );
286 
287     try
288     {
289         CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE );
290         ByteSequence_t aLCIDSeq = getClipboardData( fetc );
291         lcid = *(reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) ) );
292 
293         // because of a Win95/98 Bug; there the high word
294         // of a locale has the same value as the
295         // low word e.g. 0x07040704 that's not right
296         // correct is 0x00000704
297         lcid &= 0x0000FFFF;
298     }
299     catch(...)
300     {
301         // we take the default locale
302     }
303 
304     return lcid;
305 }
306 
307 //------------------------------------------------------------------------
308 // i think it's not necessary to call ReleaseStgMedium
309 // in case of failures because nothing should have been
310 // allocated etc.
311 //------------------------------------------------------------------------
312 
313 CDOTransferable::ByteSequence_t SAL_CALL CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc )
314 {
315     STGMEDIUM stgmedium;
316     HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium );
317 
318     // in case of failure to get a WMF metafile handle, try to get a memory block
319     if( FAILED( hr ) &&
320         ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) &&
321         ( TYMED_MFPICT == aFormatEtc.getTymed() ) )
322     {
323         CFormatEtc aTempFormat( aFormatEtc );
324         aTempFormat.setTymed( TYMED_HGLOBAL );
325         hr = m_rDataObject->GetData( aTempFormat, &stgmedium );
326     }
327 
328     if ( FAILED( hr ) )
329     {
330         OSL_ASSERT( (hr != E_INVALIDARG) &&
331                     (hr != DV_E_DVASPECT) &&
332                     (hr != DV_E_LINDEX) &&
333                     (hr != DV_E_TYMED) );
334 
335         if ( DV_E_FORMATETC == hr )
336             throw UnsupportedFlavorException( );
337         else if ( STG_E_MEDIUMFULL == hr )
338             throw IOException( );
339         else
340             throw RuntimeException( );
341     }
342 
343     ByteSequence_t byteStream;
344 
345     try
346     {
347         if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() )
348             byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile );
349         else if (CF_HDROP == aFormatEtc.getClipformat())
350             byteStream = CF_HDROPToFileList(stgmedium.hGlobal);
351         else if ( CF_BITMAP == aFormatEtc.getClipformat() )
352         {
353             byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap);
354             if( aFormatEtc.getTymed() == TYMED_GDI &&
355                 ! stgmedium.pUnkForRelease )
356             {
357                 DeleteObject(stgmedium.hBitmap);
358             }
359         }
360         else
361         {
362             clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream );
363 
364             // format conversion if necessary
365             if ( CF_DIB == aFormatEtc.getClipformat() )
366                 byteStream = WinDIBToOOBMP( byteStream );
367             else if ( CF_METAFILEPICT == aFormatEtc.getClipformat() )
368                 byteStream = WinMFPictToOOMFPict( byteStream );
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