From 9d2703c376d2ee7501ed78be8c962203fbfd098f Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Mon, 25 Mar 2013 12:32:48 +0100 Subject: Added support for charset conversion with ICU (thanks to Mehmet Bozkurt). --- AUTHORS | 2 +- CMakeLists.txt | 75 +++++- SConstruct | 15 ++ cmake/FindICU.cmake | 314 +++++++++++++++++++++++ cmake/config.hpp.cmake | 4 + src/charsetConverter.cpp | 3 +- src/charsetConverter_iconv.cpp | 18 ++ src/charsetConverter_icu.cpp | 202 +++++++++++++++ tests/parser/charsetFilteredOutputStreamTest.cpp | 10 + tests/parser/charsetTest.cpp | 3 +- vmime/charsetConverter.hpp | 6 + vmime/charsetConverter_iconv.hpp | 8 + vmime/charsetConverter_icu.hpp | 84 ++++++ 13 files changed, 727 insertions(+), 17 deletions(-) create mode 100644 cmake/FindICU.cmake create mode 100755 src/charsetConverter_icu.cpp create mode 100755 vmime/charsetConverter_icu.hpp diff --git a/AUTHORS b/AUTHORS index 98406a08..42b43b4b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,7 +28,7 @@ AUTHORS file. - Zarafa - Bartek Szurgot - Achim Brandt - - Mehmet Bozkurt (OpenSSL support) + - Mehmet Bozkurt (OpenSSL support, ICU support) Please apologize if I have forgotten someone here. ;) Send me an email to if you want your name to be listed. diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f246d74..6809e7c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ # http://www.cmake.org # -CMAKE_MINIMUM_REQUIRED(VERSION 2.6 FATAL_ERROR) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3 FATAL_ERROR) INCLUDE(cmake/Utils.cmake) @@ -623,25 +623,74 @@ ENDIF(VMIME_HAVE_TLS_SUPPORT) ############################################################################## -# iconv +# Charset conversion library INCLUDE(cmake/FindIconv.cmake) +INCLUDE(cmake/FindICU.cmake) -INCLUDE_DIRECTORIES( - ${INCLUDE_DIRECTORIES} - ${ICONV_INCLUDE_DIR} +FIND_PACKAGE(ICU QUIET) + +IF(ICONV_FOUND) + SET(VMIME_CHARSETCONV_LIB_IS_ICONV_DEFAULT "ON") + SET(VMIME_CHARSETCONV_LIB_IS_ICU_DEFAULT "OFF") +ELSEIF(ICU_LIBRARIES) + SET(VMIME_CHARSETCONV_LIB_IS_ICONV_DEFAULT "OFF") + SET(VMIME_CHARSETCONV_LIB_IS_ICU_DEFAULT "ON") +ENDIF() + +OPTION( + VMIME_CHARSETCONV_LIB_IS_ICONV + "Use iconv library for charset conversion" + ${VMIME_CHARSETCONV_LIB_IS_ICONV_DEFAULT} ) -IF(VMIME_BUILD_SHARED_LIBRARY) - TARGET_LINK_LIBRARIES( - ${VMIME_LIBRARY_NAME} - ${TARGET_LINK_LIBRARIES} - ${ICONV_LIBRARIES} +OPTION( + VMIME_CHARSETCONV_LIB_IS_ICU + "Use ICU library for charset conversion" + ${VMIME_CHARSETCONV_LIB_IS_ICU_DEFAULT} +) + +IF(VMIME_CHARSETCONV_LIB_IS_ICONV) + + INCLUDE_DIRECTORIES( + ${INCLUDE_DIRECTORIES} + ${ICONV_INCLUDE_DIR} ) -ENDIF() -SET(VMIME_PKGCONFIG_LIBS "${VMIME_PKGCONFIG_LIBS} ${ICONV_LIBRARIES}") -SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} -I${ICONV_INCLUDE_DIR}") + IF(VMIME_BUILD_SHARED_LIBRARY) + TARGET_LINK_LIBRARIES( + ${VMIME_LIBRARY_NAME} + ${TARGET_LINK_LIBRARIES} + ${ICONV_LIBRARIES} + ) + ENDIF() + + SET(VMIME_PKGCONFIG_LIBS "${VMIME_PKGCONFIG_LIBS} ${ICONV_LIBRARIES}") + SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} -I${ICONV_INCLUDE_DIR}") + +ELSEIF(VMIME_CHARSETCONV_LIB_IS_ICU) + + INCLUDE_DIRECTORIES( + ${INCLUDE_DIRECTORIES} + ${ICU_INCLUDE_DIRS} + ) + + IF(VMIME_BUILD_SHARED_LIBRARY) + TARGET_LINK_LIBRARIES( + ${VMIME_LIBRARY_NAME} + ${TARGET_LINK_LIBRARIES} + ${ICU_LIBRARIES} + ) + ENDIF() + + SET(VMIME_PKGCONFIG_LIBS "${VMIME_PKGCONFIG_LIBS} ${ICU_LIBRARIES}") + SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} -I${ICU_INCLUDE_DIRS}") + +ELSE() + + MESSAGE(FATAL_ERROR "No charset conversion library was selected/found") + +ENDIF() ############################################################################## diff --git a/SConstruct b/SConstruct index 60ee5159..eed044f7 100644 --- a/SConstruct +++ b/SConstruct @@ -57,6 +57,7 @@ libvmime_sources = [ 'charset.cpp', 'charset.hpp', 'charsetConverter.cpp', 'charsetConverter.hpp', 'charsetConverter_iconv.cpp', 'charsetConverter_iconv.hpp', + 'charsetConverter_icu.cpp', 'charsetConverter_icu.hpp', 'charsetConverter_idna.cpp', 'charsetConverter_idna.hpp', 'charsetConverterOptions.cpp', 'charsetConverterOptions.hpp', 'component.cpp', 'component.hpp', @@ -673,6 +674,15 @@ if env['with_tls'] == 'yes': env.Append(CXXFLAGS = ['-pthread']) +# Charset conversion library + +# -- iconv +if sys.platform == "mac" or sys.platform == "darwin": + env.Append(LIBS = ['iconv', 'gcrypt']) + +# -- ICU +env.Append(LIBS = ['icuuc', 'icudata', 'icui18n']) + # Generate help text for command line options Help(opts.GenerateHelpText(env)) @@ -836,6 +846,11 @@ config_hpp.write('\n') config_hpp.write('#define VMIME_HAVE_SIZE_T 1\n') config_hpp.write('\n') +config_hpp.write('// Charset conversion support\n') +config_hpp.write('#define VMIME_CHARSETCONV_LIB_IS_ICONV 1\n') +config_hpp.write('#define VMIME_CHARSETCONV_LIB_IS_ICU 0\n') +config_hpp.write('\n') + config_hpp.write('// Options\n') config_hpp.write('// -- File-system support\n') diff --git a/cmake/FindICU.cmake b/cmake/FindICU.cmake new file mode 100644 index 00000000..786f157c --- /dev/null +++ b/cmake/FindICU.cmake @@ -0,0 +1,314 @@ +# This module can find the International Components for Unicode (ICU) Library +# +# Requirements: +# - CMake >= 2.8.3 (for new version of find_package_handle_standard_args) +# +# The following variables will be defined for your use: +# - ICU_FOUND : were all of your specified components found (include dependencies)? +# - ICU_INCLUDE_DIRS : ICU include directory +# - ICU_LIBRARIES : ICU libraries +# - ICU_VERSION : complete version of ICU (x.y.z) +# - ICU_MAJOR_VERSION : major version of ICU +# - ICU_MINOR_VERSION : minor version of ICU +# - ICU_PATCH_VERSION : patch version of ICU +# - ICU__FOUND : were found? (FALSE for non specified component if it is not a dependency) +# +# For windows or non standard installation, define ICU_ROOT variable to point to the root installation of ICU. Two ways: +# - run cmake with -DICU_ROOT= +# - define an environment variable with the same name before running cmake +# With cmake-gui, before pressing "Configure": +# 1) Press "Add Entry" button +# 2) Add a new entry defined as: +# - Name: ICU_ROOT +# - Type: choose PATH in the selection list +# - Press "..." button and select the root installation of ICU +# +# Example Usage: +# +# 1. Copy this file in the root of your project source directory +# 2. Then, tell CMake to search this non-standard module in your project directory by adding to your CMakeLists.txt: +# set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) +# 3. Finally call find_package() once, here are some examples to pick from +# +# Require ICU 4.4 or later +# find_package(ICU 4.4 REQUIRED) +# +# if(ICU_FOUND) +# include_directories(${ICU_INCLUDE_DIRS}) +# add_executable(myapp myapp.c) +# target_link_libraries(myapp ${ICU_LIBRARIES}) +# endif(ICU_FOUND) + +#============================================================================= +# Copyright (c) 2011-2012, julp +# https://github.com/julp/FindICU.cmake +# +# Distributed under the OSI-approved BSD License +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +#============================================================================= + +find_package(PkgConfig QUIET) + +########## Private ########## +set(ICU_PUBLIC_VAR_NS "ICU") # Prefix for all ICU relative public variables +set(ICU_PRIVATE_VAR_NS "_${ICU_PUBLIC_VAR_NS}") # Prefix for all ICU relative internal variables +set(PC_ICU_PRIVATE_VAR_NS "_PC${ICU_PRIVATE_VAR_NS}") # Prefix for all pkg-config relative internal variables + +function(icudebug _VARNAME) + if(${ICU_PUBLIC_VAR_NS}_DEBUG) + if(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME}) + message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = ${${ICU_PUBLIC_VAR_NS}_${_VARNAME}}") + else(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME}) + message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = ") + endif(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME}) + endif(${ICU_PUBLIC_VAR_NS}_DEBUG) +endfunction(icudebug) + +set(${ICU_PRIVATE_VAR_NS}_ROOT "") +if(DEFINED ENV{ICU_ROOT}) + set(${ICU_PRIVATE_VAR_NS}_ROOT "$ENV{ICU_ROOT}") +endif(DEFINED ENV{ICU_ROOT}) +if (DEFINED ICU_ROOT) + set(${ICU_PRIVATE_VAR_NS}_ROOT "${ICU_ROOT}") +endif(DEFINED ICU_ROOT) + +set(${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES ) +set(${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES ) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND ${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin64") + list(APPEND ${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib64") +endif(CMAKE_SIZEOF_VOID_P EQUAL 8) +list(APPEND ${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin") +list(APPEND ${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib") + +set(${ICU_PRIVATE_VAR_NS}_COMPONENTS ) +# ... +macro(icu_declare_component _NAME) + list(APPEND ${ICU_PRIVATE_VAR_NS}_COMPONENTS ${_NAME}) + set("${ICU_PRIVATE_VAR_NS}_COMPONENTS_${_NAME}" ${ARGN}) +endmacro(icu_declare_component) + +icu_declare_component(data icudata) +icu_declare_component(uc icuuc) # Common and Data libraries +icu_declare_component(i18n icui18n icuin) # Internationalization library +icu_declare_component(io icuio ustdio) # Stream and I/O Library +icu_declare_component(le icule) # Layout library +icu_declare_component(lx iculx) # Paragraph Layout library + +########## Public ########## +set(${ICU_PUBLIC_VAR_NS}_FOUND TRUE) +set(${ICU_PUBLIC_VAR_NS}_LIBRARIES ) +set(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS ) +set(${ICU_PUBLIC_VAR_NS}_C_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_CXX_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_CPP_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS "") +foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS}) + string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT) + set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) # may be done in the icu_declare_component macro +endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT) + +# Check components +if(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) # uc required at least + set(${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc) +else(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) + list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc) + list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) + foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS}) + if(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) + message(FATAL_ERROR "Unknown ICU component: ${${ICU_PRIVATE_VAR_NS}_COMPONENT}") + endif(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) + endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT) +endif(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) + +# Includes +find_path( + ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS + NAMES unicode/utypes.h utypes.h + HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT} + PATH_SUFFIXES "include" + DOC "Include directories for ICU" +) + +if(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS) + ########## ########## + if(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uvernum.h") # ICU >= 4 + file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uvernum.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) + elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uversion.h") # ICU [2;4[ + file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uversion.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) + elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/utypes.h") # ICU [1.4;2[ + file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) + elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/utypes.h") # ICU 1.3 + file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) + else() + message(FATAL_ERROR "ICU version header not found") + endif() + + if(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *ICU_VERSION *\"([0-9]+)\".*") # ICU 1.3 + # [1.3;1.4[ as #define ICU_VERSION "3" (no patch version, ie all 1.3.X versions will be detected as 1.3.0) + set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "1") + set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_1}") + set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "0") + elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION_MAJOR_NUM *([0-9]+).*") + set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}") + # + # Since version 4.9.1, ICU release version numbering was totaly changed, see: + # - http://site.icu-project.org/download/49 + # - http://userguide.icu-project.org/design#TOC-Version-Numbers-in-ICU + # + if(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION LESS 49) + string(REGEX REPLACE ".*# *define *U_ICU_VERSION_MINOR_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}") + string(REGEX REPLACE ".*# *define *U_ICU_VERSION_PATCHLEVEL_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}") + else(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION LESS 49) + string(REGEX MATCH [0-9]$ ${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION}") + string(REGEX REPLACE [0-9]$ "" ${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION}") + string(REGEX REPLACE ".*# *define *U_ICU_VERSION_MINOR_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}") + endif(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION LESS 49) + elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION *\"(([0-9]+)(\\.[0-9]+)*)\".*") # ICU [1.4;1.8[ + # [1.4;1.8[ as #define U_ICU_VERSION "1.4.1.2" but it seems that some 1.4.1(?:\.\d)? have releasing error and appears as 1.4.0 + set(${ICU_PRIVATE_VAR_NS}_FULL_VERSION "${CMAKE_MATCH_1}") # copy CMAKE_MATCH_1, no longer valid on the following if + if(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)$") + set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}") + set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}") + set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "0") + elseif(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}") + set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}") + set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${CMAKE_MATCH_3}") + endif() + else() + message(FATAL_ERROR "failed to detect ICU version") + endif() + set(${ICU_PUBLIC_VAR_NS}_VERSION "${${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION}.${${ICU_PUBLIC_VAR_NS}_MINOR_VERSION}.${${ICU_PUBLIC_VAR_NS}_PATCH_VERSION}") + ########## ########## + + # Check dependencies (implies pkg-config) + if(PKG_CONFIG_FOUND) + set(${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS}) + foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP}) + pkg_check_modules(PC_ICU_PRIVATE_VAR_NS "icu-${${ICU_PRIVATE_VAR_NS}_COMPONENT}" QUIET) + + if(${PC_ICU_PRIVATE_VAR_NS}_FOUND) + foreach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY ${PC_ICU_LIBRARIES}) + string(REGEX REPLACE "^icu" "" ${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY ${${PC_ICU_PRIVATE_VAR_NS}_LIBRARY}) + list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS ${${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY}) + endforeach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY) + endif(${PC_ICU_PRIVATE_VAR_NS}_FOUND) + endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT) + list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) + endif(PKG_CONFIG_FOUND) + + # Check libraries + foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS}) + set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES ) + set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES ) + foreach(${ICU_PRIVATE_VAR_NS}_BASE_NAME ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}) + list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}") + list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}d") + list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${ICU_MAJOR_VERSION}${ICU_MINOR_VERSION}") + list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${ICU_MAJOR_VERSION}${ICU_MINOR_VERSION}d") + endforeach(${ICU_PRIVATE_VAR_NS}_BASE_NAME) + + find_library( + ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} + NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES} + HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT} + PATH_SUFFIXES ${_ICU_LIB_SUFFIXES} + DOC "Release libraries for ICU" + ) + find_library( + ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT} + NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES} + HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT} + PATH_SUFFIXES ${_ICU_LIB_SUFFIXES} + DOC "Debug libraries for ICU" + ) + + string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT) + if(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # both not found + set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) + set("${ICU_PUBLIC_VAR_NS}_FOUND" FALSE) + else(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # one or both found + set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" TRUE) + if(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # release not found => we are in debug + set(${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} "${${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}") + elseif(NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # debug not found => we are in release + set(${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} "${${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}") + else() # both found + set( + ${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} + optimized ${${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}} + debug ${${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}} + ) + endif() + list(APPEND ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}) + endif(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) + endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT) + + # Try to find out compiler flags + find_program(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT} icu-config) + if(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + endif(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE) + + # Check find_package arguments + include(FindPackageHandleStandardArgs) + if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) + find_package_handle_standard_args( + ${ICU_PUBLIC_VAR_NS} + REQUIRED_VARS ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS + VERSION_VAR ${ICU_PUBLIC_VAR_NS}_VERSION + ) + else(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) + find_package_handle_standard_args(${ICU_PUBLIC_VAR_NS} "ICU not found" ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS) + endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) +else(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS) + if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) + message(FATAL_ERROR "Could not find ICU include directory") + endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) +endif(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS) + +mark_as_advanced( + ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS + ${ICU_PUBLIC_VAR_NS}_LIBRARIES +) + +# IN (args) +icudebug("FIND_COMPONENTS") +icudebug("FIND_REQUIRED") +icudebug("FIND_QUIETLY") +icudebug("FIND_VERSION") +# OUT +# Found +icudebug("FOUND") +icudebug("UC_FOUND") +icudebug("I18N_FOUND") +icudebug("IO_FOUND") +icudebug("LE_FOUND") +icudebug("LX_FOUND") +icudebug("DATA_FOUND") +# Flags +icudebug("C_FLAGS") +icudebug("CPP_FLAGS") +icudebug("CXX_FLAGS") +icudebug("C_SHARED_FLAGS") +icudebug("CPP_SHARED_FLAGS") +icudebug("CXX_SHARED_FLAGS") +# Linking +icudebug("INCLUDE_DIRS") +icudebug("LIBRARIES") +# Version +icudebug("MAJOR_VERSION") +icudebug("MINOR_VERSION") +icudebug("PATCH_VERSION") +icudebug("VERSION") diff --git a/cmake/config.hpp.cmake b/cmake/config.hpp.cmake index 3af17eb5..71badf40 100644 --- a/cmake/config.hpp.cmake +++ b/cmake/config.hpp.cmake @@ -37,6 +37,10 @@ typedef unsigned @VMIME_32BIT_TYPE@ vmime_uint32; #cmakedefine01 VMIME_HAVE_SIZE_T +// Charset conversion support +#cmakedefine01 VMIME_CHARSETCONV_LIB_IS_ICONV +#cmakedefine01 VMIME_CHARSETCONV_LIB_IS_ICU + // Options // -- File-system support #cmakedefine01 VMIME_HAVE_FILESYSTEM_FEATURES diff --git a/src/charsetConverter.cpp b/src/charsetConverter.cpp index c2041476..5d3ab626 100644 --- a/src/charsetConverter.cpp +++ b/src/charsetConverter.cpp @@ -23,7 +23,6 @@ #include "vmime/charsetConverter.hpp" -#include "vmime/charsetConverter_iconv.hpp" #include "vmime/charsetConverter_idna.hpp" @@ -39,7 +38,7 @@ ref charsetConverter::create if (source == "idna" || dest == "idna") return vmime::create (source, dest, opts); else - return vmime::create (source, dest, opts); + return createGenericConverter(source, dest, opts); } diff --git a/src/charsetConverter_iconv.cpp b/src/charsetConverter_iconv.cpp index c5d3557e..43556298 100644 --- a/src/charsetConverter_iconv.cpp +++ b/src/charsetConverter_iconv.cpp @@ -21,6 +21,12 @@ // the GNU General Public License cover the whole combination. // +#include "vmime/config.hpp" + + +#if VMIME_CHARSETCONV_LIB_IS_ICONV + + #include "vmime/charsetConverter_iconv.hpp" #include "vmime/exception.hpp" @@ -82,6 +88,15 @@ namespace vmime { +// static +ref charsetConverter::createGenericConverter + (const charset& source, const charset& dest, + const charsetConverterOptions& opts) +{ + return vmime::create (source, dest, opts); +} + + charsetConverter_iconv::charsetConverter_iconv (const charset& source, const charset& dest, const charsetConverterOptions& opts) : m_desc(NULL), m_source(source), m_dest(dest), m_options(opts) @@ -433,3 +448,6 @@ void charsetFilteredOutputStream_iconv::flush() } // vmime + + +#endif // VMIME_CHARSETCONV_LIB_IS_ICONV diff --git a/src/charsetConverter_icu.cpp b/src/charsetConverter_icu.cpp new file mode 100755 index 00000000..c5a19dc6 --- /dev/null +++ b/src/charsetConverter_icu.cpp @@ -0,0 +1,202 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_CHARSETCONV_LIB_IS_ICU + + +#include "vmime/charsetConverter_icu.hpp" + +#include "vmime/exception.hpp" +#include "vmime/utility/inputStreamStringAdapter.hpp" +#include "vmime/utility/outputStreamStringAdapter.hpp" + + +extern "C" +{ +#ifndef VMIME_BUILDING_DOC + + #include + #include + +#endif // VMIME_BUILDING_DOC +} + + +#include + + +namespace vmime +{ + + +// static +ref charsetConverter::createGenericConverter + (const charset& source, const charset& dest, + const charsetConverterOptions& opts) +{ + return vmime::create (source, dest, opts); +} + + +charsetConverter_icu::charsetConverter_icu + (const charset& source, const charset& dest, const charsetConverterOptions& opts) + : m_from(NULL), m_to(NULL), m_source(source), m_dest(dest), m_options(opts) +{ + UErrorCode err = U_ZERO_ERROR; + m_from = ucnv_open(source.getName().c_str(), &err); + + if (err != U_ZERO_ERROR) + throw exceptions::charset_conv_error("Cannot initialize ICU [from] converter."); + + m_to = ucnv_open(dest.getName().c_str(), &err); + + if (err != U_ZERO_ERROR) + throw exceptions::charset_conv_error("Cannot initialize ICU [to] converter."); +} + + +charsetConverter_icu::~charsetConverter_icu() +{ + ucnv_close(m_from); + ucnv_close(m_to); +} + + +void charsetConverter_icu::convert(utility::inputStream& in, utility::outputStream& out) +{ + UErrorCode err = U_ZERO_ERROR; + + // From buffers + char cpInBuffer[16]; // stream data put here + size_t outSize = ucnv_getMinCharSize(m_from) * sizeof(cpInBuffer) * sizeof(UChar); + UChar* uOutBuffer = new UChar[outSize]; // Unicode chars end up here + + // Auto delete Unicode char buffer + vmime::utility::auto_ptr cleanup(uOutBuffer); + + // To buffers + // converted (char) data end up here + size_t cpOutBufferSz = ucnv_getMaxCharSize(m_to) * outSize; + char* cpOutBuffer = new char[cpOutBufferSz]; + vmime::utility::auto_ptr cleanupOut(cpOutBuffer); + + // Set replacement chars for when converting from Unicode to codepage + icu::UnicodeString substString(m_options.invalidSequence.c_str()); + ucnv_setSubstString(m_to, substString.getTerminatedBuffer(), -1, &err); + + if (U_FAILURE(err)) + throw exceptions::charset_conv_error("[ICU] Error setting replacement char."); + + // Input data available + while (!in.eof()) + { + // Read input data into buffer + size_t inLength = static_cast(in.read(cpInBuffer, sizeof(cpInBuffer))); + + // Beginning of read data + const char* source = &cpInBuffer[0]; + const char* sourceLimit = source + inLength; // end + 1 + + UBool flush = in.eof(); // is this last run? + + UErrorCode toErr; + + // Loop until all source has been processed + do + { + // Set up target pointers + UChar* target = uOutBuffer; + UChar* targetLimit = target + outSize; + + toErr = U_ZERO_ERROR; + ucnv_toUnicode(m_from, &target, targetLimit, + &source, sourceLimit, NULL, flush, &toErr); + + if (toErr != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(toErr)) + throw exceptions::charset_conv_error("[ICU] Error converting to Unicode from " + m_source.getName()); + + // The Unicode source is the buffer just written and the limit + // is where the previous conversion stopped (target is moved in the conversion) + const UChar* uSource = uOutBuffer; + UChar* uSourceLimit = target; + UErrorCode fromErr; + + // Loop until converted chars are fully written + do + { + char* cpTarget = &cpOutBuffer[0]; + const char* cpTargetLimit = cpOutBuffer + cpOutBufferSz; + + fromErr = U_ZERO_ERROR; + + // Write converted bytes (Unicode) to destination codepage + ucnv_fromUnicode(m_to, &cpTarget, cpTargetLimit, + &uSource, uSourceLimit, NULL, flush, &fromErr); + + if (fromErr != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(fromErr)) + throw exceptions::charset_conv_error("[ICU] Error converting from Unicode to " + m_dest.getName()); + + // Write to destination stream + out.write(cpOutBuffer, (cpTarget - cpOutBuffer)); + + } while (fromErr == U_BUFFER_OVERFLOW_ERROR); + + } while (toErr == U_BUFFER_OVERFLOW_ERROR); + } +} + + +void charsetConverter_icu::convert(const string& in, string& out) +{ + if (m_source == m_dest) + { + // No conversion needed + out = in; + return; + } + + out.clear(); + + utility::inputStreamStringAdapter is(in); + utility::outputStreamStringAdapter os(out); + + convert(is, os); + + os.flush(); +} + + +ref charsetConverter_icu::getFilteredOutputStream(utility::outputStream& os) +{ + // TODO: implement charsetFilteredOutputStream for ICU + return NULL; +} + + +} // vmime + + +#endif // VMIME_CHARSETCONV_LIB_IS_ICU diff --git a/tests/parser/charsetFilteredOutputStreamTest.cpp b/tests/parser/charsetFilteredOutputStreamTest.cpp index 08eeb63c..92c7a595 100644 --- a/tests/parser/charsetFilteredOutputStreamTest.cpp +++ b/tests/parser/charsetFilteredOutputStreamTest.cpp @@ -49,6 +49,8 @@ VMIME_TEST_SUITE_BEGIN(charsetFilteredOutputStreamTest) vmime::utility::outputStreamStringAdapter os(output); vmime::ref cfos = cc->getFilteredOutputStream(os); + VASSERT_NOT_NULL("filteredOutputStream availability", cfos); + // føo = 66 c3 b8 6f [UTF8] // føo = 66 c3 b8 6f [latin1] @@ -79,6 +81,8 @@ VMIME_TEST_SUITE_BEGIN(charsetFilteredOutputStreamTest) vmime::ref os = conv->getFilteredOutputStream(osa); + VASSERT_NOT_NULL("filteredOutputStream availability", os); + vmime::utility::inputStreamStringAdapter is(in); vmime::utility::stream::value_type buffer[16]; @@ -116,6 +120,8 @@ VMIME_TEST_SUITE_BEGIN(charsetFilteredOutputStreamTest) vmime::ref os = conv->getFilteredOutputStream(osa); + VASSERT_NOT_NULL("filteredOutputStream availability", os); + vmime::utility::inputStreamStringAdapter is(in); vmime::utility::bufferedStreamCopy(is, *os); @@ -151,6 +157,8 @@ VMIME_TEST_SUITE_BEGIN(charsetFilteredOutputStreamTest) vmime::ref os = conv->getFilteredOutputStream(osa); + VASSERT_NOT_NULL("filteredOutputStream availability", os); + vmime::utility::inputStreamStringAdapter is(in); vmime::utility::stream::value_type buffer[16]; @@ -189,6 +197,8 @@ VMIME_TEST_SUITE_BEGIN(charsetFilteredOutputStreamTest) vmime::ref os = conv->getFilteredOutputStream(osa); + VASSERT_NOT_NULL("filteredOutputStream availability", os); + vmime::utility::inputStreamStringAdapter is(in); vmime::utility::stream::value_type buffer[16]; diff --git a/tests/parser/charsetTest.cpp b/tests/parser/charsetTest.cpp index 2aab7550..915b8560 100644 --- a/tests/parser/charsetTest.cpp +++ b/tests/parser/charsetTest.cpp @@ -141,7 +141,8 @@ VMIME_TEST_SUITE_BEGIN(charsetTest) void testUTF7Support() { // Ensure UTF-7 is supported, because it is used for IMAP - VASSERT_EQ("1", "VMime +ACY UTF-7 encoding", convertHelper("VMime & UTF-7 encoding", "utf-8", "utf-7")); + VASSERT_EQ("1", "VMime +- UTF-7 encoding", convertHelper("VMime + UTF-7 encoding", "utf-8", "utf-7")); + VASSERT_EQ("2", "f+APg-o", convertHelper("\x66\xc3\xb8\x6f", "utf-8", "utf-7")); } VMIME_TEST_SUITE_END diff --git a/vmime/charsetConverter.hpp b/vmime/charsetConverter.hpp index b7292d66..dcf90e48 100644 --- a/vmime/charsetConverter.hpp +++ b/vmime/charsetConverter.hpp @@ -104,6 +104,12 @@ public: * @return a filtered output stream, or NULL if not supported */ virtual ref getFilteredOutputStream(utility::outputStream& os) = 0; + +private: + + static ref createGenericConverter + (const charset& source, const charset& dest, + const charsetConverterOptions& opts); }; diff --git a/vmime/charsetConverter_iconv.hpp b/vmime/charsetConverter_iconv.hpp index 77a6651c..a590b320 100644 --- a/vmime/charsetConverter_iconv.hpp +++ b/vmime/charsetConverter_iconv.hpp @@ -25,6 +25,12 @@ #define VMIME_CHARSETCONVERTER_ICONV_HPP_INCLUDED +#include "vmime/config.hpp" + + +#if VMIME_CHARSETCONV_LIB_IS_ICONV + + #include "vmime/charsetConverter.hpp" @@ -121,4 +127,6 @@ private: } // vmime +#endif // VMIME_CHARSETCONV_LIB_IS_ICONV + #endif // VMIME_CHARSETCONVERTER_ICONV_HPP_INCLUDED diff --git a/vmime/charsetConverter_icu.hpp b/vmime/charsetConverter_icu.hpp new file mode 100755 index 00000000..ba0b82a9 --- /dev/null +++ b/vmime/charsetConverter_icu.hpp @@ -0,0 +1,84 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_CHARSETCONVERTER_ICU_HPP_INCLUDED +#define VMIME_CHARSETCONVERTER_ICU_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_CHARSETCONV_LIB_IS_ICU + + +#include "vmime/charsetConverter.hpp" + + +struct UConverter; + + +namespace vmime +{ + + +/** A generic charset converter which uses ICU library. + */ + +class charsetConverter_icu : public charsetConverter +{ +public: + + /** Construct and initialize an ICU charset converter. + * + * @param source input charset + * @param dest output charset + * @param opts conversion options + */ + charsetConverter_icu(const charset& source, const charset& dest, + const charsetConverterOptions& opts = charsetConverterOptions()); + + ~charsetConverter_icu(); + + void convert(const string& in, string& out); + void convert(utility::inputStream& in, utility::outputStream& out); + + ref getFilteredOutputStream(utility::outputStream& os); + +private: + + UConverter* m_from; + UConverter* m_to; + + charset m_source; + charset m_dest; + + charsetConverterOptions m_options; +}; + + +} // vmime + + +#endif // VMIME_CHARSETCONV_LIB_IS_ICU + +#endif // VMIME_CHARSETCONVERTER_ICU_HPP_INCLUDED -- cgit v1.2.3