utf8.c (3524B)
1 /* This program is licensed under the terms of GNU GPL v3 or (at your option) 2 * any later version. Copyright (C) 2020-2026 Страхиња Радић. 3 * See the file LICENSE for exact copyright and license details. */ 4 5 #include "utf8.h" 6 7 /* 8 * 00000000 -- 0000007F: 0xxxxxxx 9 * (2^7 = 128 chars) 10 * 00000080 -- 000007FF: 110xxxxx 10xxxxxx 11 * (2^5 = 32 chars) 12 * 00000800 -- 0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 13 * (2^4 = 16 chars) 14 * 00010000 -- 001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 15 * (2^3 = 8 chars) 16 * 00200000 -- 007FFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 17 * (2^2 = 4 chars) 18 * 00800000 -- 00FFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 19 * 10xxxxxx 20 * (2^1 = 2 chars) 21 */ 22 23 /* clang-format off */ 24 const int utf_length_table[256] = { 25 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 32 */ 27 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64 */ 29 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96 */ 31 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 128 */ 33 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 160 */ 35 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 192 */ 37 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 38 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 224 */ 39 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 40 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1, /* 256 */ 41 }; 42 /* clang-format on */ 43 44 const int extract_masks[6] = {XMASK1, XMASK2, XMASK3, XMASK4, XMASK5, XMASK6}; 45 46 int 47 u8_rune_to_u32(u32* to, const u8* from, size_t* from_delta) 48 { 49 const u8* pfrom = from; 50 if (!from) 51 return 1; 52 *from_delta = 0; 53 int len = utf_length_table[*from]; 54 *to = *from & extract_masks[len - 1]; 55 for (int i = 1; i < len; i++) 56 { 57 pfrom = from + i; 58 if (!*pfrom) 59 return 1; 60 *to <<= 6; 61 *to |= *pfrom & XMASKR; 62 } 63 *from_delta = len; 64 65 return 0; 66 } 67 68 int 69 u32_rune_to_u8(u8* to, const u32 from) 70 { 71 u32 cfrom = from; 72 u8 start = 0; 73 int len = 0; 74 if (from >= BOUND6) 75 { 76 start = START6; 77 len = 6; 78 } 79 else if (from >= BOUND5) 80 { 81 start = START5; 82 len = 5; 83 } 84 else if (from >= BOUND4) 85 { 86 start = START4; 87 len = 4; 88 } 89 else if (from >= BOUND3) 90 { 91 start = START3; 92 len = 3; 93 } 94 else if (from >= BOUND2) 95 { 96 start = START2; 97 len = 2; 98 } 99 else 100 { 101 start = START1; 102 len = 1; 103 } 104 for (int i = len - 1; i > 0; i--) 105 { 106 to[i] = STARTR | (cfrom & XMASKR); 107 cfrom >>= 6; 108 } 109 to[0] = start | cfrom; 110 return len; 111 } 112 113 int 114 u8_to_u32(u32* to, const u8* from, const ssize_t max, size_t* from_delta) 115 { 116 const u8* pfrom = from; 117 u32* pto = to; 118 if (!from) 119 return 1; 120 size_t delta = 0; 121 *from_delta = 0; 122 while (pfrom - from < max && *pfrom) 123 { 124 int result = u8_rune_to_u32(pto, pfrom, &delta); 125 if (result) 126 return result; 127 pto++; 128 pfrom += delta; 129 *from_delta += delta; 130 } 131 *pto = 0; 132 return 0; 133 } 134 135 int 136 u32_to_u8(u8* to, const u32* from, const ssize_t max) 137 { 138 const u32* pfrom = from; 139 u8* pto = to; 140 int len = 0; 141 if (!from) 142 return 0; 143 while (pfrom - from < max && *pfrom) 144 { 145 size_t delta = u32_rune_to_u8(pto, *pfrom); 146 pto += delta; 147 len += delta; 148 pfrom++; 149 } 150 return len; 151 } 152 153 size_t 154 u32_strlen(const u32* s, const ssize_t max) 155 { 156 const u32* ps = s; 157 while (ps && ps - s < max && *ps) 158 ps++; 159 return ps - s; 160 }