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