-
Notifications
You must be signed in to change notification settings - Fork 0
/
utf8_2_win1251.c
50 lines (49 loc) · 4.11 KB
/
utf8_2_win1251.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/* Функция конвертирует utf8 строку в win 1251. Символы, не имеющие отображения, или переходят в 0x98 или пропускаются.
Вариант работы выбирается версией макроса SKIP_OR_NOT.
Входной массив может совпадать с выходным: данные будут перезаписаны.
ВНИМАНИЕ: массив utf8 должен быть выделен с запасом по памяти в 2 байта. Т.е. за символом конца строки '\0' должно быть как минимум 2 байта памяти.
В этих 2х байтах может лежать любой муcор. В противном случае программа может падать из-за доступа к не своей памяти.
Функция полностью независима и не требует ничего, кроме тройки макросов ниже. В том числе не требует никаких инклюдов.
Для использования просто скопируйте ее код вместе с 3мя макросами.
Не использует SIMD и даже x64, потому подходит для многих архитектур и даже для микроконтроллеров, т.к. ест мало памяти.
Связаться с автором: Илья chronosphere@mail.ru. Любой может использовать данный код для любых целей.
Просьба только не удалять ссылку на автора при копировании. */
#define NONS (0x98)
//#define SKIP_OR_NOT 1
#define SKIP_OR_NOT (dest != NONS)
#define M(W40, W45, W201) ((((W40) - 0x80) << 10) | (((W45) - (W40)) << 5) | ((W201) - 0x80))
unsigned int utf8_2_win1251(const char *utf8, char *win)
{
unsigned int dest, p, l1, l2, l3, inc, i, j, b1, b2, b3;
const unsigned short AR[16] = { M(NONS,NONS,0x86),M(0xA8,0xB8,0x87),M(0x80,0x90,0x95),M(0x81,0x83,0x96),
M(0xAA,0xBA,0x97),M(0xBD,0xBE,NONS),M(0xB2,0xB3,NONS),M(0xAF,0xBF,NONS),
M(0xA3,0xBC,0x91),M(0x8A,0x9A,0x92),M(0x8C,0x9C,0x82),M(0x8E,0x9E,NONS),
M(0x8D,0x9D,0x93),M(NONS,NONS,0x94),M(0xA1,0xA2,0x84),M(0x8F,0x9F,NONS) };
for (i = 0, j = 0; utf8[i] != 0; i += inc)
{
b1 = utf8[i]; b2 = utf8[i + 1]; b3 = utf8[i + 2];
/* Utf8 переводим в Unicode. */
inc = (0xE5000000u >> (((b1) >> 4) << 1)) & 0x3;
p = ((((b1) << 12) + (((b2) & 0x3F) << 6) + ((b3) & 0x3F)) & (0x7FFFF >> inc)) >> (((0xC5FFAAAAu >> (((b1) >> 4) << 1)) & 0x3) * 6);
/* Добавляем все остающиеся на месте. */
dest = (((inc != 0) & (((p >> 5) != 0x5) | (0xF71C852E >> b2))) - 1) & p; inc++;
/* Добавляем русские буквы кроме ё и Ё.*/
dest += ((((p - 0x10) >> 6) != 0x10) - 1) & (p - 0x350);
/* Добавляем символы из диапазонов: 0x401-0x40F, 0x451-0x45F, 0x2013-0x2022. */
l1 = ((p >> 4) != 0x40) - 1; l2 = ((p >> 4) != 0x45) - 1; l3 = (((p - 3) >> 4) != 0x201) - 1;
dest += ((((l2 & (AR[p & 0xF] >> 5)) | (l3 & AR[p & 0xF])) & 0x1F) + ((l1 | l2) & (AR[p & 0xF] >> 10))) + ((l1 | l2 | l3) & 0x80);
/* Добавляем оставшиеся. */
dest += (((p != 0x490) - 1) & 0xA5) | (((p != 0x491) - 1) & 0xB4) | (((p != 0x2026) - 1) & 0x85) |
(((p != 0x2030) - 1) & 0x89) | (((p != 0x2039) - 1) & 0x8B) | (((p != 0x203A) - 1) & 0x9B) |
(((p != 0x20AC) - 1) & 0x88) | (((p != 0x2116) - 1) & 0xB9) | (((p != 0x2122) - 1) & 0x99);
/* Отличаем настоящий 0 от просто отсутствующих в win 1251 символов. */
dest += (((b1 == 0) | (dest != 0)) - 1) & NONS;
win[j] = dest;
j += SKIP_OR_NOT;
}
win[j] = 0;
return j;
}
#undef M
#undef NONS
#undef SKIP_OR_NOT