| 26 | |
| 27 | namespace visage { |
| 28 | class String { |
| 29 | public: |
| 30 | template<typename Utf32String> |
| 31 | static Utf32String convertUtf8ToUtf32(const std::string& utf8_str) { |
| 32 | Utf32String result; |
| 33 | result.reserve(utf8_str.size()); |
| 34 | |
| 35 | for (size_t i = 0; i < utf8_str.size(); ++i) { |
| 36 | unsigned char ch = utf8_str[i]; |
| 37 | |
| 38 | if (ch < 0x80) // ASCII character |
| 39 | result.push_back(ch); |
| 40 | else if (ch < 0xC0) // Error on continuation byte |
| 41 | result.push_back('*'); |
| 42 | else if (ch < 0xE0) { // 2 byte character |
| 43 | if (i + 1 >= utf8_str.size()) // Error - unfinished character. |
| 44 | return result; |
| 45 | |
| 46 | result.push_back(((ch & 0x1F) << 6) | (utf8_str[i + 1] & 0x3F)); |
| 47 | i += 1; |
| 48 | } |
| 49 | else if (ch < 0xF0) { // 3 byte character |
| 50 | if (i + 2 >= utf8_str.size()) // Error - unfinished character. |
| 51 | return result; |
| 52 | |
| 53 | result.push_back(((ch & 0x0F) << 12) | ((utf8_str[i + 1] & 0x3F) << 6) | |
| 54 | (utf8_str[i + 2] & 0x3F)); |
| 55 | i += 2; |
| 56 | } |
| 57 | else if (ch < 0xF8) { // 4 byte character |
| 58 | if (i + 3 >= utf8_str.size()) // Error - unfinished character. |
| 59 | return result; |
| 60 | |
| 61 | result.push_back(((ch & 0x07) << 18) | ((utf8_str[i + 1] & 0x3F) << 12) | |
| 62 | ((utf8_str[i + 2] & 0x3F) << 6) | (utf8_str[i + 3] & 0x3F)); |
| 63 | i += 3; |
| 64 | } |
| 65 | else // Error |
| 66 | return result; |
| 67 | } |
| 68 | |
| 69 | return result; |
| 70 | } |
| 71 | |
| 72 | template<typename Utf32String> |
| 73 | static std::string convertUtf32ToUtf8(const Utf32String& utf32_str) { |
| 74 | std::string result; |
| 75 | result.reserve(utf32_str.size() * 4); |
| 76 | |
| 77 | for (auto character : utf32_str) { |
| 78 | if (character < 0x80) // ASCII character |
| 79 | result.push_back(static_cast<char>(character)); |
| 80 | else if (character < 0x800) { // 2 byte character |
| 81 | result.push_back(static_cast<char>((character >> 6) | 0xC0)); |
| 82 | result.push_back(static_cast<char>((character & 0x3F) | 0x80)); |
| 83 | } |
| 84 | else if (character < 0x10000) { // 3 byte character |
| 85 | result.push_back(static_cast<char>((character >> 12) | 0xE0)); |
nothing calls this directly
no outgoing calls
no test coverage detected