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