| 1764 | } |
| 1765 | |
| 1766 | Error String::append_utf8(const char *p_utf8, int p_len, bool p_skip_cr) { |
| 1767 | if (!p_utf8) { |
| 1768 | return ERR_INVALID_DATA; |
| 1769 | } |
| 1770 | |
| 1771 | /* HANDLE BOM (Byte Order Mark) */ |
| 1772 | if (p_len < 0 || p_len >= 3) { |
| 1773 | bool has_bom = uint8_t(p_utf8[0]) == 0xef && uint8_t(p_utf8[1]) == 0xbb && uint8_t(p_utf8[2]) == 0xbf; |
| 1774 | if (has_bom) { |
| 1775 | //8-bit encoding, byte order has no meaning in UTF-8, just skip it |
| 1776 | if (p_len >= 0) { |
| 1777 | p_len -= 3; |
| 1778 | } |
| 1779 | p_utf8 += 3; |
| 1780 | } |
| 1781 | } |
| 1782 | |
| 1783 | if (p_len < 0) { |
| 1784 | p_len = strlen(p_utf8); |
| 1785 | } |
| 1786 | |
| 1787 | const int prev_length = length(); |
| 1788 | // If all utf8 characters maps to ASCII, then the max size will be p_len, and we add +1 for the null termination. |
| 1789 | resize_uninitialized(prev_length + p_len + 1); |
| 1790 | char32_t *dst = ptrw() + prev_length; |
| 1791 | |
| 1792 | Error result = Error::OK; |
| 1793 | |
| 1794 | const uint8_t *ptrtmp = (uint8_t *)p_utf8; |
| 1795 | const uint8_t *ptr_limit = (uint8_t *)p_utf8 + p_len; |
| 1796 | |
| 1797 | while (ptrtmp < ptr_limit && *ptrtmp) { |
| 1798 | uint8_t c = *ptrtmp; |
| 1799 | |
| 1800 | if (p_skip_cr && c == '\r') { |
| 1801 | ++ptrtmp; |
| 1802 | continue; |
| 1803 | } |
| 1804 | uint32_t unicode = _replacement_char; |
| 1805 | uint32_t size = 1; |
| 1806 | |
| 1807 | if ((c & 0b10000000) == 0) { |
| 1808 | unicode = c; |
| 1809 | if (unicode > 0x7F) { |
| 1810 | unicode = _replacement_char; |
| 1811 | print_unicode_error(vformat("Invalid unicode codepoint (%d)", unicode), true); |
| 1812 | result = Error::ERR_INVALID_DATA; |
| 1813 | } |
| 1814 | } else if ((c & 0b11100000) == 0b11000000) { |
| 1815 | if (ptrtmp + 1 >= ptr_limit) { |
| 1816 | print_unicode_error(vformat("Missing %x UTF-8 continuation byte", c), true); |
| 1817 | result = Error::ERR_INVALID_DATA; |
| 1818 | } else { |
| 1819 | uint8_t c2 = *(ptrtmp + 1); |
| 1820 | |
| 1821 | if ((c2 & 0b11000000) == 0b10000000) { |
| 1822 | unicode = (uint32_t)((c & 0b00011111) << 6) | (uint32_t)(c2 & 0b00111111); |
| 1823 |
no test coverage detected