Всё же пришлось поизучать юникод.
Два четырёхзначных кодпоинта могут идти в суррогатной паре UTF-16, тогда декодировать их можно только вместе (там какой-то алгоритм с битовыми операциями).
То есть мне нужно обрабатывать такую ситуацию, когда в буфер попал первый кодпоинт из пары, без второго, и слать декодеру часть буфера до начала этой сломанной пары.
Иначе декодер выдаст не то. Склеивать полученные байты не поможет.
Пример: \u1F4AF — это эмоджи [💯]
В жсоне для кодирования юникода применяется UTF-16-BE, видимо чтобы количество цифр в кодпоинте всегда было 4 для удобства парсинга (удобства!! спасибо, блин).
Получаем "\ud83d\udcaf".
\ud83d — первый символ в суррогатной паре, leading UTF-16 surrogate, его можно определить по диапазону от 0xD800 до 0xDBFF включительно.
\udcaf — второй символ в паре, trailing UTF-16 surrogate, диапазон от 0xDC00 до 0xDFFF включительно.
Если парсер смог прочитать только первый кодпоинт 0xD83D и дошёл до конца буфера, значит, trailing surrogate мы не считали, декодировать кодпоинт не получится. Вернём его обратно к вызывающему (см. переменную leftovers), чтобы он добавил кривой жсон-эскейп с этим кодпоинтом в буфер в следующий раз, когда будет читать байты дальше. А щас декодируем только часть строки до \ud83d, не захватывая этот эскейп.
Багфикс:
https://git.dc09.ru/DarkCat09/proxishot/commit/e4873223f5
Разговор с самим собой:
https://git.dc09.ru/DarkCat09/proxishot/issues/1
#unicode #utf16 #json #parser