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