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/container/NoSuchElementException.hpp>
24 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
25 #include <com/sun/star/datatransfer/XMimeContentType.hpp>
27 #include "DataFmtTransl.hxx"
28 #include "ImplHelper.hxx"
29 #include "WinClip.hxx"
33 #include "MimeAttrib.hxx"
35 using namespace com::sun::star::uno
;
36 using namespace com::sun::star::datatransfer
;
37 using namespace com::sun::star::lang
;
38 using namespace com::sun::star::container
;
40 LCID
CFormatRegistrar::m_TxtLocale
= 0;
41 sal_uInt32
CFormatRegistrar::m_TxtCodePage
= GetACP( );
43 CFormatEtcContainer::CFormatEtcContainer( )
45 m_EnumIterator
= m_FormatMap
.begin( );
48 void CFormatEtcContainer::addFormatEtc( const CFormatEtc
& fetc
)
50 m_FormatMap
.push_back( fetc
);
53 void CFormatEtcContainer::removeFormatEtc( const CFormatEtc
& fetc
)
55 FormatEtcMap_t::iterator iter
=
56 find( m_FormatMap
.begin(), m_FormatMap
.end(), fetc
);
58 if ( iter
!= m_FormatMap
.end( ) )
59 m_FormatMap
.erase( iter
);
62 void CFormatEtcContainer::removeAllFormatEtc( )
67 bool CFormatEtcContainer::hasFormatEtc( const CFormatEtc
& fetc
) const
69 FormatEtcMap_t::const_iterator iter
=
70 find( m_FormatMap
.begin(), m_FormatMap
.end(), fetc
);
72 return ( iter
!= m_FormatMap
.end( ) );
75 bool CFormatEtcContainer::hasElements( ) const
77 return !m_FormatMap
.empty();
80 void CFormatEtcContainer::beginEnumFormatEtc( )
82 m_EnumIterator
= m_FormatMap
.begin( );
85 sal_uInt32
CFormatEtcContainer::nextFormatEtc( LPFORMATETC lpFetc
,
89 OSL_ASSERT( !IsBadWritePtr( lpFetc
, sizeof( FORMATETC
) * aNum
) );
91 sal_uInt32 nFetched
= 0;
93 for ( sal_uInt32 i
= 0; i
< aNum
; i
++, nFetched
++, lpFetc
++, ++m_EnumIterator
)
95 if ( m_EnumIterator
== m_FormatMap
.end() )
97 CopyFormatEtc( lpFetc
, *m_EnumIterator
);
103 bool CFormatEtcContainer::skipFormatEtc( sal_uInt32 aNum
)
105 FormatEtcMap_t::const_iterator iter_end
= m_FormatMap
.end( );
106 for ( sal_uInt32 i
= 0;
107 (i
< aNum
) && (m_EnumIterator
!= iter_end
);
108 i
++, ++m_EnumIterator
)
109 ;/* intentionally left empty */
111 return ( m_EnumIterator
!= m_FormatMap
.end( ) );
114 CFormatRegistrar::CFormatRegistrar( const Reference
< XComponentContext
>& rxContext
,
115 const CDataFormatTranslator
& aDataFormatTranslator
) :
116 m_DataFormatTranslator( aDataFormatTranslator
),
117 m_bHasSynthesizedLocale( false ),
118 m_xContext( rxContext
)
122 // this function converts all DataFlavors of the given FlavorList into
123 // an appropriate FORMATETC structure, for some formats like unicodetext,
124 // text and text/html we will offer an accompany format e.g.:
126 // DataFlavor | Registered Clipformat | Registered accompany clipformat
127 // -------------------------|---------------------------|-----------------------------------
128 // text/plain;charset=ansi | CF_TEXT | CF_UNICODETEXT
129 // | | CF_LOCALE (if charset != GetACP()
131 // text/plain;charset=oem | CF_OEMTEXT | CF_UNICODETEXT
132 // | | CF_LOCALE (if charset != GetOEMCP()
134 // text/plain;charset=utf-16| CF_UNICODETEXT | CF_TEXT
136 // text/html | HTML (Hypertext ...) | HTML Format
139 // if some tries to register different text formats with different charsets the last
140 // registered wins and the others are ignored
142 void CFormatRegistrar::RegisterFormats(
143 const Reference
< XTransferable
>& aXTransferable
, CFormatEtcContainer
& aFormatEtcContainer
)
145 Sequence
< DataFlavor
> aFlavorList
= aXTransferable
->getTransferDataFlavors( );
146 sal_Int32 nFlavors
= aFlavorList
.getLength( );
147 bool bUnicodeRegistered
= false;
150 for( sal_Int32 i
= 0; i
< nFlavors
; i
++ )
152 aFlavor
= aFlavorList
[i
];
153 CFormatEtc fetc
= m_DataFormatTranslator
.getFormatEtcFromDataFlavor( aFlavor
);
155 // maybe an internal format so we ignore it
156 if ( CF_INVALID
== fetc
.getClipformat( ) )
159 if ( !needsToSynthesizeAccompanyFormats( fetc
) )
160 aFormatEtcContainer
.addFormatEtc( fetc
);
163 // if we haven't registered any text format up to now
164 if ( CDataFormatTranslator::isTextFormat( fetc
.getClipformat() ) && !bUnicodeRegistered
)
166 // if the transferable supports unicode text we ignore
167 // any further text format the transferable offers
168 // because we can create it from Unicode text in addition
169 // we register CF_TEXT for non unicode clients
170 if ( CDataFormatTranslator::isUnicodeTextFormat( fetc
.getClipformat() ) )
172 aFormatEtcContainer
.addFormatEtc( fetc
); // add CF_UNICODE
173 aFormatEtcContainer
.addFormatEtc(
174 CDataFormatTranslator::getFormatEtcForClipformat( CF_TEXT
) ); // add CF_TEXT
175 bUnicodeRegistered
= true;
177 else if ( !hasUnicodeFlavor( aXTransferable
) )
179 // we try to investigate the charset and make a valid
180 // windows codepage from this charset the default
181 // return value is the result of GetACP( )
182 OUString charset
= getCharsetFromDataFlavor( aFlavor
);
183 sal_uInt32 txtCP
= getWinCPFromMimeCharset( charset
);
185 // we try to get a Locale appropriate for this codepage
186 if ( findLocaleForTextCodePage( ) )
188 m_TxtCodePage
= txtCP
;
190 aFormatEtcContainer
.addFormatEtc(
191 CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT
) );
193 if ( !IsOEMCP( m_TxtCodePage
) )
194 aFormatEtcContainer
.addFormatEtc(
195 CDataFormatTranslator::getFormatEtcForClipformat( CF_TEXT
) );
197 aFormatEtcContainer
.addFormatEtc(
198 CDataFormatTranslator::getFormatEtcForClipformat( CF_OEMTEXT
) );
200 aFormatEtcContainer
.addFormatEtc(
201 CDataFormatTranslator::getFormatEtcForClipformat( CF_LOCALE
) );
203 // we save the flavor so it's easier when
204 // queried for it in XTDataObject::GetData(...)
205 m_RegisteredTextFlavor
= aFlavor
;
206 m_bHasSynthesizedLocale
= true;
210 else if ( CDataFormatTranslator::isTextHtmlFormat( fetc
.getClipformat( ) ) ) // Html (Hyper Text...)
212 // we add text/html ( HTML (HyperText Markup Language) )
213 aFormatEtcContainer
.addFormatEtc( fetc
);
216 aFormatEtcContainer
.addFormatEtc(
217 CDataFormatTranslator::getFormatEtcForClipformatName( "HTML Format" ) );
223 bool CFormatRegistrar::hasSynthesizedLocale( ) const
225 return m_bHasSynthesizedLocale
;
228 LCID
CFormatRegistrar::getSynthesizedLocale( )
233 sal_uInt32
CFormatRegistrar::getRegisteredTextCodePage( )
235 return m_TxtCodePage
;
238 DataFlavor
CFormatRegistrar::getRegisteredTextFlavor( ) const
240 return m_RegisteredTextFlavor
;
243 bool CFormatRegistrar::isSynthesizeableFormat( const CFormatEtc
& aFormatEtc
)
245 return ( CDataFormatTranslator::isOemOrAnsiTextFormat( aFormatEtc
.getClipformat() ) ||
246 CDataFormatTranslator::isUnicodeTextFormat( aFormatEtc
.getClipformat() ) ||
247 CDataFormatTranslator::isHTMLFormat( aFormatEtc
.getClipformat() ) );
251 bool CFormatRegistrar::needsToSynthesizeAccompanyFormats( const CFormatEtc
& aFormatEtc
)
253 return ( CDataFormatTranslator::isOemOrAnsiTextFormat( aFormatEtc
.getClipformat() ) ||
254 CDataFormatTranslator::isUnicodeTextFormat( aFormatEtc
.getClipformat() ) ||
255 CDataFormatTranslator::isTextHtmlFormat( aFormatEtc
.getClipformat( ) ) );
258 OUString
CFormatRegistrar::getCharsetFromDataFlavor( const DataFlavor
& aFlavor
)
264 Reference
< XMimeContentTypeFactory
> xMimeFac
=
265 MimeContentTypeFactory::create(m_xContext
);
267 Reference
< XMimeContentType
> xMimeType( xMimeFac
->createMimeContentType( aFlavor
.MimeType
) );
268 if ( xMimeType
->hasParameter( TEXTPLAIN_PARAM_CHARSET
) )
269 charset
= xMimeType
->getParameterValue( TEXTPLAIN_PARAM_CHARSET
);
271 charset
= getMimeCharsetFromWinCP( GetACP( ), PRE_WINDOWS_CODEPAGE
);
273 catch(NoSuchElementException
&)
275 OSL_FAIL( "Unexpected" );
279 OSL_FAIL( "Invalid data flavor" );
285 bool CFormatRegistrar::hasUnicodeFlavor( const Reference
< XTransferable
>& aXTransferable
) const
287 DataFlavor aFlavor
= m_DataFormatTranslator
.getDataFlavorFromFormatEtc(CF_UNICODETEXT
);
289 return aXTransferable
->isDataFlavorSupported( aFlavor
);
292 bool CFormatRegistrar::findLocaleForTextCodePage( )
295 EnumSystemLocalesA( CFormatRegistrar::EnumLocalesProc
, LCID_INSTALLED
);
296 return IsValidLocale( m_TxtLocale
, LCID_INSTALLED
);
299 bool CFormatRegistrar::isLocaleCodePage( LCID lcid
, LCTYPE lctype
, sal_uInt32 codepage
)
302 sal_uInt32 localeCodePage
;
304 OSL_ASSERT( IsValidLocale( lcid
, LCID_INSTALLED
) );
306 // get the ansi codepage of the current locale
307 GetLocaleInfoA( lcid
, lctype
, buff
, sizeof( buff
) );
308 localeCodePage
= atol( buff
);
310 return ( localeCodePage
== codepage
);
314 bool CFormatRegistrar::isLocaleOemCodePage( LCID lcid
, sal_uInt32 codepage
)
316 return isLocaleCodePage( lcid
, LOCALE_IDEFAULTCODEPAGE
, codepage
);
320 bool CFormatRegistrar::isLocaleAnsiCodePage( LCID lcid
, sal_uInt32 codepage
)
322 return isLocaleCodePage( lcid
, LOCALE_IDEFAULTANSICODEPAGE
, codepage
);
325 BOOL CALLBACK
CFormatRegistrar::EnumLocalesProc( LPSTR lpLocaleStr
)
327 // the lpLocaleStr parameter is hexadecimal
328 LCID lcid
= strtol( lpLocaleStr
, nullptr, 16 );
330 if ( isLocaleAnsiCodePage( lcid
, CFormatRegistrar::m_TxtCodePage
) ||
331 isLocaleOemCodePage( lcid
, CFormatRegistrar::m_TxtCodePage
) )
333 CFormatRegistrar::m_TxtLocale
= lcid
;
334 return false; // stop enumerating
340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */