Skip to content

Instantly share code, notes, and snippets.

@kbinani
Last active December 15, 2015 14:09
Show Gist options
  • Save kbinani/5272091 to your computer and use it in GitHub Desktop.
Save kbinani/5272091 to your computer and use it in GitHub Desktop.
#include "convert_text_encoding.hpp"
#include <CoreServices/CoreServices.h>
#include <memory>
namespace detail
{
//!
//! @brief Get string encoding of wstring.
CFStringEncoding get_wide_string_encoding();
//!
//! @brief Create CFStringRef from std::basic_string
template<typename StringType>
CFStringRef create_string(const StringType &string, CFStringEncoding encoding);
size_t estimate_converted_string_bytes(const CFStringRef string, CFStringEncoding encode_to);
template<typename CharType>
bool convert(
const CFStringRef string,
CFStringEncoding encode_to,
const std::auto_ptr<CharType> &buffer,
size_t num_characters);
}
template<
typename DestStringType,
typename SourceStringType
>
DestStringType convert_encoding(
SourceStringType source,
CFStringEncoding encode_from,
CFStringEncoding encode_to)
{
typedef typename SourceStringType::value_type SourceCharType;
typedef typename DestStringType::value_type DestCharType;
const CFStringRef intermediate = detail::create_string(source, encode_from);
if (!intermediate) {
CFRelease(intermediate);
return DestStringType();
}
const size_t estimated_string_bytes = detail::estimate_converted_string_bytes(intermediate, encode_to);
if (estimated_string_bytes == 0) {
CFRelease(intermediate);
return DestStringType();
}
const size_t num_characters = estimated_string_bytes / sizeof(DestCharType);
const std::auto_ptr<DestCharType> buffer(new DestCharType[num_characters + 1]);
if (!buffer.get()) {
CFRelease(intermediate);
return DestStringType();
}
if (detail::convert(intermediate, encode_to, buffer, num_characters)) {
CFRelease(intermediate);
return DestStringType(buffer.get(), num_characters);
} else {
CFRelease(intermediate);
return DestStringType();
}
}
namespace detail
{
CFStringEncoding get_wide_string_encoding()
{
return CreateTextEncoding(kTextEncodingUnicodeDefault,
kTextEncodingDefaultVariant,
kUnicodeUTF32LEFormat);
}
template<typename StringType>
CFStringRef create_string(const StringType &string, CFStringEncoding encoding)
{
typedef typename StringType::value_type CharType;
const CFAllocatorRef allocator = NULL;
const Boolean has_external_representation = false;
const size_t string_bytes = string.size() * sizeof(CharType);
return CFStringCreateWithBytes(allocator,
(const UInt8 *)string.data(),
string_bytes,
encoding,
has_external_representation);
}
size_t estimate_converted_string_bytes(const CFStringRef string, CFStringEncoding encode_to)
{
const CFRange range = CFRangeMake(0, CFStringGetLength(string));
const UInt8 loss_byte = 0;
const Boolean has_external_representation = false;
const CFIndex max_buffer_length = 0;
CFIndex result = 0;
const CFIndex converted_characters = CFStringGetBytes(string,
range,
encode_to,
loss_byte,
has_external_representation,
NULL,
max_buffer_length,
&result);
if (converted_characters <= 0) {
return 0;
} else {
return result;
}
}
template<typename CharType>
bool convert(
const CFStringRef string,
CFStringEncoding encode_to,
const std::auto_ptr<CharType> &buffer,
size_t num_characters)
{
const size_t buffer_bytes = sizeof(CharType) * (num_characters + 1);
memset(buffer.get(), 0, buffer_bytes);
const CFRange range = CFRangeMake(0, CFStringGetLength(string));
const UInt8 loss_byte = 0;
const Boolean has_external_representation = false;
const CFIndex converted_characters = CFStringGetBytes(string,
range,
encode_to,
loss_byte,
has_external_representation,
(UInt8 *)buffer.get(),
buffer_bytes,
NULL);
return converted_characters > 0;
}
}
std::string encode(const std::wstring &string, CFStringEncoding encode_to)
{
return convert_encoding<std::string, std::wstring>(string, detail::get_wide_string_encoding(), encode_to);
}
std::wstring encode(const std::string &string, CFStringEncoding encode_from)
{
return convert_encoding<std::wstring, std::string>(string, encode_from, detail::get_wide_string_encoding());
}
#ifndef convert_text_encoding_convert_text_encoding_hpp
#define convert_text_encoding_convert_text_encoding_hpp
#include <CoreFoundation/CFString.h>
#include <string>
std::string encode(const std::wstring &string, CFStringEncoding encode_to);
std::wstring encode(const std::string &string, CFStringEncoding encode_from);
#endif
#include "convert_text_encoding.hpp"
#include <iostream>
#include <string>
int main()
{
std::wstring source(L"わはー");
std::string result = encode(source, kCFStringEncodingUTF8);
std::cout << result << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment