| 15 | namespace dxmt::str { |
| 16 | |
| 17 | const uint8_t *decodeTypedChar(const uint8_t *begin, const uint8_t *end, |
| 18 | uint32_t &ch) { |
| 19 | uint32_t first = begin[0]; |
| 20 | |
| 21 | if (likely(first < 0x80)) { |
| 22 | // Basic ASCII character |
| 23 | ch = uint32_t(first); |
| 24 | return begin + 1; |
| 25 | } else if (unlikely(first < 0xC0)) { |
| 26 | // Character starts with a continuation byte, |
| 27 | // just skip until we find the next valid prefix |
| 28 | while ((begin < end) && (((*begin) & 0xC0) == 0x80)) |
| 29 | begin += 1; |
| 30 | |
| 31 | ch = uint32_t('?'); |
| 32 | return begin; |
| 33 | } else { |
| 34 | // The number of leading 1 bits in the first byte |
| 35 | // determines the length of this character |
| 36 | size_t length = bit::lzcnt((~first) << 24); |
| 37 | |
| 38 | if (unlikely(begin + length > end)) { |
| 39 | ch = uint32_t('?'); |
| 40 | return end; |
| 41 | } |
| 42 | |
| 43 | if (first < 0xE0) { |
| 44 | ch = ((uint32_t(begin[0]) & 0x1F) << 6) | ((uint32_t(begin[1]) & 0x3F)); |
| 45 | } else if (first < 0xF0) { |
| 46 | ch = ((uint32_t(begin[0]) & 0x0F) << 12) | |
| 47 | ((uint32_t(begin[1]) & 0x3F) << 6) | ((uint32_t(begin[2]) & 0x3F)); |
| 48 | } else if (first < 0xF8) { |
| 49 | ch = ((uint32_t(begin[0]) & 0x07) << 18) | |
| 50 | ((uint32_t(begin[1]) & 0x3F) << 12) | |
| 51 | ((uint32_t(begin[2]) & 0x3F) << 6) | ((uint32_t(begin[3]) & 0x3F)); |
| 52 | } else { |
| 53 | // Invalid prefix |
| 54 | ch = uint32_t('?'); |
| 55 | } |
| 56 | |
| 57 | return begin + length; |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | const uint16_t *decodeTypedChar(const uint16_t *begin, const uint16_t *end, |
| 62 | uint32_t &ch) { |