]> git.ipfire.org Git - thirdparty/u-boot.git/blob - lib/charset.c
Merge branch 'master' of git://git.denx.de/u-boot-spi
[thirdparty/u-boot.git] / lib / charset.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * charset conversion utils
4 *
5 * Copyright (c) 2017 Rob Clark
6 */
7
8 #include <common.h>
9 #include <charset.h>
10 #include <capitalization.h>
11 #include <malloc.h>
12
13 static struct capitalization_table capitalization_table[] =
14 #ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
15 UNICODE_CAPITALIZATION_TABLE;
16 #elif CONFIG_FAT_DEFAULT_CODEPAGE == 1250
17 CP1250_CAPITALIZATION_TABLE;
18 #else
19 CP437_CAPITALIZATION_TABLE;
20 #endif
21
22 /**
23 * get_code() - read Unicode code point from UTF-8 stream
24 *
25 * @read_u8: - stream reader
26 * @src: - string buffer passed to stream reader, optional
27 * Return: - Unicode code point
28 */
29 static int get_code(u8 (*read_u8)(void *data), void *data)
30 {
31 s32 ch = 0;
32
33 ch = read_u8(data);
34 if (!ch)
35 return 0;
36 if (ch >= 0xc2 && ch <= 0xf4) {
37 int code = 0;
38
39 if (ch >= 0xe0) {
40 if (ch >= 0xf0) {
41 /* 0xf0 - 0xf4 */
42 ch &= 0x07;
43 code = ch << 18;
44 ch = read_u8(data);
45 if (ch < 0x80 || ch > 0xbf)
46 goto error;
47 ch &= 0x3f;
48 } else {
49 /* 0xe0 - 0xef */
50 ch &= 0x0f;
51 }
52 code += ch << 12;
53 if ((code >= 0xD800 && code <= 0xDFFF) ||
54 code >= 0x110000)
55 goto error;
56 ch = read_u8(data);
57 if (ch < 0x80 || ch > 0xbf)
58 goto error;
59 }
60 /* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
61 ch &= 0x3f;
62 code += ch << 6;
63 ch = read_u8(data);
64 if (ch < 0x80 || ch > 0xbf)
65 goto error;
66 ch &= 0x3f;
67 ch += code;
68 } else if (ch >= 0x80) {
69 goto error;
70 }
71 return ch;
72 error:
73 return '?';
74 }
75
76 /**
77 * read_string() - read byte from character string
78 *
79 * @data: - pointer to string
80 * Return: - byte read
81 *
82 * The string pointer is incremented if it does not point to '\0'.
83 */
84 static u8 read_string(void *data)
85
86 {
87 const char **src = (const char **)data;
88 u8 c;
89
90 if (!src || !*src || !**src)
91 return 0;
92 c = **src;
93 ++*src;
94 return c;
95 }
96
97 /**
98 * read_console() - read byte from console
99 *
100 * @src - not used, needed to match interface
101 * Return: - byte read
102 */
103 static u8 read_console(void *data)
104 {
105 return getc();
106 }
107
108 int console_read_unicode(s32 *code)
109 {
110 if (!tstc()) {
111 /* No input available */
112 return 1;
113 }
114
115 /* Read Unicode code */
116 *code = get_code(read_console, NULL);
117 return 0;
118 }
119
120 s32 utf8_get(const char **src)
121 {
122 return get_code(read_string, src);
123 }
124
125 int utf8_put(s32 code, char **dst)
126 {
127 if (!dst || !*dst)
128 return -1;
129 if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
130 return -1;
131 if (code <= 0x007F) {
132 **dst = code;
133 } else {
134 if (code <= 0x07FF) {
135 **dst = code >> 6 | 0xC0;
136 } else {
137 if (code < 0x10000) {
138 **dst = code >> 12 | 0xE0;
139 } else {
140 **dst = code >> 18 | 0xF0;
141 ++*dst;
142 **dst = (code >> 12 & 0x3F) | 0x80;
143 }
144 ++*dst;
145 **dst = (code >> 6 & 0x3F) | 0x80;
146 }
147 ++*dst;
148 **dst = (code & 0x3F) | 0x80;
149 }
150 ++*dst;
151 return 0;
152 }
153
154 size_t utf8_utf16_strnlen(const char *src, size_t count)
155 {
156 size_t len = 0;
157
158 for (; *src && count; --count) {
159 s32 code = utf8_get(&src);
160
161 if (!code)
162 break;
163 if (code < 0) {
164 /* Reserve space for a replacement character */
165 len += 1;
166 } else if (code < 0x10000) {
167 len += 1;
168 } else {
169 len += 2;
170 }
171 }
172 return len;
173 }
174
175 int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count)
176 {
177 if (!src || !dst || !*dst)
178 return -1;
179
180 for (; count && *src; --count) {
181 s32 code = utf8_get(&src);
182
183 if (code < 0)
184 code = '?';
185 utf16_put(code, dst);
186 }
187 **dst = 0;
188 return 0;
189 }
190
191 s32 utf16_get(const u16 **src)
192 {
193 s32 code, code2;
194
195 if (!src || !*src)
196 return -1;
197 if (!**src)
198 return 0;
199 code = **src;
200 ++*src;
201 if (code >= 0xDC00 && code <= 0xDFFF)
202 return -1;
203 if (code >= 0xD800 && code <= 0xDBFF) {
204 if (!**src)
205 return -1;
206 code &= 0x3ff;
207 code <<= 10;
208 code += 0x10000;
209 code2 = **src;
210 ++*src;
211 if (code2 <= 0xDC00 || code2 >= 0xDFFF)
212 return -1;
213 code2 &= 0x3ff;
214 code += code2;
215 }
216 return code;
217 }
218
219 int utf16_put(s32 code, u16 **dst)
220 {
221 if (!dst || !*dst)
222 return -1;
223 if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
224 return -1;
225 if (code < 0x10000) {
226 **dst = code;
227 } else {
228 code -= 0x10000;
229 **dst = code >> 10 | 0xD800;
230 ++*dst;
231 **dst = (code & 0x3ff) | 0xDC00;
232 }
233 ++*dst;
234 return 0;
235 }
236
237 size_t utf16_strnlen(const u16 *src, size_t count)
238 {
239 size_t len = 0;
240
241 for (; *src && count; --count) {
242 s32 code = utf16_get(&src);
243
244 if (!code)
245 break;
246 /*
247 * In case of an illegal sequence still reserve space for a
248 * replacement character.
249 */
250 ++len;
251 }
252 return len;
253 }
254
255 size_t utf16_utf8_strnlen(const u16 *src, size_t count)
256 {
257 size_t len = 0;
258
259 for (; *src && count; --count) {
260 s32 code = utf16_get(&src);
261
262 if (!code)
263 break;
264 if (code < 0)
265 /* Reserve space for a replacement character */
266 len += 1;
267 else if (code < 0x80)
268 len += 1;
269 else if (code < 0x800)
270 len += 2;
271 else if (code < 0x10000)
272 len += 3;
273 else
274 len += 4;
275 }
276 return len;
277 }
278
279 int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count)
280 {
281 if (!src || !dst || !*dst)
282 return -1;
283
284 for (; count && *src; --count) {
285 s32 code = utf16_get(&src);
286
287 if (code < 0)
288 code = '?';
289 utf8_put(code, dst);
290 }
291 **dst = 0;
292 return 0;
293 }
294
295 s32 utf_to_lower(const s32 code)
296 {
297 struct capitalization_table *pos = capitalization_table;
298 s32 ret = code;
299
300 if (code <= 0x7f) {
301 if (code >= 'A' && code <= 'Z')
302 ret += 0x20;
303 return ret;
304 }
305 for (; pos->upper; ++pos) {
306 if (pos->upper == code) {
307 ret = pos->lower;
308 break;
309 }
310 }
311 return ret;
312 }
313
314 s32 utf_to_upper(const s32 code)
315 {
316 struct capitalization_table *pos = capitalization_table;
317 s32 ret = code;
318
319 if (code <= 0x7f) {
320 if (code >= 'a' && code <= 'z')
321 ret -= 0x20;
322 return ret;
323 }
324 for (; pos->lower; ++pos) {
325 if (pos->lower == code) {
326 ret = pos->upper;
327 break;
328 }
329 }
330 return ret;
331 }
332
333 size_t u16_strlen(const u16 *in)
334 {
335 size_t i;
336 for (i = 0; in[i]; i++);
337 return i;
338 }
339
340 size_t u16_strnlen(const u16 *in, size_t count)
341 {
342 size_t i;
343 for (i = 0; count-- && in[i]; i++);
344 return i;
345 }
346
347 /* Convert UTF-16 to UTF-8. */
348 uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
349 {
350 uint32_t code_high = 0;
351
352 while (size--) {
353 uint32_t code = *src++;
354
355 if (code_high) {
356 if (code >= 0xDC00 && code <= 0xDFFF) {
357 /* Surrogate pair. */
358 code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
359
360 *dest++ = (code >> 18) | 0xF0;
361 *dest++ = ((code >> 12) & 0x3F) | 0x80;
362 *dest++ = ((code >> 6) & 0x3F) | 0x80;
363 *dest++ = (code & 0x3F) | 0x80;
364 } else {
365 /* Error... */
366 *dest++ = '?';
367 /* *src may be valid. Don't eat it. */
368 src--;
369 }
370
371 code_high = 0;
372 } else {
373 if (code <= 0x007F) {
374 *dest++ = code;
375 } else if (code <= 0x07FF) {
376 *dest++ = (code >> 6) | 0xC0;
377 *dest++ = (code & 0x3F) | 0x80;
378 } else if (code >= 0xD800 && code <= 0xDBFF) {
379 code_high = code;
380 continue;
381 } else if (code >= 0xDC00 && code <= 0xDFFF) {
382 /* Error... */
383 *dest++ = '?';
384 } else if (code < 0x10000) {
385 *dest++ = (code >> 12) | 0xE0;
386 *dest++ = ((code >> 6) & 0x3F) | 0x80;
387 *dest++ = (code & 0x3F) | 0x80;
388 } else {
389 *dest++ = (code >> 18) | 0xF0;
390 *dest++ = ((code >> 12) & 0x3F) | 0x80;
391 *dest++ = ((code >> 6) & 0x3F) | 0x80;
392 *dest++ = (code & 0x3F) | 0x80;
393 }
394 }
395 }
396
397 return dest;
398 }