Commit 2aad3158 authored by Mickaël Turnel's avatar Mickaël Turnel

Charset conversion is now specific to each platform

parent 2425a224
......@@ -63,10 +63,6 @@ if(NOT CPACK_GENERATOR AND NOT CMAKE_INSTALL_RPATH AND CMAKE_INSTALL_PREFIX)
message(STATUS "Setting install rpath to ${CMAKE_INSTALL_RPATH}")
endif()
if(APPLE)
find_package(Iconv REQUIRED)
endif()
if(ENABLE_MBEDTLS)
find_package(MbedTLS)
if(MBEDTLS_FOUND)
......
......@@ -31,7 +31,7 @@ extern "C" {
* @return a pointer to a null-terminated string containing the converted string. This buffer must then be freed
* by caller. NULL on failure.
*/
BCTBX_PUBLIC char *bctbx_locale_to_utf8(const char *str);
BCTBX_PUBLIC char *bctbx_locale_to_utf8 (const char *str);
/**
* @brief Convert the given string from UTF8 to system locale.
......@@ -41,22 +41,21 @@ BCTBX_PUBLIC char *bctbx_locale_to_utf8(const char *str);
* @return a pointer to a null-terminated string containing the converted string. This buffer must then be freed
* by caller. NULL on failure.
*/
BCTBX_PUBLIC char *bctbx_utf8_to_locale(const char *str);
BCTBX_PUBLIC char *bctbx_utf8_to_locale (const char *str);
/**
* @brief Convert the given string.
*
* @param[in] str string to convert
* @param[in] from charset of the string
* @param[in] to charset to convert
* @param[in] encoding charset of the string
*
* @return a pointer to a null-terminated string containing the converted string. This buffer must then be freed
* by caller. NULL on failure.
*
* @note If from or to is equal to "locale" then it will use the system's locale
* @note If from and to are equals then it returns a copy of str
* @note If encoding is equal to "locale" then it will use the system's locale
* @note If encoding is UTF-8 then it returns a copy of str
*/
BCTBX_PUBLIC char *bctbx_convert_from_to(const char *str, const char *from, const char *to);
BCTBX_PUBLIC char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding);
#ifdef __cplusplus
}
......
......@@ -34,9 +34,19 @@ set(BCTOOLBOX_CXX_SOURCE_FILES
containers/map.cc
crypto/ecc.cc
utils/regex.cc
utils/charconv.cc
)
set(BCTOOLBOX_OBJC_SOURCE_FILES)
if (APPLE)
list(APPEND BCTOOLBOX_OBJC_SOURCE_FILES conversion/charconv_apple.mm)
elseif (ANDROID)
list(APPEND BCTOOLBOX_CXX_SOURCE_FILES conversion/charconv_android.cc)
elseif (WIN32)
list(APPEND BCTOOLBOX_CXX_SOURCE_FILES conversion/charconv_windows.cc)
elseif (UNIX)
list(APPEND BCTOOLBOX_CXX_SOURCE_FILES conversion/charconv_linux.cc)
endif ()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
list(APPEND STRICT_OPTIONS_CXX "-x c++")
endif()
......@@ -59,20 +69,17 @@ if(BCUNIT_FOUND)
set(BCTOOLBOX_C_TESTER_SOURCE_FILES tester.c)
endif()
set(BCTOOLBOX_SOURCE_FILES ${BCTOOLBOX_C_SOURCE_FILES} ${BCTOOLBOX_CXX_SOURCE_FILES})
set(BCTOOLBOX_SOURCE_FILES ${BCTOOLBOX_C_SOURCE_FILES} ${BCTOOLBOX_CXX_SOURCE_FILES} ${BCTOOLBOX_OBJC_SOURCE_FILES})
set(BCTOOLBOX_TESTER_SOURCE_FILES ${BCTOOLBOX_C_TESTER_SOURCE_FILES})
bc_apply_compile_flags(BCTOOLBOX_C_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C)
bc_apply_compile_flags(BCTOOLBOX_C_TESTER_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C)
bc_apply_compile_flags(BCTOOLBOX_CXX_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX)
bc_apply_compile_flags(BCTOOLBOX_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC)
if(ENABLE_STATIC)
add_library(bctoolbox-static STATIC ${BCTOOLBOX_SOURCE_FILES} ${BCTOOLBOX_HEADER_FILES})
target_link_libraries(bctoolbox-static INTERFACE ${CMAKE_THREAD_LIBS_INIT})
if(APPLE)
target_include_directories(bctoolbox-static PRIVATE ${ICONV_INCLUDE_DIRS})
target_link_libraries(bctoolbox-static INTERFACE ${ICONV_LIBRARIES})
endif()
if(WIN32)
target_link_libraries(bctoolbox-static INTERFACE "Winmm" "Ws2_32")
endif()
......@@ -96,10 +103,6 @@ endif()
if(ENABLE_SHARED)
add_library(bctoolbox SHARED ${BCTOOLBOX_SOURCE_FILES} ${BCTOOLBOX_HEADER_FILES})
target_link_libraries(bctoolbox PRIVATE ${CMAKE_THREAD_LIBS_INIT})
if(APPLE)
target_include_directories(bctoolbox PRIVATE ${ICONV_INCLUDE_DIRS})
target_link_libraries(bctoolbox PRIVATE ${ICONV_LIBRARIES})
endif()
#TODO: replace by if(APPLE) when we want to make apple framework on linphone-desktop too
if(IOS)
if(IOS)
......
/*
bctoolbox
Copyright (C) 2016 Belledonne Communications SARL
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 2 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "bctoolbox/logging.h"
#include "bctoolbox/port.h"
#include "bctoolbox/charconv.h"
extern "C" char *bctbx_locale_to_utf8 (const char *str) {
// TODO remove this part when the NDK will contain a usable iconv
return bctbx_strdup(str);
}
extern "C" char *bctbx_utf8_to_locale (const char *str) {
// TODO remove this part when the NDK will contain a usable iconv
return bctbx_strdup(str);
}
extern "C" char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding) {
if (!encoding)
return NULL;
// TODO change this part when the NDK will contain a usable iconv
return bctbx_strdup(str);
}
/*
bctoolbox
Copyright (C) 2016 Belledonne Communications SARL
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 2 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <algorithm>
#include <unordered_map>
#include <NSString>
#include <NSStringEncoding>
#include "bctoolbox/logging.h"
#include "bctoolbox/port.h"
#include "bctoolbox/charconv.h"
extern "C" char *bctbx_locale_to_utf8 (const char *str) {
NSString *string = [NSString initWithCString:str encoding:defaultCStringEncoding];
return bctbx_strdup([string cStringUsingEncoding:defaultCStringEncoding]);
}
extern "C" char *bctbx_utf8_to_locale (const char *str) {
NSString *string = [NSString initWithUTF8String:str];
return bctbx_strdup([string UTF8String]);
}
extern "C" char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding) {
if (!encoding)
return NULL;
NSString *encodingString = [NSString initWithCString:encoding encoding:defaultCStringEncoding];
if (encodingString == kCFStringEncodingInvalidId) {
bctbx_error("Error while converting a string from '%s' to 'UTF-8': unknown charset", encoding);
return NULL;
}
NSStringEncoding encodingValue = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encodingString));
NSString *string = [NSString initWithCString:str encoding:encodingValue];
return bctbx_strdup([string UTF8String]);
}
/*
bctoolbox
Copyright (C) 2016 Belledonne Communications SARL
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 2 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <iconv.h>
#include <langinfo.h>
#include <locale.h>
#include <string.h>
#include "bctoolbox/logging.h"
#include "bctoolbox/port.h"
#include "bctoolbox/charconv.h"
static char *convert_from_to (const char *str, const char *from, const char *to) {
if (!from || !to)
return NULL;
if (strcasecmp(from, to) == 0)
return bctbx_strdup(str);
char *in_buf = (char *) str;
char *out_buf, *ptr;
size_t in_left = strlen(str) + 1;
size_t out_left = in_left + in_left/10; // leave a marge of 10%
iconv_t cd;
setlocale(LC_CTYPE, ""); // Retrieve environment locale before calling nl_langinfo
const char* r_from = strcasecmp("locale", from) == 0 ? nl_langinfo(CODESET) : from;
const char* r_to = strcasecmp("locale", to) == 0 ? nl_langinfo(CODESET) : to;
if (strcasecmp(r_from, r_to) == 0) {
return bctbx_strdup(str);
}
cd = iconv_open(r_to, r_from);
if (cd != (iconv_t)-1) {
size_t ret;
size_t out_len = out_left;
out_buf = (char *) bctbx_malloc(out_left);
ptr = out_buf; // Keep a pointer to the beginning of this buffer to be able to realloc
ret = iconv(cd, &in_buf, &in_left, &out_buf, &out_left);
while (ret == (size_t)-1 && errno == E2BIG) {
ptr = (char *) bctbx_realloc(ptr, out_len*2);
out_left = out_len;
out_buf = ptr + out_left;
out_len *= 2;
ret = iconv(cd, &in_buf, &in_left, &out_buf, &out_left);
}
iconv_close(cd);
if (ret == (size_t)-1 && errno != E2BIG) {
bctbx_error("Error while converting a string from '%s' to '%s': %s", from, to, strerror(errno));
bctbx_free(ptr);
return NULL;
}
} else {
bctbx_error("Unable to open iconv content descriptor from '%s' to '%s': %s", from, to, strerror(errno));
return NULL;
}
return ptr;
}
extern "C" char *bctbx_locale_to_utf8 (const char *str) {
return convert_from_to(str, "locale", "UTF-8");
}
extern "C" char *bctbx_utf8_to_locale (const char *str) {
return convert_from_to(str, "UTF-8", "locale");
}
extern "C" char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding) {
return convert_from_to(str, encoding, "UTF-8");
}
......@@ -20,27 +20,14 @@
#include "config.h"
#endif
#if !defined(_WIN32) && !defined(__QNXNTO__) && !defined(__ANDROID__)
# include <langinfo.h>
# include <locale.h>
# include <iconv.h>
# include <string.h>
# include <errno.h>
#endif
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
#include <algorithm>
#include <unordered_map>
#include "bctoolbox/logging.h"
#include "bctoolbox/port.h"
#include "bctoolbox/charconv.h"
#ifdef _WIN32
#include <algorithm>
#include <unordered_map>
static std::unordered_map <std::string, UINT> windows_charset {
static std::unordered_map <std::string, UINT> windowsCharset {
{ "LOCALE", CP_ACP },
{ "IBM037", 037 },
{ "IBM437", 437 },
......@@ -120,123 +107,64 @@ static std::unordered_map <std::string, UINT> windows_charset {
{ "UTF-8", 65001 }
};
std::string string_to_upper (const std::string &str) {
static std::string stringToUpper (const std::string &str) {
std::string result(str.size(), ' ');
std::transform(str.cbegin(), str.cend(), result.begin(), ::toupper);
return result;
}
#endif
extern "C" char *bctbx_locale_to_utf8(const char *str) {
#if defined(__ANDROID__) || TARGET_OS_IPHONE
// TODO remove this part when the NDK will contain a usable iconv
return bctbx_strdup(str);
#else
return bctbx_convert_from_to(str, "locale", "UTF-8");
#endif
}
extern "C" char *bctbx_utf8_to_locale(const char *str) {
#if defined(__ANDROID__) || TARGET_OS_IPHONE
// TODO remove this part when the NDK will contain a usable iconv
return bctbx_strdup(str);
#else
return bctbx_convert_from_to(str, "UTF-8", "locale");
#endif
}
extern "C" char *bctbx_convert_from_to(const char *str, const char *from, const char *to) {
static char *convert_from_to (const char *str, const char *from, const char *to) {
if (!from || !to)
return NULL;
if (strcasecmp(from, to) == 0)
return bctbx_strdup(str);
#if defined(_WIN32)
char* converted_str;
int n_char, nb_byte;
LPWSTR wide_str;
UINT r_from, r_to;
char* convertedStr;
int nChar, nbByte;
LPWSTR wideStr;
UINT rFrom, rTo;
try {
r_from = windows_charset.at(string_to_upper(std::string(from)));
r_to = windows_charset.at(string_to_upper(std::string(to)));
rFrom = windowsCharset.at(stringToUpper(std::string(from)));
rTo = windowsCharset.at(stringToUpper(std::string(to)));
}
catch (const std::out_of_range&) {
bctbx_error("Error while converting a string from '%s' to '%s': unknown charset", from, to);
return FALSE;
return NULL;
}
n_char = MultiByteToWideChar(r_from, 0, str, -1, NULL, 0);
if (n_char == 0) return NULL;
wide_str = (LPWSTR) bctbx_malloc(n_char*sizeof(wide_str[0]));
if (wide_str == NULL) return NULL;
n_char = MultiByteToWideChar(r_from, 0, str, -1, wide_str, n_char);
if (n_char == 0) {
bctbx_free(wide_str);
wide_str = 0;
nChar = MultiByteToWideChar(rFrom, 0, str, -1, NULL, 0);
if (nChar == 0) return NULL;
wideStr = (LPWSTR) bctbx_malloc(nChar*sizeof(wideStr[0]));
if (wideStr == NULL) return NULL;
nChar = MultiByteToWideChar(rFrom, 0, str, -1, wideStr, nChar);
if (nChar == 0) {
bctbx_free(wideStr);
wideStr = 0;
}
nb_byte = WideCharToMultiByte(r_to, 0, wide_str, -1, 0, 0, 0, 0);
if (nb_byte == 0) return NULL;
converted_str = (char *) bctbx_malloc(nb_byte);
if (converted_str == NULL) return NULL;
nb_byte = WideCharToMultiByte(r_to, 0, wide_str, -1, converted_str, nb_byte, 0, 0);
if (nb_byte == 0) {
bctbx_free(converted_str);
converted_str = 0;
}
bctbx_free(wide_str);
return converted_str;
#elif defined(__ANDROID__)
// TODO remove this part when the NDK will contain a usable iconv
bctbx_error("Unable to convert a string in Android: iconv is not available");
return NULL;
#else
char *in_buf = (char *) str;
char *out_buf, *ptr;
size_t in_left = strlen(str) + 1;
size_t out_left = in_left + in_left/10; // leave a marge of 10%
iconv_t cd;
setlocale(LC_CTYPE, ""); // Retrieve environment locale before calling nl_langinfo
const char* r_from = strcasecmp("locale", from) == 0 ? nl_langinfo(CODESET) : from;
const char* r_to = strcasecmp("locale", to) == 0 ? nl_langinfo(CODESET) : to;
if (strcasecmp(r_from, r_to) == 0) {
return bctbx_strdup(str);
nbByte = WideCharToMultiByte(rTo, 0, wideStr, -1, 0, 0, 0, 0);
if (nbByte == 0) return NULL;
convertedStr = (char *) bctbx_malloc(nbByte);
if (convertedStr == NULL) return NULL;
nbByte = WideCharToMultiByte(rTo, 0, wideStr, -1, convertedStr, nbByte, 0, 0);
if (nbByte == 0) {
bctbx_free(convertedStr);
convertedStr = 0;
}
bctbx_free(wideStr);
return convertedStr;
}
cd = iconv_open(r_to, r_from);
if (cd != (iconv_t)-1) {
size_t ret;
size_t out_len = out_left;
out_buf = (char *) bctbx_malloc(out_left);
ptr = out_buf; // Keep a pointer to the beginning of this buffer to be able to realloc
ret = iconv(cd, &in_buf, &in_left, &out_buf, &out_left);
while (ret == (size_t)-1 && errno == E2BIG) {
ptr = (char *) bctbx_realloc(ptr, out_len*2);
out_left = out_len;
out_buf = ptr + out_left;
out_len *= 2;
ret = iconv(cd, &in_buf, &in_left, &out_buf, &out_left);
}
iconv_close(cd);
if (ret == (size_t)-1 && errno != E2BIG) {
bctbx_error("Error while converting a string from '%s' to '%s': %s", from, to, strerror(errno));
bctbx_free(ptr);
return NULL;
}
} else {
bctbx_error("Unable to open iconv content descriptor from '%s' to '%s': %s", from, to, strerror(errno));
return NULL;
}
return ptr;
#endif
extern "C" char *bctbx_locale_to_utf8 (const char *str) {
return convert_from_to(str, "locale", "UTF-8");
}
extern "C" char *bctbx_utf8_to_locale (const char *str) {
return convert_from_to(str, "UTF-8", "locale");
}
extern "C" char *bctbx_convert_any_to_utf8 (const char *str, const char *encoding) {
return convert_from_to(str, encoding, "UTF-8");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment