| 361 | } |
| 362 | |
| 363 | static char32_t decode_utf8(const std::string & input, size_t pos, size_t & advance) { |
| 364 | unsigned char c = static_cast<unsigned char>(input[pos]); |
| 365 | if ((c & 0x80u) == 0u) { |
| 366 | advance = 1; |
| 367 | return c; |
| 368 | } |
| 369 | if ((c & 0xE0u) == 0xC0u && pos + 1 < input.size()) { |
| 370 | unsigned char c1 = static_cast<unsigned char>(input[pos + 1]); |
| 371 | if ((c1 & 0xC0u) != 0x80u) { |
| 372 | advance = 1; |
| 373 | return 0xFFFD; |
| 374 | } |
| 375 | advance = 2; |
| 376 | return ((c & 0x1Fu) << 6) | (static_cast<unsigned char>(input[pos + 1]) & 0x3Fu); |
| 377 | } |
| 378 | if ((c & 0xF0u) == 0xE0u && pos + 2 < input.size()) { |
| 379 | unsigned char c1 = static_cast<unsigned char>(input[pos + 1]); |
| 380 | unsigned char c2 = static_cast<unsigned char>(input[pos + 2]); |
| 381 | if ((c1 & 0xC0u) != 0x80u || (c2 & 0xC0u) != 0x80u) { |
| 382 | advance = 1; |
| 383 | return 0xFFFD; |
| 384 | } |
| 385 | advance = 3; |
| 386 | return ((c & 0x0Fu) << 12) | |
| 387 | ((static_cast<unsigned char>(input[pos + 1]) & 0x3Fu) << 6) | |
| 388 | (static_cast<unsigned char>(input[pos + 2]) & 0x3Fu); |
| 389 | } |
| 390 | if ((c & 0xF8u) == 0xF0u && pos + 3 < input.size()) { |
| 391 | unsigned char c1 = static_cast<unsigned char>(input[pos + 1]); |
| 392 | unsigned char c2 = static_cast<unsigned char>(input[pos + 2]); |
| 393 | unsigned char c3 = static_cast<unsigned char>(input[pos + 3]); |
| 394 | if ((c1 & 0xC0u) != 0x80u || (c2 & 0xC0u) != 0x80u || (c3 & 0xC0u) != 0x80u) { |
| 395 | advance = 1; |
| 396 | return 0xFFFD; |
| 397 | } |
| 398 | advance = 4; |
| 399 | return ((c & 0x07u) << 18) | |
| 400 | ((static_cast<unsigned char>(input[pos + 1]) & 0x3Fu) << 12) | |
| 401 | ((static_cast<unsigned char>(input[pos + 2]) & 0x3Fu) << 6) | |
| 402 | (static_cast<unsigned char>(input[pos + 3]) & 0x3Fu); |
| 403 | } |
| 404 | |
| 405 | advance = 1; |
| 406 | return 0xFFFD; // replacement character for invalid input |
| 407 | } |
| 408 | |
| 409 | static void append_utf8(char32_t ch, std::string & out) { |
| 410 | if (ch <= 0x7F) { |
no test coverage detected