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 "DataFmtTransl.hxx"
35 #include <rtl/string.hxx>
36 #include <osl/diagnose.h>
37 #include <rtl/tencinfo.h>
38 #include "..\misc\ImplHelper.hxx"
39 #include "..\misc\WinClip.hxx"
40 #include "MimeAttrib.hxx"
41 #include "DTransHelper.hxx"
42 #include <rtl/string.h>
43 #include "Fetc.hxx"
44 
45 #if defined _MSC_VER
46 #pragma warning(push,1)
47 #pragma warning(disable:4917)
48 #endif
49 #include <windows.h>
50 #if (_MSC_VER < 1300) && !defined(__MINGW32__)
51 #include <olestd.h>
52 #endif
53 #include <shlobj.h>
54 #if defined _MSC_VER
55 #pragma warning(pop)
56 #endif
57 
58 
59 //------------------------------------------------------------------------
60 // namespace directives
61 //------------------------------------------------------------------------
62 
63 using namespace rtl;
64 using namespace std;
65 using namespace com::sun::star::uno;
66 using namespace com::sun::star::datatransfer;
67 using namespace com::sun::star::lang;
68 
69 //------------------------------------------------------------------------
70 // const
71 //------------------------------------------------------------------------
72 
73 const Type       CPPUTYPE_SALINT32   = getCppuType((sal_Int32*)0);
74 const Type       CPPUTYPE_SALINT8    = getCppuType((sal_Int8*)0);
75 const Type       CPPUTYPE_OUSTRING   = getCppuType((OUString*)0);
76 const Type       CPPUTYPE_SEQSALINT8 = getCppuType((Sequence< sal_Int8>*)0);
77 const sal_Int32  MAX_CLIPFORMAT_NAME = 256;
78 
79 const OUString TEXT_PLAIN_CHARSET   = OUString::createFromAscii( "text/plain;charset=" );
80 const OUString HPNAME_OEM_ANSI_TEXT = OUString::createFromAscii( "OEM/ANSI Text" );
81 
82 const OUString HTML_FORMAT_NAME_WINDOWS = OUString::createFromAscii( "HTML Format" );
83 const OUString HTML_FORMAT_NAME_SOFFICE = OUString::createFromAscii( "HTML (HyperText Markup Language)" );
84 
85 //------------------------------------------------------------------------
86 //
87 //------------------------------------------------------------------------
88 
89 CDataFormatTranslator::CDataFormatTranslator( const Reference< XMultiServiceFactory >& aServiceManager ) :
90 	m_SrvMgr( aServiceManager )
91 {
92 	m_XDataFormatTranslator = Reference< XDataFormatTranslator >(
93 		m_SrvMgr->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.DataFormatTranslator" ) ), UNO_QUERY );
94 }
95 
96 //------------------------------------------------------------------------
97 //
98 //------------------------------------------------------------------------
99 
100 CFormatEtc CDataFormatTranslator::getFormatEtcFromDataFlavor( const DataFlavor& aDataFlavor ) const
101 {
102 	sal_Int32 cf = CF_INVALID;
103 
104 	try
105 	{
106         if( m_XDataFormatTranslator.is( ) )
107         {
108 		    Any aFormat = m_XDataFormatTranslator->getSystemDataTypeFromDataFlavor( aDataFlavor );
109 
110 		    if ( aFormat.hasValue( ) )
111 		    {
112 			    if ( aFormat.getValueType( ) == CPPUTYPE_SALINT32 )
113 			    {
114 				    aFormat >>= cf;
115 				    OSL_ENSURE( CF_INVALID != cf, "Invalid Clipboard format delivered" );
116 			    }
117 			    else if ( aFormat.getValueType( ) == CPPUTYPE_OUSTRING )
118 			    {
119 				    OUString aClipFmtName;
120 				    aFormat >>= aClipFmtName;
121 
122 				    OSL_ASSERT( aClipFmtName.getLength( ) );
123 				    cf = RegisterClipboardFormatW( reinterpret_cast<LPCWSTR>(aClipFmtName.getStr( )) );
124 
125 				    OSL_ENSURE( CF_INVALID != cf, "RegisterClipboardFormat failed" );
126 			    }
127 			    else
128 				    OSL_ENSURE( sal_False, "Wrong Any-Type detected" );
129 		    }
130         }
131     }
132 	catch( ... )
133 	{
134 		OSL_ENSURE( sal_False, "Unexpected error" );
135 	}
136 
137 	return sal::static_int_cast<CFormatEtc>(getFormatEtcForClipformat( sal::static_int_cast<CLIPFORMAT>(cf) ));
138 }
139 
140 //------------------------------------------------------------------------
141 //
142 //------------------------------------------------------------------------
143 
144 DataFlavor CDataFormatTranslator::getDataFlavorFromFormatEtc( const FORMATETC& aFormatEtc, LCID lcid ) const
145 {
146 	DataFlavor aFlavor;
147 
148 	try
149 	{
150 		CLIPFORMAT aClipformat = aFormatEtc.cfFormat;
151 
152 		Any aAny;
153 		aAny <<= static_cast< sal_Int32 >( aClipformat );
154 
155 		if ( isOemOrAnsiTextFormat( aClipformat ) )
156 		{
157 			aFlavor.MimeType             = TEXT_PLAIN_CHARSET;
158 			aFlavor.MimeType            += getTextCharsetFromLCID( lcid, aClipformat );
159 
160 			aFlavor.HumanPresentableName = HPNAME_OEM_ANSI_TEXT;
161 			aFlavor.DataType             = CPPUTYPE_SEQSALINT8;
162 		}
163 		else if ( CF_INVALID != aClipformat )
164 		{
165             if ( m_XDataFormatTranslator.is( ) )
166             {
167 			    aFlavor = m_XDataFormatTranslator->getDataFlavorFromSystemDataType( aAny );
168 
169 			    if ( !aFlavor.MimeType.getLength( ) )
170 			    {
171 				    // lookup of DataFlavor from clipboard format id
172 				    // failed, so we try to resolve via clipboard
173 				    // format name
174 				    OUString clipFormatName = getClipboardFormatName( aClipformat );
175 
176 				    // if we could not get a clipboard format name an
177 				    // error must have occured or it is a standard
178 				    // clipboard format that we don't translate, e.g.
179 				    // CF_BITMAP (the office only uses CF_DIB)
180 				    if ( clipFormatName.getLength( ) )
181 				    {
182 					    aAny <<= clipFormatName;
183 					    aFlavor = m_XDataFormatTranslator->getDataFlavorFromSystemDataType( aAny );
184 				    }
185 			    }
186             }
187 		}
188 	}
189 	catch( ... )
190 	{
191 		OSL_ENSURE( sal_False, "Unexpected error" );
192 	}
193 
194 	return aFlavor;
195 }
196 
197 //------------------------------------------------------------------------
198 //
199 //------------------------------------------------------------------------
200 
201 CFormatEtc SAL_CALL CDataFormatTranslator::getFormatEtcForClipformatName( const OUString& aClipFmtName ) const
202 {
203 	// check parameter
204 	if ( !aClipFmtName.getLength( ) )
205 		return CFormatEtc( CF_INVALID );
206 
207 	CLIPFORMAT cf = sal::static_int_cast<CLIPFORMAT>(RegisterClipboardFormatW( reinterpret_cast<LPCWSTR>(aClipFmtName.getStr( )) ));
208 	return getFormatEtcForClipformat( cf );
209 }
210 
211 //------------------------------------------------------------------------
212 //
213 //------------------------------------------------------------------------
214 
215 OUString CDataFormatTranslator::getClipboardFormatName( CLIPFORMAT aClipformat ) const
216 {
217 	OSL_PRECOND( CF_INVALID != aClipformat, "Invalid clipboard format" );
218 
219 	sal_Unicode wBuff[ MAX_CLIPFORMAT_NAME ];
220 	sal_Int32   nLen = GetClipboardFormatNameW( aClipformat, reinterpret_cast<LPWSTR>(wBuff), MAX_CLIPFORMAT_NAME );
221 
222 	return OUString( wBuff, nLen );
223 }
224 
225 //------------------------------------------------------------------------
226 //
227 //------------------------------------------------------------------------
228 
229 CFormatEtc SAL_CALL CDataFormatTranslator::getFormatEtcForClipformat( CLIPFORMAT cf ) const
230 {
231 	CFormatEtc fetc( cf, TYMED_NULL, NULL, DVASPECT_CONTENT );
232 
233 	switch( cf )
234 	{
235 	case CF_METAFILEPICT:
236 		fetc.setTymed( TYMED_MFPICT );
237 		break;
238 
239 	case CF_ENHMETAFILE:
240 		fetc.setTymed( TYMED_ENHMF );
241 		break;
242 
243 	default:
244 		fetc.setTymed( TYMED_HGLOBAL /*| TYMED_ISTREAM*/ );
245 	}
246 
247     /*
248         hack: in order to paste urls copied by Internet Explorer
249         with "copy link" we set the lindex member to 0
250         but if we really want to support CFSTR_FILECONTENT and
251         the accompany format CFSTR_FILEDESCRIPTOR (FileGroupDescriptor)
252         the client of the clipboard service has to provide a id
253         of which FileContents it wants to paste
254         see MSDN: "Handling Shell Data Transfer Scenarios"
255     */
256     if ( cf == RegisterClipboardFormatA( CFSTR_FILECONTENTS ) )
257          fetc.setLindex( 0 );
258 
259 	return fetc;
260 }
261 
262 //------------------------------------------------------------------------
263 //
264 //------------------------------------------------------------------------
265 
266 sal_Bool SAL_CALL CDataFormatTranslator::isOemOrAnsiTextFormat( CLIPFORMAT cf ) const
267 {
268 	return ( (cf == CF_TEXT) || (cf == CF_OEMTEXT) );
269 }
270 
271 //------------------------------------------------------------------------
272 //
273 //------------------------------------------------------------------------
274 
275 sal_Bool SAL_CALL CDataFormatTranslator::isUnicodeTextFormat( CLIPFORMAT cf ) const
276 {
277 	return ( cf == CF_UNICODETEXT );
278 }
279 
280 //------------------------------------------------------------------------
281 //
282 //------------------------------------------------------------------------
283 
284 sal_Bool SAL_CALL CDataFormatTranslator::isTextFormat( CLIPFORMAT cf ) const
285 {
286 	return ( isOemOrAnsiTextFormat( cf ) || isUnicodeTextFormat( cf ) );
287 }
288 
289 //------------------------------------------------------------------------
290 //
291 //------------------------------------------------------------------------
292 
293 sal_Bool SAL_CALL CDataFormatTranslator::isHTMLFormat( CLIPFORMAT cf ) const
294 {
295 	OUString clipFormatName = getClipboardFormatName( cf );
296 	return ( clipFormatName == HTML_FORMAT_NAME_WINDOWS );
297 }
298 
299 //------------------------------------------------------------------------
300 //
301 //------------------------------------------------------------------------
302 
303 sal_Bool SAL_CALL CDataFormatTranslator::isTextHtmlFormat( CLIPFORMAT cf ) const
304 {
305 	OUString clipFormatName = getClipboardFormatName( cf );
306 	return ( clipFormatName.equalsIgnoreAsciiCase( HTML_FORMAT_NAME_SOFFICE ) );
307 }
308 
309 //------------------------------------------------------------------------
310 //
311 //------------------------------------------------------------------------
312 
313 OUString SAL_CALL CDataFormatTranslator::getTextCharsetFromLCID( LCID lcid, CLIPFORMAT aClipformat ) const
314 {
315 	OSL_ASSERT( isOemOrAnsiTextFormat( aClipformat ) );
316 
317 	OUString charset;
318 	if ( CF_TEXT == aClipformat )
319 	{
320 		charset = getMimeCharsetFromLocaleId(
321 					lcid,
322 					LOCALE_IDEFAULTANSICODEPAGE,
323 					PRE_WINDOWS_CODEPAGE );
324 	}
325 	else if ( CF_OEMTEXT == aClipformat )
326 	{
327 		charset = getMimeCharsetFromLocaleId(
328 					lcid,
329 					LOCALE_IDEFAULTCODEPAGE,
330 					PRE_OEM_CODEPAGE );
331 	}
332 	else // CF_UNICODE
333 		OSL_ASSERT( sal_False );
334 
335 	return charset;
336 }
337