1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
21 #include "FetcList.hxx"
23 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
24 #include <com/sun/star/datatransfer/XMimeContentType.hpp>
26 #include "DataFmtTransl.hxx"
27 #include "../misc/ImplHelper.hxx"
28 #include "../misc/WinClip.hxx"
32 #include "MimeAttrib.hxx"
34 // namespace directives
36 using namespace com::sun::star::uno
;
37 using namespace com::sun::star::datatransfer
;
38 using namespace com::sun::star::lang
;
39 using namespace com::sun::star::container
;
42 LCID
CFormatRegistrar::m_TxtLocale
= 0;
43 sal_uInt32
CFormatRegistrar::m_TxtCodePage
= GetACP( );
45 CFormatEtcContainer::CFormatEtcContainer( )
47 m_EnumIterator
= m_FormatMap
.begin( );
50 void CFormatEtcContainer::addFormatEtc( const CFormatEtc
& fetc
)
52 m_FormatMap
.push_back( CFormatEtc( fetc
) );
55 void SAL_CALL
CFormatEtcContainer::removeFormatEtc( const CFormatEtc
& fetc
)
57 FormatEtcMap_t::iterator iter
=
58 find( m_FormatMap
.begin(), m_FormatMap
.end(), fetc
);
60 if ( iter
!= m_FormatMap
.end( ) )
61 m_FormatMap
.erase( iter
);
64 void SAL_CALL
CFormatEtcContainer::removeAllFormatEtc( )
69 sal_Bool
CFormatEtcContainer::hasFormatEtc( const CFormatEtc
& fetc
) const
71 FormatEtcMap_t::const_iterator iter
=
72 find( m_FormatMap
.begin(), m_FormatMap
.end(), fetc
);
74 return ( iter
!= m_FormatMap
.end( ) );
77 sal_Bool
CFormatEtcContainer::hasElements( ) const
79 return !m_FormatMap
.empty();
82 void CFormatEtcContainer::beginEnumFormatEtc( )
84 m_EnumIterator
= m_FormatMap
.begin( );
87 sal_uInt32 SAL_CALL
CFormatEtcContainer::nextFormatEtc( LPFORMATETC lpFetc
,
91 OSL_ASSERT( !IsBadWritePtr( lpFetc
, sizeof( FORMATETC
) * aNum
) );
93 sal_uInt32 nFetched
= 0;
95 for ( sal_uInt32 i
= 0; i
< aNum
; i
++, nFetched
++, lpFetc
++, ++m_EnumIterator
)
97 if ( m_EnumIterator
== m_FormatMap
.end() )
99 CopyFormatEtc( lpFetc
, *m_EnumIterator
);
105 sal_Bool SAL_CALL
CFormatEtcContainer::skipFormatEtc( sal_uInt32 aNum
)
107 FormatEtcMap_t::const_iterator iter_end
= m_FormatMap
.end( );
108 for ( sal_uInt32 i
= 0;
109 (i
< aNum
) && (m_EnumIterator
!= iter_end
);
110 i
++, ++m_EnumIterator
)
111 ;/* intentionally left empty */
113 return ( m_EnumIterator
!= m_FormatMap
.end( ) );
116 CFormatRegistrar::CFormatRegistrar( const Reference
< XComponentContext
>& rxContext
,
117 const CDataFormatTranslator
& aDataFormatTranslator
) :
118 m_DataFormatTranslator( aDataFormatTranslator
),
119 m_bHasSynthesizedLocale( sal_False
),
120 m_xContext( rxContext
)
124 // this function converts all DataFlavors of the given FlavorList into
125 // an appropriate FORMATETC structure, for some formats like unicodetext,
126 // text and text/html we will offer an accompany format e.g.:
128 // DataFlavor | Registered Clipformat | Registered accompany clipformat
129 // -------------------------|---------------------------|-----------------------------------
130 // text/plain;charset=ansi | CF_TEXT | CF_UNICODETEXT
131 // | | CF_LOCALE (if charset != GetACP()
133 // text/plain;charset=oem | CF_OEMTEXT | CF_UNICODETEXT
134 // | | CF_LOCALE (if charset != GetOEMCP()
136 // text/plain;charset=utf-16| CF_UNICODETEXT | CF_TEXT
138 // text/html | HTML (Hypertext ...) | HTML Format
141 // if some tries to register different text formats with different charsets the last
142 // registered wins and the others are ignored
144 void SAL_CALL
CFormatRegistrar::RegisterFormats(
145 const Reference
< XTransferable
>& aXTransferable
, CFormatEtcContainer
& aFormatEtcContainer
)
147 Sequence
< DataFlavor
> aFlavorList
= aXTransferable
->getTransferDataFlavors( );
148 sal_Int32 nFlavors
= aFlavorList
.getLength( );
149 sal_Bool bUnicodeRegistered
= sal_False
;
152 for( sal_Int32 i
= 0; i
< nFlavors
; i
++ )
154 aFlavor
= aFlavorList
[i
];
155 CFormatEtc fetc
= m_DataFormatTranslator
.getFormatEtcFromDataFlavor( aFlavor
);
157 // maybe an internal format so we ignore it
158 if ( CF_INVALID
== fetc
.getClipformat( ) )
161 if ( !needsToSynthesizeAccompanyFormats( fetc
) )
162 aFormatEtcContainer
.addFormatEtc( fetc
);
165 // if we haven't registered any text format up to now
166 if ( m_DataFormatTranslator
.isTextFormat( fetc
.getClipformat() ) && !bUnicodeRegistered
)
168 // if the transferable supports unicode text we ignore
169 // any further text format the transferable offers
170 // because we can create it from Unicode text in addition
171 // we register CF_TEXT for non unicode clients
172 if ( m_DataFormatTranslator
.isUnicodeTextFormat( fetc
.getClipformat() ) )
174 aFormatEtcContainer
.addFormatEtc( fetc
); // add CF_UNICODE
175 aFormatEtcContainer
.addFormatEtc(
176 m_DataFormatTranslator
.getFormatEtcForClipformat( CF_TEXT
) ); // add CF_TEXT
177 bUnicodeRegistered
= sal_True
;
179 else if ( !hasUnicodeFlavor( aXTransferable
) )
181 // we try to investigate the charset and make a valid
182 // windows codepage from this charset the default
183 // return value is the result of GetACP( )
184 OUString charset
= getCharsetFromDataFlavor( aFlavor
);
185 sal_uInt32 txtCP
= getWinCPFromMimeCharset( charset
);
187 // we try to get a Locale appropriate for this codepage
188 if ( findLocaleForTextCodePage( ) )
190 m_TxtCodePage
= txtCP
;
192 aFormatEtcContainer
.addFormatEtc(
193 m_DataFormatTranslator
.getFormatEtcForClipformat( CF_UNICODETEXT
) );
195 if ( !IsOEMCP( m_TxtCodePage
) )
196 aFormatEtcContainer
.addFormatEtc(
197 m_DataFormatTranslator
.getFormatEtcForClipformat( CF_TEXT
) );
199 aFormatEtcContainer
.addFormatEtc(
200 m_DataFormatTranslator
.getFormatEtcForClipformat( CF_OEMTEXT
) );
202 aFormatEtcContainer
.addFormatEtc(
203 m_DataFormatTranslator
.getFormatEtcForClipformat( CF_LOCALE
) );
205 // we save the flavor so it's easier when
206 // queried for it in XTDataObject::GetData(...)
207 m_RegisteredTextFlavor
= aFlavor
;
208 m_bHasSynthesizedLocale
= sal_True
;
212 else if ( m_DataFormatTranslator
.isTextHtmlFormat( fetc
.getClipformat( ) ) ) // Html (Hyper Text...)
214 // we add text/html ( HTML (HyperText Markup Language) )
215 aFormatEtcContainer
.addFormatEtc( fetc
);
218 OUString
htmlFormat( "HTML Format" );
219 aFormatEtcContainer
.addFormatEtc(
220 m_DataFormatTranslator
.getFormatEtcForClipformatName( htmlFormat
) );
226 sal_Bool SAL_CALL
CFormatRegistrar::hasSynthesizedLocale( ) const
228 return m_bHasSynthesizedLocale
;
231 LCID SAL_CALL
CFormatRegistrar::getSynthesizedLocale( ) const
236 sal_uInt32 SAL_CALL
CFormatRegistrar::getRegisteredTextCodePage( ) const
238 return m_TxtCodePage
;
241 DataFlavor SAL_CALL
CFormatRegistrar::getRegisteredTextFlavor( ) const
243 return m_RegisteredTextFlavor
;
246 sal_Bool SAL_CALL
CFormatRegistrar::isSynthesizeableFormat( const CFormatEtc
& aFormatEtc
) const
248 return ( m_DataFormatTranslator
.isOemOrAnsiTextFormat( aFormatEtc
.getClipformat() ) ||
249 m_DataFormatTranslator
.isUnicodeTextFormat( aFormatEtc
.getClipformat() ) ||
250 m_DataFormatTranslator
.isHTMLFormat( aFormatEtc
.getClipformat() ) );
254 sal_Bool SAL_CALL
CFormatRegistrar::needsToSynthesizeAccompanyFormats( const CFormatEtc
& aFormatEtc
) const
256 return ( m_DataFormatTranslator
.isOemOrAnsiTextFormat( aFormatEtc
.getClipformat() ) ||
257 m_DataFormatTranslator
.isUnicodeTextFormat( aFormatEtc
.getClipformat() ) ||
258 m_DataFormatTranslator
.isTextHtmlFormat( aFormatEtc
.getClipformat( ) ) );
261 OUString SAL_CALL
CFormatRegistrar::getCharsetFromDataFlavor( const DataFlavor
& aFlavor
)
267 Reference
< XMimeContentTypeFactory
> xMimeFac
=
268 MimeContentTypeFactory::create(m_xContext
);
270 Reference
< XMimeContentType
> xMimeType( xMimeFac
->createMimeContentType( aFlavor
.MimeType
) );
271 if ( xMimeType
->hasParameter( TEXTPLAIN_PARAM_CHARSET
) )
272 charset
= xMimeType
->getParameterValue( TEXTPLAIN_PARAM_CHARSET
);
274 charset
= getMimeCharsetFromWinCP( GetACP( ), PRE_WINDOWS_CODEPAGE
);
276 catch(NoSuchElementException
&)
278 OSL_FAIL( "Unexpected" );
282 OSL_FAIL( "Invalid data flavor" );
288 sal_Bool SAL_CALL
CFormatRegistrar::hasUnicodeFlavor( const Reference
< XTransferable
>& aXTransferable
) const
290 CFormatEtc
fetc( CF_UNICODETEXT
);
293 m_DataFormatTranslator
.getDataFlavorFromFormatEtc( fetc
);
295 return aXTransferable
->isDataFlavorSupported( aFlavor
);
299 sal_Bool
CFormatRegistrar::isEqualCurrentSystemCodePage( sal_uInt32 aCodePage
) const
301 return ( (aCodePage
== GetOEMCP()) || (aCodePage
== GetACP()) );
304 sal_Bool SAL_CALL
CFormatRegistrar::findLocaleForTextCodePage( )
307 EnumSystemLocalesA( CFormatRegistrar::EnumLocalesProc
, LCID_INSTALLED
);
308 return ( IsValidLocale( m_TxtLocale
, LCID_INSTALLED
) ) ? sal_True
: sal_False
;
311 sal_Bool SAL_CALL
CFormatRegistrar::isLocaleCodePage( LCID lcid
, LCTYPE lctype
, sal_uInt32 codepage
)
314 sal_uInt32 localeCodePage
;
316 OSL_ASSERT( IsValidLocale( lcid
, LCID_INSTALLED
) );
318 // get the ansi codepage of the current locale
319 GetLocaleInfoA( lcid
, lctype
, buff
, sizeof( buff
) );
320 localeCodePage
= atol( buff
);
322 return ( localeCodePage
== codepage
);
326 sal_Bool SAL_CALL
CFormatRegistrar::isLocaleOemCodePage( LCID lcid
, sal_uInt32 codepage
)
328 return isLocaleCodePage( lcid
, LOCALE_IDEFAULTCODEPAGE
, codepage
);
332 sal_Bool SAL_CALL
CFormatRegistrar::isLocaleAnsiCodePage( LCID lcid
, sal_uInt32 codepage
)
334 return isLocaleCodePage( lcid
, LOCALE_IDEFAULTANSICODEPAGE
, codepage
);
337 BOOL CALLBACK
CFormatRegistrar::EnumLocalesProc( LPSTR lpLocaleStr
)
339 // the lpLocaleStr parametere is hexadecimal
340 LCID lcid
= strtol( lpLocaleStr
, NULL
, 16 );
342 if ( isLocaleAnsiCodePage( lcid
, CFormatRegistrar::m_TxtCodePage
) ||
343 isLocaleOemCodePage( lcid
, CFormatRegistrar::m_TxtCodePage
) )
345 CFormatRegistrar::m_TxtLocale
= lcid
;
346 return sal_False
; // stop enumerating
352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */