xref: /AOO41X/main/dtrans/source/win32/dtobj/FetcList.cxx (revision d3e0dd8eb215533c15e891ee35bd141abe9397ee)
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 <osl/diagnose.h>
31 #include "FetcList.hxx"
32 #include "Fetc.hxx"
33 #include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
34 #include <com/sun/star/datatransfer/XMimeContentType.hpp>
35 
36 #ifndef _DATAFORMATTRANSLATOR_HXX_
37 #include "DataFmtTransl.hxx"
38 #endif
39 #include "..\misc\ImplHelper.hxx"
40 #include "..\misc\WinClip.hxx"
41 
42 #include <algorithm>
43 
44 #include "MimeAttrib.hxx"
45 
46 //------------------------------------------------------------------------
47 // namespace directives
48 //------------------------------------------------------------------------
49 
50 using namespace com::sun::star::uno;
51 using namespace com::sun::star::datatransfer;
52 using namespace com::sun::star::lang;
53 using namespace com::sun::star::container;
54 using namespace rtl;
55 using namespace std;
56 
57 //------------------------------------------------------------------------
58 //
59 //------------------------------------------------------------------------
60 
61 LCID       CFormatRegistrar::m_TxtLocale   = 0;
62 sal_uInt32 CFormatRegistrar::m_TxtCodePage = GetACP( );
63 
64 //------------------------------------------------------------------------
65 //
66 //------------------------------------------------------------------------
67 
CFormatEtcContainer()68 CFormatEtcContainer::CFormatEtcContainer( )
69 {
70     m_EnumIterator = m_FormatMap.begin( );
71 }
72 
73 //------------------------------------------------------------------------
74 //
75 //------------------------------------------------------------------------
76 
addFormatEtc(const CFormatEtc & fetc)77 void CFormatEtcContainer::addFormatEtc( const CFormatEtc& fetc )
78 {
79     m_FormatMap.push_back( CFormatEtc( fetc ) );
80 }
81 
82 //------------------------------------------------------------------------
83 //
84 //------------------------------------------------------------------------
85 
removeFormatEtc(const CFormatEtc & fetc)86 void SAL_CALL CFormatEtcContainer::removeFormatEtc( const CFormatEtc& fetc )
87 {
88     FormatEtcMap_t::iterator iter =
89         find( m_FormatMap.begin(), m_FormatMap.end(), fetc );
90 
91     if ( iter != m_FormatMap.end( ) )
92         m_FormatMap.erase( iter );
93 }
94 
95 //------------------------------------------------------------------------
96 //
97 //------------------------------------------------------------------------
98 
removeAllFormatEtc()99 void SAL_CALL CFormatEtcContainer::removeAllFormatEtc( )
100 {
101     m_FormatMap.clear( );
102 }
103 
104 //------------------------------------------------------------------------
105 //
106 //------------------------------------------------------------------------
107 
hasFormatEtc(const CFormatEtc & fetc) const108 sal_Bool CFormatEtcContainer::hasFormatEtc( const CFormatEtc& fetc ) const
109 {
110     FormatEtcMap_t::const_iterator iter =
111         find( m_FormatMap.begin(), m_FormatMap.end(), fetc );
112 
113     return ( iter != m_FormatMap.end( ) );
114 }
115 
116 //------------------------------------------------------------------------
117 //
118 //------------------------------------------------------------------------
119 
hasElements() const120 sal_Bool CFormatEtcContainer::hasElements( ) const
121 {
122     return ( m_FormatMap.size( ) > 0 );
123 }
124 
125 //------------------------------------------------------------------------
126 //
127 //------------------------------------------------------------------------
128 
beginEnumFormatEtc()129 void CFormatEtcContainer::beginEnumFormatEtc( )
130 {
131     m_EnumIterator = m_FormatMap.begin( );
132 }
133 
134 //------------------------------------------------------------------------
135 //
136 //------------------------------------------------------------------------
137 
nextFormatEtc(LPFORMATETC lpFetc,sal_uInt32 aNum)138 sal_uInt32 SAL_CALL CFormatEtcContainer::nextFormatEtc( LPFORMATETC lpFetc,
139                                                         sal_uInt32 aNum )
140 {
141     OSL_ASSERT( lpFetc );
142     OSL_ASSERT( !IsBadWritePtr( lpFetc, sizeof( FORMATETC ) * aNum ) );
143 
144     sal_uInt32 nFetched = 0;
145 
146     for ( sal_uInt32 i = 0; i < aNum; i++, nFetched++, lpFetc++, ++m_EnumIterator )
147     {
148         if ( m_EnumIterator == m_FormatMap.end() )
149             break;
150         CopyFormatEtc( lpFetc, *m_EnumIterator );
151     }
152 
153     return nFetched;
154 }
155 
156 
157 //------------------------------------------------------------------------
158 //
159 //------------------------------------------------------------------------
160 
skipFormatEtc(sal_uInt32 aNum)161 sal_Bool SAL_CALL CFormatEtcContainer::skipFormatEtc( sal_uInt32 aNum )
162 {
163     FormatEtcMap_t::const_iterator iter_end = m_FormatMap.end( );
164     for ( sal_uInt32 i = 0;
165           (i < aNum) && (m_EnumIterator != iter_end);
166           i++, ++m_EnumIterator )
167         ;/* intentionally left empty */
168 
169     return ( m_EnumIterator != m_FormatMap.end( ) );
170 }
171 
172 
173 //#########################################################################
174 
175 
176 //------------------------------------------------------------------------
177 //
178 //------------------------------------------------------------------------
179 
CFormatRegistrar(const Reference<XMultiServiceFactory> & ServiceManager,const CDataFormatTranslator & aDataFormatTranslator)180 CFormatRegistrar::CFormatRegistrar( const Reference< XMultiServiceFactory >& ServiceManager,
181                                     const CDataFormatTranslator& aDataFormatTranslator ) :
182     m_DataFormatTranslator( aDataFormatTranslator ),
183     m_bHasSynthesizedLocale( sal_False ),
184     m_SrvMgr( ServiceManager )
185 {
186 }
187 
188 // ----------------------------------------------------------------------------------------
189 // this function converts all DataFlavors of the given FlavorList into
190 // an appropriate FORMATETC structure, for some formats like unicodetext,
191 // text and text/html we will offer an accompany format e.g.:
192 //
193 // DataFlavor               | Registered Clipformat     |   Registered accompany clipformat
194 // -------------------------|---------------------------|-----------------------------------
195 // text/plain;charset=ansi  | CF_TEXT                   |   CF_UNICODETEXT
196 //                          |                           |   CF_LOCALE (if charset != GetACP()
197 //                          |                           |
198 // text/plain;charset=oem   | CF_OEMTEXT                |   CF_UNICODETEXT
199 //                          |                           |   CF_LOCALE (if charset != GetOEMCP()
200 //                          |                           |
201 // text/plain;charset=utf-16| CF_UNICODETEXT            |   CF_TEXT
202 //                          |                           |
203 // text/html                | HTML (Hypertext ...)      |   HTML Format
204 //                          |                           |
205 //
206 // if some tries to register different text formats with different charsets the last
207 // registered wins and the others are ignored
208 // ----------------------------------------------------------------------------------------
209 
RegisterFormats(const Reference<XTransferable> & aXTransferable,CFormatEtcContainer & aFormatEtcContainer)210 void SAL_CALL CFormatRegistrar::RegisterFormats(
211     const Reference< XTransferable >& aXTransferable, CFormatEtcContainer& aFormatEtcContainer )
212 {
213     Sequence< DataFlavor > aFlavorList = aXTransferable->getTransferDataFlavors( );
214     sal_Int32  nFlavors                = aFlavorList.getLength( );
215     sal_Bool   bUnicodeRegistered      = sal_False;
216     DataFlavor aFlavor;
217 
218     for( sal_Int32 i = 0; i < nFlavors; i++ )
219     {
220         aFlavor = aFlavorList[i];
221         CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
222 
223         // maybe an internal format so we ignore it
224         if ( CF_INVALID == fetc.getClipformat( ) )
225             continue;
226 
227         if ( !needsToSynthesizeAccompanyFormats( fetc ) )
228             aFormatEtcContainer.addFormatEtc( fetc );
229         else
230         {
231             // if we haven't registered any text format up to now
232             if ( m_DataFormatTranslator.isTextFormat( fetc.getClipformat() ) && !bUnicodeRegistered )
233             {
234                 // if the transferable supports unicode text we ignore
235                 // any further text format the transferable offers
236                 // because we can create it from Unicode text in addition
237                 // we register CF_TEXT for non unicode clients
238                 if ( m_DataFormatTranslator.isUnicodeTextFormat( fetc.getClipformat() ) )
239                 {
240                     aFormatEtcContainer.addFormatEtc( fetc ); // add CF_UNICODE
241                     aFormatEtcContainer.addFormatEtc(
242                         m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT ) ); // add CF_TEXT
243                     bUnicodeRegistered = sal_True;
244                 }
245                 else if ( !hasUnicodeFlavor( aXTransferable ) )
246                 {
247                     // we try to investigate the charset and make a valid
248                     // windows codepage from this charset the default
249                     // return value is the result of GetACP( )
250                     OUString charset = getCharsetFromDataFlavor( aFlavor );
251                     sal_uInt32 txtCP = getWinCPFromMimeCharset( charset );
252 
253                     // we try to get a Locale appropriate for this codepage
254                     if ( findLocaleForTextCodePage( ) )
255                     {
256                         m_TxtCodePage = txtCP;
257 
258                         aFormatEtcContainer.addFormatEtc(
259                             m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) );
260 
261                         if ( !IsOEMCP( m_TxtCodePage ) )
262                             aFormatEtcContainer.addFormatEtc(
263                                 m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT ) );
264                         else
265                             aFormatEtcContainer.addFormatEtc(
266                                 m_DataFormatTranslator.getFormatEtcForClipformat( CF_OEMTEXT ) );
267 
268                         aFormatEtcContainer.addFormatEtc(
269                             m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE ) );
270 
271                         // we save the flavor so it's easier when
272                         // queried for it in XTDataObject::GetData(...)
273                         m_RegisteredTextFlavor  = aFlavor;
274                         m_bHasSynthesizedLocale = sal_True;
275                     }
276                 }
277             }
278             else if ( m_DataFormatTranslator.isTextHtmlFormat( fetc.getClipformat( ) ) ) // Html (Hyper Text...)
279             {
280                 // we add text/html ( HTML (HyperText Markup Language) )
281                 aFormatEtcContainer.addFormatEtc( fetc );
282 
283                 // and HTML Format
284                 OUString htmlFormat( OUString::createFromAscii( "HTML Format" ) );
285                 aFormatEtcContainer.addFormatEtc(
286                     m_DataFormatTranslator.getFormatEtcForClipformatName( htmlFormat ) );
287             }
288         }
289     }
290 }
291 
292 //------------------------------------------------------------------------
293 //
294 //------------------------------------------------------------------------
295 
hasSynthesizedLocale() const296 sal_Bool SAL_CALL CFormatRegistrar::hasSynthesizedLocale( ) const
297 {
298     return m_bHasSynthesizedLocale;
299 }
300 
301 //------------------------------------------------------------------------
302 //
303 //------------------------------------------------------------------------
304 
getSynthesizedLocale() const305 LCID SAL_CALL CFormatRegistrar::getSynthesizedLocale( ) const
306 {
307     return m_TxtLocale;
308 }
309 
310 //------------------------------------------------------------------------
311 //
312 //------------------------------------------------------------------------
313 
getRegisteredTextCodePage() const314 sal_uInt32 SAL_CALL CFormatRegistrar::getRegisteredTextCodePage( ) const
315 {
316     return m_TxtCodePage;
317 }
318 
319 //------------------------------------------------------------------------
320 //
321 //------------------------------------------------------------------------
322 
getRegisteredTextFlavor() const323 DataFlavor SAL_CALL CFormatRegistrar::getRegisteredTextFlavor( ) const
324 {
325     return m_RegisteredTextFlavor;
326 }
327 
328 //------------------------------------------------------------------------
329 //
330 //------------------------------------------------------------------------
331 
isSynthesizeableFormat(const CFormatEtc & aFormatEtc) const332 sal_Bool SAL_CALL CFormatRegistrar::isSynthesizeableFormat( const CFormatEtc& aFormatEtc ) const
333 {
334     return ( m_DataFormatTranslator.isOemOrAnsiTextFormat( aFormatEtc.getClipformat() ) ||
335              m_DataFormatTranslator.isUnicodeTextFormat( aFormatEtc.getClipformat() ) ||
336              m_DataFormatTranslator.isHTMLFormat( aFormatEtc.getClipformat() ) );
337 }
338 
339 //------------------------------------------------------------------------
340 //
341 //------------------------------------------------------------------------
342 
343 inline
needsToSynthesizeAccompanyFormats(const CFormatEtc & aFormatEtc) const344 sal_Bool SAL_CALL CFormatRegistrar::needsToSynthesizeAccompanyFormats( const CFormatEtc& aFormatEtc ) const
345 {
346     return ( m_DataFormatTranslator.isOemOrAnsiTextFormat( aFormatEtc.getClipformat() ) ||
347              m_DataFormatTranslator.isUnicodeTextFormat( aFormatEtc.getClipformat() ) ||
348              m_DataFormatTranslator.isTextHtmlFormat( aFormatEtc.getClipformat( ) ) );
349 }
350 
351 //------------------------------------------------------------------------
352 //
353 //------------------------------------------------------------------------
354 
getCharsetFromDataFlavor(const DataFlavor & aFlavor)355 OUString SAL_CALL CFormatRegistrar::getCharsetFromDataFlavor( const DataFlavor& aFlavor )
356 {
357     OUString charset;
358 
359     try
360     {
361         Reference< XMimeContentTypeFactory > xMimeFac(
362             m_SrvMgr->createInstance( OUString::createFromAscii( \
363                 "com.sun.star.datatransfer.MimeContentTypeFactory" ) ), UNO_QUERY );
364 
365         if( xMimeFac.is( ) )
366         {
367             Reference< XMimeContentType > xMimeType( xMimeFac->createMimeContentType( aFlavor.MimeType ) );
368             if ( xMimeType->hasParameter( TEXTPLAIN_PARAM_CHARSET ) )
369                 charset = xMimeType->getParameterValue( TEXTPLAIN_PARAM_CHARSET );
370             else
371                 charset = getMimeCharsetFromWinCP( GetACP( ), PRE_WINDOWS_CODEPAGE );
372         }
373     }
374     catch(NoSuchElementException&)
375     {
376         OSL_ENSURE( sal_False, "Unexpected" );
377     }
378     catch(...)
379     {
380         OSL_ENSURE( sal_False, "Invalid data flavor" );
381     }
382 
383     return charset;
384 }
385 
386 //------------------------------------------------------------------------
387 //
388 //------------------------------------------------------------------------
389 
hasUnicodeFlavor(const Reference<XTransferable> & aXTransferable) const390 sal_Bool SAL_CALL CFormatRegistrar::hasUnicodeFlavor( const Reference< XTransferable >& aXTransferable ) const
391 {
392     CFormatEtc fetc( CF_UNICODETEXT );
393 
394     DataFlavor aFlavor =
395         m_DataFormatTranslator.getDataFlavorFromFormatEtc( fetc );
396 
397     return aXTransferable->isDataFlavorSupported( aFlavor );
398 }
399 
400 //------------------------------------------------------------------------
401 //
402 //------------------------------------------------------------------------
403 
404 inline
isEqualCurrentSystemCodePage(sal_uInt32 aCodePage) const405 sal_Bool CFormatRegistrar::isEqualCurrentSystemCodePage( sal_uInt32 aCodePage ) const
406 {
407     return ( (aCodePage == GetOEMCP()) || (aCodePage == GetACP()) );
408 }
409 
410 //------------------------------------------------------------------------
411 //
412 //------------------------------------------------------------------------
413 
findLocaleForTextCodePage()414 sal_Bool SAL_CALL CFormatRegistrar::findLocaleForTextCodePage( )
415 {
416     m_TxtLocale = 0;
417     EnumSystemLocalesA( CFormatRegistrar::EnumLocalesProc, LCID_INSTALLED );
418     return ( IsValidLocale( m_TxtLocale, LCID_INSTALLED ) ) ? sal_True : sal_False;
419 }
420 
421 //------------------------------------------------------------------------
422 //
423 //------------------------------------------------------------------------
424 
isLocaleCodePage(LCID lcid,LCTYPE lctype,sal_uInt32 codepage)425 sal_Bool SAL_CALL CFormatRegistrar::isLocaleCodePage( LCID lcid, LCTYPE lctype, sal_uInt32 codepage )
426 {
427     char  buff[6];
428     sal_uInt32 localeCodePage;
429 
430     OSL_ASSERT( IsValidLocale( lcid, LCID_INSTALLED ) );
431 
432     // get the ansi codepage of the current locale
433     GetLocaleInfoA( lcid, lctype, buff, sizeof( buff ) );
434     localeCodePage = atol( buff );
435 
436     return ( localeCodePage == codepage );
437 }
438 
439 //------------------------------------------------------------------------
440 //
441 //------------------------------------------------------------------------
442 
443 inline
isLocaleOemCodePage(LCID lcid,sal_uInt32 codepage)444 sal_Bool SAL_CALL CFormatRegistrar::isLocaleOemCodePage( LCID lcid, sal_uInt32 codepage )
445 {
446     return isLocaleCodePage( lcid, LOCALE_IDEFAULTCODEPAGE, codepage );
447 }
448 
449 //------------------------------------------------------------------------
450 //
451 //------------------------------------------------------------------------
452 
453 inline
isLocaleAnsiCodePage(LCID lcid,sal_uInt32 codepage)454 sal_Bool SAL_CALL CFormatRegistrar::isLocaleAnsiCodePage( LCID lcid, sal_uInt32 codepage )
455 {
456     return isLocaleCodePage( lcid, LOCALE_IDEFAULTANSICODEPAGE, codepage );
457 }
458 
459 //------------------------------------------------------------------------
460 //
461 //------------------------------------------------------------------------
462 
EnumLocalesProc(LPSTR lpLocaleStr)463 BOOL CALLBACK CFormatRegistrar::EnumLocalesProc( LPSTR lpLocaleStr )
464 {
465     // the lpLocaleStr parametere is hexadecimal
466     LCID lcid = strtol( lpLocaleStr, NULL, 16 );
467 
468     if ( isLocaleAnsiCodePage( lcid, CFormatRegistrar::m_TxtCodePage ) ||
469          isLocaleOemCodePage( lcid, CFormatRegistrar::m_TxtCodePage ) )
470     {
471         CFormatRegistrar::m_TxtLocale = lcid;
472         return sal_False; // stop enumerating
473     }
474 
475     return sal_True;
476 }
477 
478