UTF-8 — это многобайтовая кодировка и у неё нет кодов. Так что считаем, что имеем дело с кодами Юникода.
Это только кусок моей мини-библиотеки, так что…
Шаблон использовался, чтобы автоматически специализировать под нужную длину wchar_t, реально есть версии под 1 и 2.
namespace str{
enum {
SURROGATE_MIN = 0xD800,
SURROGATE_MAX = 0xDFFF,
SURROGATE_LO_MIN = SURROGATE_MIN,
SURROGATE_HI_MIN = 0xDC00,
SURROGATE_LO_MAX = SURROGATE_HI_MIN - 1,
SURROGATE_HI_MAX = SURROGATE_MAX,
UNICODE_MAX = 0x10FFFF,
U8_1BYTE_MAX = 0x7F,
U8_2BYTE_MIN = 0x80,
U8_2BYTE_MAX = 0x7FF,
U8_3BYTE_MIN = 0x800,
U8_3BYTE_MAX = 0xFFFF,
U8_4BYTE_MIN = 0x10000,
U8_4BYTE_MAX = UNICODE_MAX,
U16_1WORD_MAX = 0xFFFF,
U16_2WORD_MIN = 0x10000,
U16_2WORD_MAX = UNICODE_MAX,
};
template <int Len>
void putCpNeT (wchar_t*& p, unsigned long aCp);
/// Puts a code-point in wchar_t encoding, w/o error-checking
/// @param [in,out] p position to put to
/// @param [in] aCp code-point, surely valid
inline void putCpNe (wchar_t*& p, unsigned long aCp)
{ putCpNeT<sizeof(wchar_t)>(p, aCp); }
} // namespace str
template <>
void str::putCpNeT<2> (wchar_t*& p, unsigned long aCp)
{
if (aCp < U16_2WORD_MIN) { // 1 word
*(p++) = static_cast<wchar_t>(aCp);
} else if (aCp <= U16_2WORD_MAX) { // 2 words
aCp -= U16_2WORD_MIN;
// Hi word
const wchar_t lo10 = aCp & 0x3FF;
const wchar_t hi10 = aCp >> 10;
*(p++) = static_cast<wchar_t>(0xD800 | hi10);
*(p++) = static_cast<wchar_t>(0xDC00 | lo10);
}
}
void str::appendCp(std::wstring& s, unsigned long aCp)
{
wchar_t c[5];
wchar_t* end = c;
putCpNe(end, aCp);
s.append(c, end);
}