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