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