clean up utf8 conversion wrapper a bit, to not rely on dead-code elimination in constant conditions

This commit is contained in:
Arvid Norberg 2015-05-09 13:58:32 +00:00
parent b3d7668e7a
commit b4a6a14dfb
1 changed files with 105 additions and 48 deletions

View File

@ -40,67 +40,124 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent
{
utf8_conv_result_t utf8_wchar(const std::string &utf8, std::wstring &wide)
namespace
{
// ==== utf-8 -> wide ===
template<int width>
struct convert_to_wide
{
static utf8_conv_result_t convert(UTF8 const** src_start
, UTF8 const* src_end
, std::wstring& wide)
{
return source_illegal;
}
};
// ==== utf-8 -> utf-32 ===
template<>
struct convert_to_wide<4>
{
static utf8_conv_result_t convert(char const** src_start
, char const* src_end
, std::wstring& wide)
{
wchar_t const* dst_start = wide.c_str();
int ret = ConvertUTF8toUTF32((UTF8 const**)src_start
, (UTF8 const*)src_end
, (UTF32**)&dst_start, (UTF32*)dst_start + wide.size()
, lenientConversion);
wide.resize(dst_start - wide.c_str());
return (utf8_conv_result_t)ret;
}
};
// ==== utf-8 -> utf-16 ===
template<>
struct convert_to_wide<2>
{
static utf8_conv_result_t convert(char const** src_start
, char const* src_end
, std::wstring& wide)
{
wchar_t const* dst_start = wide.c_str();
int ret = ConvertUTF8toUTF16((UTF8 const**)src_start
, (UTF8 const*)src_end
, (UTF16**)&dst_start, (UTF16*)dst_start + wide.size()
, lenientConversion);
wide.resize(dst_start - wide.c_str());
return (utf8_conv_result_t)ret;
}
};
// ==== wide -> utf-8 ===
template<int width>
struct convert_from_wide
{
static utf8_conv_result_t convert(wchar_t const** src_start
, wchar_t const* src_end
, std::string& utf8)
{
return source_illegal;
}
};
// ==== utf-32 -> utf-8 ===
template<>
struct convert_from_wide<4>
{
static utf8_conv_result_t convert(wchar_t const** src_start
, wchar_t const* src_end
, std::string& utf8)
{
char const* dst_start = utf8.c_str();
int ret = ConvertUTF32toUTF8((UTF32 const**)src_start
, (UTF32 const*)src_end, (UTF8**)&dst_start
, (UTF8*)dst_start + utf8.size()
, lenientConversion);
utf8.resize(dst_start - &utf8[0]);
return (utf8_conv_result_t)ret;
}
};
// ==== utf-16 -> utf-8 ===
template<>
struct convert_from_wide<2>
{
static utf8_conv_result_t convert(wchar_t const** src_start
, wchar_t const* src_end
, std::string& utf8)
{
char const* dst_start = utf8.c_str();
int ret = ConvertUTF16toUTF8((UTF16 const**)src_start
, (UTF16 const*)src_end, (UTF8**)&dst_start
, (UTF8*)dst_start + utf8.size()
, lenientConversion);
utf8.resize(dst_start - &utf8[0]);
return (utf8_conv_result_t)ret;
}
};
} // anonymous namespace
utf8_conv_result_t utf8_wchar(std::string const& utf8, std::wstring &wide)
{
// allocate space for worst-case
wide.resize(utf8.size());
wchar_t const* dst_start = wide.c_str();
char const* src_start = utf8.c_str();
ConversionResult ret;
// TODO: 3 refactor this to use wchar_t as a template
// it would cause less code to be generated without
// relying on dead-code elimination and fix msvc constant
// expression warning
if (sizeof(wchar_t) == sizeof(UTF32))
{
ret = ConvertUTF8toUTF32((const UTF8**)&src_start, (const UTF8*)src_start
+ utf8.size(), (UTF32**)&dst_start, (UTF32*)dst_start + wide.size()
, lenientConversion);
wide.resize(dst_start - wide.c_str());
return (utf8_conv_result_t)ret;
}
else if (sizeof(wchar_t) == sizeof(UTF16))
{
ret = ConvertUTF8toUTF16((const UTF8**)&src_start, (const UTF8*)src_start
+ utf8.size(), (UTF16**)&dst_start, (UTF16*)dst_start + wide.size()
, lenientConversion);
wide.resize(dst_start - wide.c_str());
return (utf8_conv_result_t)ret;
}
else
{
return source_illegal;
}
return convert_to_wide<sizeof(wchar_t)>::convert(
&src_start, src_start + utf8.size(), wide);
}
utf8_conv_result_t wchar_utf8(const std::wstring &wide, std::string &utf8)
utf8_conv_result_t wchar_utf8(std::wstring const& wide, std::string &utf8)
{
// allocate space for worst-case
utf8.resize(wide.size() * 6);
if (wide.empty()) return conversion_ok;
char* dst_start = &utf8[0];
wchar_t const* src_start = wide.c_str();
ConversionResult ret;
if (sizeof(wchar_t) == sizeof(UTF32))
{
ret = ConvertUTF32toUTF8((const UTF32**)&src_start, (const UTF32*)src_start
+ wide.size(), (UTF8**)&dst_start, (UTF8*)dst_start + utf8.size()
, lenientConversion);
utf8.resize(dst_start - &utf8[0]);
return (utf8_conv_result_t)ret;
}
else if (sizeof(wchar_t) == sizeof(UTF16))
{
ret = ConvertUTF16toUTF8((const UTF16**)&src_start, (const UTF16*)src_start
+ wide.size(), (UTF8**)&dst_start, (UTF8*)dst_start + utf8.size()
, lenientConversion);
utf8.resize(dst_start - &utf8[0]);
return (utf8_conv_result_t)ret;
}
else
{
return source_illegal;
}
return convert_from_wide<sizeof(wchar_t)>::convert(
&src_start, src_start + wide.size(), utf8);
}
}