xref: /AOO41X/main/dtrans/source/win32/dtobj/DOTransferable.cxx (revision 03c97e340010506c11d4ffaab7f577e5f7050fe6)
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