blob: a543586e70054a84db6a10ff6488ce68ae381d9e [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dtrans.hxx"
//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------
#include <osl/diagnose.h>
#include "FetcList.hxx"
#include "Fetc.hxx"
#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
#include <com/sun/star/datatransfer/XMimeContentType.hpp>
#ifndef _DATAFORMATTRANSLATOR_HXX_
#include "DataFmtTransl.hxx"
#endif
#include "..\misc\ImplHelper.hxx"
#include "..\misc\WinClip.hxx"
#include <algorithm>
#include "MimeAttrib.hxx"
//------------------------------------------------------------------------
// namespace directives
//------------------------------------------------------------------------
using namespace com::sun::star::uno;
using namespace com::sun::star::datatransfer;
using namespace com::sun::star::lang;
using namespace com::sun::star::container;
using namespace rtl;
using namespace std;
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
LCID CFormatRegistrar::m_TxtLocale = 0;
sal_uInt32 CFormatRegistrar::m_TxtCodePage = GetACP( );
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
CFormatEtcContainer::CFormatEtcContainer( )
{
m_EnumIterator = m_FormatMap.begin( );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
void CFormatEtcContainer::addFormatEtc( const CFormatEtc& fetc )
{
m_FormatMap.push_back( CFormatEtc( fetc ) );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
void SAL_CALL CFormatEtcContainer::removeFormatEtc( const CFormatEtc& fetc )
{
FormatEtcMap_t::iterator iter =
find( m_FormatMap.begin(), m_FormatMap.end(), fetc );
if ( iter != m_FormatMap.end( ) )
m_FormatMap.erase( iter );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
void SAL_CALL CFormatEtcContainer::removeAllFormatEtc( )
{
m_FormatMap.clear( );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_Bool CFormatEtcContainer::hasFormatEtc( const CFormatEtc& fetc ) const
{
FormatEtcMap_t::const_iterator iter =
find( m_FormatMap.begin(), m_FormatMap.end(), fetc );
return ( iter != m_FormatMap.end( ) );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_Bool CFormatEtcContainer::hasElements( ) const
{
return ( m_FormatMap.size( ) > 0 );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
void CFormatEtcContainer::beginEnumFormatEtc( )
{
m_EnumIterator = m_FormatMap.begin( );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_uInt32 SAL_CALL CFormatEtcContainer::nextFormatEtc( LPFORMATETC lpFetc,
sal_uInt32 aNum )
{
OSL_ASSERT( lpFetc );
OSL_ASSERT( !IsBadWritePtr( lpFetc, sizeof( FORMATETC ) * aNum ) );
sal_uInt32 nFetched = 0;
for ( sal_uInt32 i = 0; i < aNum; i++, nFetched++, lpFetc++, ++m_EnumIterator )
{
if ( m_EnumIterator == m_FormatMap.end() )
break;
CopyFormatEtc( lpFetc, *m_EnumIterator );
}
return nFetched;
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_Bool SAL_CALL CFormatEtcContainer::skipFormatEtc( sal_uInt32 aNum )
{
FormatEtcMap_t::const_iterator iter_end = m_FormatMap.end( );
for ( sal_uInt32 i = 0;
(i < aNum) && (m_EnumIterator != iter_end);
i++, ++m_EnumIterator )
;/* intentionally left empty */
return ( m_EnumIterator != m_FormatMap.end( ) );
}
//#########################################################################
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
CFormatRegistrar::CFormatRegistrar( const Reference< XMultiServiceFactory >& ServiceManager,
const CDataFormatTranslator& aDataFormatTranslator ) :
m_DataFormatTranslator( aDataFormatTranslator ),
m_bHasSynthesizedLocale( sal_False ),
m_SrvMgr( ServiceManager )
{
}
// ----------------------------------------------------------------------------------------
// this function converts all DataFlavors of the given FlavorList into
// an appropriate FORMATETC structure, for some formats like unicodetext,
// text and text/html we will offer an accompany format e.g.:
//
// DataFlavor | Registered Clipformat | Registered accompany clipformat
// -------------------------|---------------------------|-----------------------------------
// text/plain;charset=ansi | CF_TEXT | CF_UNICODETEXT
// | | CF_LOCALE (if charset != GetACP()
// | |
// text/plain;charset=oem | CF_OEMTEXT | CF_UNICODETEXT
// | | CF_LOCALE (if charset != GetOEMCP()
// | |
// text/plain;charset=utf-16| CF_UNICODETEXT | CF_TEXT
// | |
// text/html | HTML (Hypertext ...) | HTML Format
// | |
//
// if some tries to register different text formats with different charsets the last
// registered wins and the others are ignored
// ----------------------------------------------------------------------------------------
void SAL_CALL CFormatRegistrar::RegisterFormats(
const Reference< XTransferable >& aXTransferable, CFormatEtcContainer& aFormatEtcContainer )
{
Sequence< DataFlavor > aFlavorList = aXTransferable->getTransferDataFlavors( );
sal_Int32 nFlavors = aFlavorList.getLength( );
sal_Bool bUnicodeRegistered = sal_False;
DataFlavor aFlavor;
for( sal_Int32 i = 0; i < nFlavors; i++ )
{
aFlavor = aFlavorList[i];
CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
// maybe an internal format so we ignore it
if ( CF_INVALID == fetc.getClipformat( ) )
continue;
if ( !needsToSynthesizeAccompanyFormats( fetc ) )
aFormatEtcContainer.addFormatEtc( fetc );
else
{
// if we haven't registered any text format up to now
if ( m_DataFormatTranslator.isTextFormat( fetc.getClipformat() ) && !bUnicodeRegistered )
{
// if the transferable supports unicode text we ignore
// any further text format the transferable offers
// because we can create it from Unicode text in addition
// we register CF_TEXT for non unicode clients
if ( m_DataFormatTranslator.isUnicodeTextFormat( fetc.getClipformat() ) )
{
aFormatEtcContainer.addFormatEtc( fetc ); // add CF_UNICODE
aFormatEtcContainer.addFormatEtc(
m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT ) ); // add CF_TEXT
bUnicodeRegistered = sal_True;
}
else if ( !hasUnicodeFlavor( aXTransferable ) )
{
// we try to investigate the charset and make a valid
// windows codepage from this charset the default
// return value is the result of GetACP( )
OUString charset = getCharsetFromDataFlavor( aFlavor );
sal_uInt32 txtCP = getWinCPFromMimeCharset( charset );
// we try to get a Locale appropriate for this codepage
if ( findLocaleForTextCodePage( ) )
{
m_TxtCodePage = txtCP;
aFormatEtcContainer.addFormatEtc(
m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) );
if ( !IsOEMCP( m_TxtCodePage ) )
aFormatEtcContainer.addFormatEtc(
m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT ) );
else
aFormatEtcContainer.addFormatEtc(
m_DataFormatTranslator.getFormatEtcForClipformat( CF_OEMTEXT ) );
aFormatEtcContainer.addFormatEtc(
m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE ) );
// we save the flavor so it's easier when
// queried for it in XTDataObject::GetData(...)
m_RegisteredTextFlavor = aFlavor;
m_bHasSynthesizedLocale = sal_True;
}
}
}
else if ( m_DataFormatTranslator.isTextHtmlFormat( fetc.getClipformat( ) ) ) // Html (Hyper Text...)
{
// we add text/html ( HTML (HyperText Markup Language) )
aFormatEtcContainer.addFormatEtc( fetc );
// and HTML Format
OUString htmlFormat( OUString::createFromAscii( "HTML Format" ) );
aFormatEtcContainer.addFormatEtc(
m_DataFormatTranslator.getFormatEtcForClipformatName( htmlFormat ) );
}
}
}
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_Bool SAL_CALL CFormatRegistrar::hasSynthesizedLocale( ) const
{
return m_bHasSynthesizedLocale;
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
LCID SAL_CALL CFormatRegistrar::getSynthesizedLocale( ) const
{
return m_TxtLocale;
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_uInt32 SAL_CALL CFormatRegistrar::getRegisteredTextCodePage( ) const
{
return m_TxtCodePage;
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
DataFlavor SAL_CALL CFormatRegistrar::getRegisteredTextFlavor( ) const
{
return m_RegisteredTextFlavor;
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_Bool SAL_CALL CFormatRegistrar::isSynthesizeableFormat( const CFormatEtc& aFormatEtc ) const
{
return ( m_DataFormatTranslator.isOemOrAnsiTextFormat( aFormatEtc.getClipformat() ) ||
m_DataFormatTranslator.isUnicodeTextFormat( aFormatEtc.getClipformat() ) ||
m_DataFormatTranslator.isHTMLFormat( aFormatEtc.getClipformat() ) );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
inline
sal_Bool SAL_CALL CFormatRegistrar::needsToSynthesizeAccompanyFormats( const CFormatEtc& aFormatEtc ) const
{
return ( m_DataFormatTranslator.isOemOrAnsiTextFormat( aFormatEtc.getClipformat() ) ||
m_DataFormatTranslator.isUnicodeTextFormat( aFormatEtc.getClipformat() ) ||
m_DataFormatTranslator.isTextHtmlFormat( aFormatEtc.getClipformat( ) ) );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
OUString SAL_CALL CFormatRegistrar::getCharsetFromDataFlavor( const DataFlavor& aFlavor )
{
OUString charset;
try
{
Reference< XMimeContentTypeFactory > xMimeFac(
m_SrvMgr->createInstance( OUString::createFromAscii( \
"com.sun.star.datatransfer.MimeContentTypeFactory" ) ), UNO_QUERY );
if( xMimeFac.is( ) )
{
Reference< XMimeContentType > xMimeType( xMimeFac->createMimeContentType( aFlavor.MimeType ) );
if ( xMimeType->hasParameter( TEXTPLAIN_PARAM_CHARSET ) )
charset = xMimeType->getParameterValue( TEXTPLAIN_PARAM_CHARSET );
else
charset = getMimeCharsetFromWinCP( GetACP( ), PRE_WINDOWS_CODEPAGE );
}
}
catch(NoSuchElementException&)
{
OSL_ENSURE( sal_False, "Unexpected" );
}
catch(...)
{
OSL_ENSURE( sal_False, "Invalid data flavor" );
}
return charset;
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_Bool SAL_CALL CFormatRegistrar::hasUnicodeFlavor( const Reference< XTransferable >& aXTransferable ) const
{
CFormatEtc fetc( CF_UNICODETEXT );
DataFlavor aFlavor =
m_DataFormatTranslator.getDataFlavorFromFormatEtc( fetc );
return aXTransferable->isDataFlavorSupported( aFlavor );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
inline
sal_Bool CFormatRegistrar::isEqualCurrentSystemCodePage( sal_uInt32 aCodePage ) const
{
return ( (aCodePage == GetOEMCP()) || (aCodePage == GetACP()) );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_Bool SAL_CALL CFormatRegistrar::findLocaleForTextCodePage( )
{
m_TxtLocale = 0;
EnumSystemLocalesA( CFormatRegistrar::EnumLocalesProc, LCID_INSTALLED );
return ( IsValidLocale( m_TxtLocale, LCID_INSTALLED ) ) ? sal_True : sal_False;
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
sal_Bool SAL_CALL CFormatRegistrar::isLocaleCodePage( LCID lcid, LCTYPE lctype, sal_uInt32 codepage )
{
char buff[6];
sal_uInt32 localeCodePage;
OSL_ASSERT( IsValidLocale( lcid, LCID_INSTALLED ) );
// get the ansi codepage of the current locale
GetLocaleInfoA( lcid, lctype, buff, sizeof( buff ) );
localeCodePage = atol( buff );
return ( localeCodePage == codepage );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
inline
sal_Bool SAL_CALL CFormatRegistrar::isLocaleOemCodePage( LCID lcid, sal_uInt32 codepage )
{
return isLocaleCodePage( lcid, LOCALE_IDEFAULTCODEPAGE, codepage );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
inline
sal_Bool SAL_CALL CFormatRegistrar::isLocaleAnsiCodePage( LCID lcid, sal_uInt32 codepage )
{
return isLocaleCodePage( lcid, LOCALE_IDEFAULTANSICODEPAGE, codepage );
}
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
BOOL CALLBACK CFormatRegistrar::EnumLocalesProc( LPSTR lpLocaleStr )
{
// the lpLocaleStr parametere is hexadecimal
LCID lcid = strtol( lpLocaleStr, NULL, 16 );
if ( isLocaleAnsiCodePage( lcid, CFormatRegistrar::m_TxtCodePage ) ||
isLocaleOemCodePage( lcid, CFormatRegistrar::m_TxtCodePage ) )
{
CFormatRegistrar::m_TxtLocale = lcid;
return sal_False; // stop enumerating
}
return sal_True;
}