10#pragma comment(lib, "Advapi32.lib")
26 FC_ReadMem(std::string_view sv)
noexcept: m_Src(sv.data()), m_End(sv.data()+sv.size()) {}
27 std::optional<char> operator()() noexcept
38 const char *m_Src, *
const m_End;
51constinit const char *
const CHSETS_SJIS[] = {
"CP932",
"EUC-JP",
"SHIFT_JIS",
"SHIFT-JIS",
"SJIS", 0};
52constinit const char *
const CHSETS_GB[] = {
"CP936",
"EUC-CN",
"GB18030",
"GBK", 0};
53constinit const char *
const CHSETS_KSC[] = {
"CP949",
"EUC-KR",
"JOHAB", 0};
54constinit const char *
const CHSETS_BIG5[] = {
"CP950",
"EUC-TW",
"BIG5-HKSCS",
"BIG5HKSCS",
"BIG-5",
"BIG5", 0};
55constinit const char *
const CHSETS_UTF8[] = {
"UTF-8",
"UTF8", 0};
56constinit const char *
const CHSETS_UTF7[] = {
"UTF-7",
"UTF7", 0};
57constinit const char *
const CHSETS_UTF16LE[] = {
"UTF-16LE",
"UTF16LE",
"UCS-2LE",
"USC2LE", 0};
58constinit const char *
const CHSETS_UTF16BE[] = {
"UTF-16BE",
"UTF16BE",
"UCS-2BE",
"USC2BE", 0};
89 else if (c < 0x200000)
95 else if (c < 0x4000000)
101 else if (c < 0x80000000)
112 for (
int i =ret; --i > 0;)
114 dst[i] =
T_Utf8((c &0x3F) | 0x80);
117 dst[0] =
T_Utf8(c |((
const unsigned char*)
"\xC0\xE0\xF0\xF8\xFC")[ret-2]);
136 const auto bytes = u32toutf8(uc, buf);
140 auto ret = std::to_chars(uc_hex, uc_hex+
sizeof uc_hex, uc, 16);
141 throw std::runtime_error{
"u32toutf8(u+" + std::string{uc_hex,ret.ptr} +
") returns " + std::to_string(bytes)};
143 return {
reinterpret_cast<char*
>(buf),
size_t(bytes)};
151 while ((n = uin.get(u8)) > 0)
152 ret.append(
reinterpret_cast<char*
>(u8),
size_t(n));
155 throw std::runtime_error{
"UTF-8 conversion error " + std::to_string(n)};
164 m_Src(std::move(readc)),
176 m_Src([&]()->std::optional<char> {
178 if (
static_cast<bool>(in.get(ch)))
219 (this->*m_ReadMethod)();
244 dst[0] =
T_Utf16((c >>10) |0xD800);
245 dst[1] =
T_Utf16((c &0x3FF) |0xDC00);
256 ret = u32toutf8(c, dst);
261void C_UnicodeIn::ingestMBCS()
265 if (
auto size = m_Src.size())
268 const auto utf16 = std::make_unique<wchar_t[]>(size);
269 if (
int wn = MultiByteToWideChar(m_CodePage, MB_ERR_INVALID_CHARS, m_Src.buffer(),
int(size), utf16.get(),
int(size)))
271 FC_ReadMem
read({
reinterpret_cast<char*
>(utf16.get()), size_t(wn*2)});
272 C_Source src(std::move(
read));
273 while (readUTF16(src,
false));
279 static constexpr const char *
const TO_UCS4 = std::endian::native == std::endian::little?
"UTF-32LE":
"UTF-32BE";
280 static_assert(std::endian::little != std::endian::big &&
281 (std::endian::native == std::endian::little || std::endian::native == std::endian::big));
282 for (
T_Encoding i = m_CodePage; *i && m_iconv == (iconv_t)(-1); ++i)
283 m_iconv = iconv_open(TO_UCS4, *i);
285 if (m_iconv == (iconv_t)(-1))
291 const auto ucs4 = std::make_unique<T_Utf32[]>(size);
292 size_t size_ucs4 = size * 4;
293 auto src =
const_cast<char*
>(m_Src.buffer());
294 auto dst =
reinterpret_cast<char*
>(ucs4.get());
295 if (
size_t(-1) != iconv(m_iconv, &src, &size, &dst, &size_ucs4))
298 for (
const T_Utf32 *i = ucs4.get(); i <
reinterpret_cast<T_Utf32*
>(dst); m_GetQ.push(*i++));
299 m_Src.pop(m_Src.size());
307 for (
const T_Utf32 *i = ucs4.get(); i <
reinterpret_cast<T_Utf32*
>(dst); m_GetQ.push(*i++));
308 m_Src.pop(m_Src.size()-size);
318void C_UnicodeIn::init()
322 switch (m_Src.size())
325 switch (m_Src.getUtf32(0,
false))
329 m_ReadMethod = &C_UnicodeIn::readUTF32;
334 m_ReadMethod = &C_UnicodeIn::readReverseUTF32;
341 switch (m_Src.getUtf16(0,
false))
345 m_ReadMethod = &C_UnicodeIn::readUTF16;
350 m_ReadMethod = &C_UnicodeIn::readReverseUTF16;
354 if (m_Src.size() >= 3 && 0 == memcmp(m_Src.buffer(), u8
"\uFEFF", 3))
358 setCodePage(CHSETS_UTF8);
359 m_ReadMethod = &C_UnicodeIn::readCodePage;
368 const auto size = m_Src.size();
371 if (size && size % 4 == 0)
373 size_t n_u32_chars = 0, n_u32rev_chars = 0;
374 const auto p_dwords =
reinterpret_cast<const T_Utf32*
>(m_Src.buffer());
375 const size_t n = size / 4;
376 for (
size_t i = 0; i < n; ++i)
378 if (
auto u32 = p_dwords[i])
380 bool matched =
false;
381 if (u32 == (u32 & 0xFFFFFF))
387 u32 = std::byteswap(u32);
388 if (u32 == (u32 & 0xFFFFFF))
398 const auto n_overflow = n_u32_chars + n_u32rev_chars - n;
399 if (n_u32_chars <= n_overflow)
401 m_ReadMethod = &C_UnicodeIn::readReverseUTF32;
404 if (n_u32rev_chars <= n_overflow)
406 m_ReadMethod = &C_UnicodeIn::readUTF32;
413 int mask = IS_TEXT_UNICODE_UNICODE_MASK;
414 if (IsTextUnicode(m_Src.buffer(),
int(size), &mask) || mask)
416 m_ReadMethod = &C_UnicodeIn::readUTF16;
419 mask = IS_TEXT_UNICODE_REVERSE_MASK;
420 if (IsTextUnicode(m_Src.buffer(),
int(size), &mask) || mask)
422 m_ReadMethod = &C_UnicodeIn::readReverseUTF16;
432 m_ReadMethod = &C_UnicodeIn::readASCII;
436 if (*m_Src.buffer() &0x80)
439 m_GetQ.push(
T_Utf8(*m_Src.buffer()));
448void C_UnicodeIn::readASCII()
453 const auto c =
T_Utf8(*m_Src.buffer());
467 m_Src.readTillCtrl();
474 m_ReadMethod = &C_UnicodeIn::readCodePage;
481bool C_UnicodeIn::guessCodePage()
483 if (m_Src.size() < 2) [[unlikely]]
486 static constinit const T_Encoding MBCS_CODEPAGES[] ={
489 932, 936, 949, 950, 951,
492 CHSETS_UTF8, CHSETS_SJIS, CHSETS_GB, CHSETS_KSC, CHSETS_BIG5, CHSETS_UTF7, CHSETS_UTF16LE, CHSETS_UTF16BE
495 for (
auto i: MBCS_CODEPAGES)
502 m_ReadMethod = &C_UnicodeIn::readCodePage;
509bool C_UnicodeIn::readUTF16(C_Source &src,
bool reverseWord)
513 const size_t read = src.size();
516 const auto uc = src.getUtf16(0,reverseWord);
517 if (0xD800 <= uc && uc < 0xDC00)
523 const T_Utf16 uc2 = src.getUtf16(1,reverseWord);
524 if (0xDC00 <= uc2 && uc2 < 0xE000)
528 m_GetQ.push(
T_Utf32((((uc&0x3FF)<<10)|(uc2&0x3FF))+0x10000));
538 else if (0xDC00 <= uc && uc < 0xE000)
554void C_UnicodeIn::readUTF16()
556 readUTF16(m_Src,
false);
559void C_UnicodeIn::readReverseUTF16()
561 readUTF16(m_Src,
true);
564bool C_UnicodeIn::readUTF32(C_Source &src,
bool reverseWord)
568 const size_t read = src.size();
571 m_GetQ.push(src.getUtf32(0,reverseWord));
581void C_UnicodeIn::readUTF32()
583 readUTF32(m_Src,
false);
586void C_UnicodeIn::readReverseUTF32()
588 readUTF32(m_Src,
true);
591void C_UnicodeIn::readCodePage()
593 m_Src.readTillCtrl();
606void C_UnicodeIn::reset_iconv()
608 if (m_iconv != (iconv_t)(-1))
610 iconv_close(m_iconv);
611 m_iconv = (iconv_t)(-1);
616C_UnicodeIn::C_Source::C_Source(
FH_ReadChar &&readc)
noexcept:
617 m_ReadCh(std::move(readc)),
622const char *C_UnicodeIn::C_Source::buffer() const noexcept
624 return m_ReadBuf.data() + m_AvailBeg;
627T_Utf16 C_UnicodeIn::C_Source::getUtf16(
size_t pos,
bool reverseWord)
const
629 const size_t off = m_AvailBeg + pos * 2;
630 if (off + 2 > m_ReadBuf.size())
631 throw std::runtime_error{
"End of char " + std::to_string(off+2) +
" passes end of buffer"};
633 auto ret = *
reinterpret_cast<const T_Utf16*
>(m_ReadBuf.data() + off);
634 return reverseWord? std::byteswap(ret): ret;
637T_Utf32 C_UnicodeIn::C_Source::getUtf32(
size_t pos,
bool reverseWord)
const
639 const size_t off = m_AvailBeg + pos * 4;
640 if (off + 4 > m_ReadBuf.size())
641 throw std::runtime_error{
"End of char " + std::to_string(off+4) +
" passes end of buffer"};
643 auto ret = *
reinterpret_cast<const T_Utf32*
>(m_ReadBuf.data() + off);
644 return reverseWord? std::byteswap(ret): ret;
647void C_UnicodeIn::C_Source::pop(
size_t bytes)
650 if (m_AvailBeg > m_ReadBuf.size())
653 throw std::runtime_error{
"m_AvailBeg overflow"};
657void C_UnicodeIn::C_Source::read(
size_t bytes)
659 if (m_AvailBeg + bytes > m_ReadBuf.size())
663 m_ReadBuf.erase(0, m_AvailBeg);
666 bytes -= m_ReadBuf.size();
667 for (
size_t i = 0; i < bytes; ++i)
668 if (
auto c = m_ReadCh())
675void C_UnicodeIn::C_Source::readTillCtrl()
677 if (m_AvailBeg == m_ReadBuf.size())
683 while (
auto c = m_ReadCh())
692size_t C_UnicodeIn::C_Source::size() const noexcept
694 return m_ReadBuf.size() - m_AvailBeg;
C_UnicodeIn(FH_ReadChar &&readc, T_Encoding codepage=0)
int lastError() const noexcept
THE common namespace of bux library.
std::string_view to_utf8(T_Utf32 uc)
const char *const * T_Encoding
std::function< std::optional< char >()> FH_ReadChar
void read(const std::string &src, size_t &off, T &data) noexcept
const T_Encoding ENCODING_UTF8
std::uint16_t T_Utf16
UTF-16: You need T_Utf16[2] to hold full range of unicode.
std::uint8_t T_Utf8
UTF-8: You need T_Utf8[4] to hold full range of unicode.
@ UIE_NO_UNICODE_TRANSLATION
std::uint32_t T_Utf32
UTF-32 to cover the full range of codespace U+0000 ~ U+10FFFF.