efi_loader: carve out utf_to_cp()
[platform/kernel/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 <cp437.h>
12 #include <efi_loader.h>
13 #include <errno.h>
14 #include <malloc.h>
15
16 /**
17  * codepage_437 - Unicode to codepage 437 translation table
18  */
19 const u16 codepage_437[128] = CP437;
20
21 static struct capitalization_table capitalization_table[] =
22 #ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
23         UNICODE_CAPITALIZATION_TABLE;
24 #elif CONFIG_FAT_DEFAULT_CODEPAGE == 1250
25         CP1250_CAPITALIZATION_TABLE;
26 #else
27         CP437_CAPITALIZATION_TABLE;
28 #endif
29
30 /**
31  * get_code() - read Unicode code point from UTF-8 stream
32  *
33  * @read_u8:    - stream reader
34  * @src:        - string buffer passed to stream reader, optional
35  * Return:      - Unicode code point
36  */
37 static int get_code(u8 (*read_u8)(void *data), void *data)
38 {
39         s32 ch = 0;
40
41         ch = read_u8(data);
42         if (!ch)
43                 return 0;
44         if (ch >= 0xc2 && ch <= 0xf4) {
45                 int code = 0;
46
47                 if (ch >= 0xe0) {
48                         if (ch >= 0xf0) {
49                                 /* 0xf0 - 0xf4 */
50                                 ch &= 0x07;
51                                 code = ch << 18;
52                                 ch = read_u8(data);
53                                 if (ch < 0x80 || ch > 0xbf)
54                                         goto error;
55                                 ch &= 0x3f;
56                         } else {
57                                 /* 0xe0 - 0xef */
58                                 ch &= 0x0f;
59                         }
60                         code += ch << 12;
61                         if ((code >= 0xD800 && code <= 0xDFFF) ||
62                             code >= 0x110000)
63                                 goto error;
64                         ch = read_u8(data);
65                         if (ch < 0x80 || ch > 0xbf)
66                                 goto error;
67                 }
68                 /* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
69                 ch &= 0x3f;
70                 code += ch << 6;
71                 ch = read_u8(data);
72                 if (ch < 0x80 || ch > 0xbf)
73                         goto error;
74                 ch &= 0x3f;
75                 ch += code;
76         } else if (ch >= 0x80) {
77                 goto error;
78         }
79         return ch;
80 error:
81         return '?';
82 }
83
84 /**
85  * read_string() - read byte from character string
86  *
87  * @data:       - pointer to string
88  * Return:      - byte read
89  *
90  * The string pointer is incremented if it does not point to '\0'.
91  */
92 static u8 read_string(void *data)
93
94 {
95         const char **src = (const char **)data;
96         u8 c;
97
98         if (!src || !*src || !**src)
99                 return 0;
100         c = **src;
101         ++*src;
102         return c;
103 }
104
105 /**
106  * read_console() - read byte from console
107  *
108  * @data        - not used, needed to match interface
109  * Return:      - byte read or 0 on error
110  */
111 static u8 read_console(void *data)
112 {
113         int ch;
114
115         ch = getchar();
116         if (ch < 0)
117                 ch = 0;
118         return ch;
119 }
120
121 int console_read_unicode(s32 *code)
122 {
123         if (!tstc()) {
124                 /* No input available */
125                 return 1;
126         }
127
128         /* Read Unicode code */
129         *code = get_code(read_console, NULL);
130         return 0;
131 }
132
133 s32 utf8_get(const char **src)
134 {
135         return get_code(read_string, src);
136 }
137
138 int utf8_put(s32 code, char **dst)
139 {
140         if (!dst || !*dst)
141                 return -1;
142         if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
143                 return -1;
144         if (code <= 0x007F) {
145                 **dst = code;
146         } else {
147                 if (code <= 0x07FF) {
148                         **dst = code >> 6 | 0xC0;
149                 } else {
150                         if (code < 0x10000) {
151                                 **dst = code >> 12 | 0xE0;
152                         } else {
153                                 **dst = code >> 18 | 0xF0;
154                                 ++*dst;
155                                 **dst = (code >> 12 & 0x3F) | 0x80;
156                         }
157                         ++*dst;
158                         **dst = (code >> 6 & 0x3F) | 0x80;
159                 }
160                 ++*dst;
161                 **dst = (code & 0x3F) | 0x80;
162         }
163         ++*dst;
164         return 0;
165 }
166
167 size_t utf8_utf16_strnlen(const char *src, size_t count)
168 {
169         size_t len = 0;
170
171         for (; *src && count; --count)  {
172                 s32 code = utf8_get(&src);
173
174                 if (!code)
175                         break;
176                 if (code < 0) {
177                         /* Reserve space for a replacement character */
178                         len += 1;
179                 } else if (code < 0x10000) {
180                         len += 1;
181                 } else {
182                         len += 2;
183                 }
184         }
185         return len;
186 }
187
188 int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count)
189 {
190         if (!src || !dst || !*dst)
191                 return -1;
192
193         for (; count && *src; --count) {
194                 s32 code = utf8_get(&src);
195
196                 if (code < 0)
197                         code = '?';
198                 utf16_put(code, dst);
199         }
200         **dst = 0;
201         return 0;
202 }
203
204 s32 utf16_get(const u16 **src)
205 {
206         s32 code, code2;
207
208         if (!src || !*src)
209                 return -1;
210         if (!**src)
211                 return 0;
212         code = **src;
213         ++*src;
214         if (code >= 0xDC00 && code <= 0xDFFF)
215                 return -1;
216         if (code >= 0xD800 && code <= 0xDBFF) {
217                 if (!**src)
218                         return -1;
219                 code &= 0x3ff;
220                 code <<= 10;
221                 code += 0x10000;
222                 code2 = **src;
223                 ++*src;
224                 if (code2 <= 0xDC00 || code2 >= 0xDFFF)
225                         return -1;
226                 code2 &= 0x3ff;
227                 code += code2;
228         }
229         return code;
230 }
231
232 int utf16_put(s32 code, u16 **dst)
233 {
234         if (!dst || !*dst)
235                 return -1;
236         if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
237                 return -1;
238         if (code < 0x10000) {
239                 **dst = code;
240         } else {
241                 code -= 0x10000;
242                 **dst = code >> 10 | 0xD800;
243                 ++*dst;
244                 **dst = (code & 0x3ff) | 0xDC00;
245         }
246         ++*dst;
247         return 0;
248 }
249
250 size_t utf16_strnlen(const u16 *src, size_t count)
251 {
252         size_t len = 0;
253
254         for (; *src && count; --count)  {
255                 s32 code = utf16_get(&src);
256
257                 if (!code)
258                         break;
259                 /*
260                  * In case of an illegal sequence still reserve space for a
261                  * replacement character.
262                  */
263                 ++len;
264         }
265         return len;
266 }
267
268 size_t utf16_utf8_strnlen(const u16 *src, size_t count)
269 {
270         size_t len = 0;
271
272         for (; *src && count; --count)  {
273                 s32 code = utf16_get(&src);
274
275                 if (!code)
276                         break;
277                 if (code < 0)
278                         /* Reserve space for a replacement character */
279                         len += 1;
280                 else if (code < 0x80)
281                         len += 1;
282                 else if (code < 0x800)
283                         len += 2;
284                 else if (code < 0x10000)
285                         len += 3;
286                 else
287                         len += 4;
288         }
289         return len;
290 }
291
292 int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count)
293 {
294         if (!src || !dst || !*dst)
295                 return -1;
296
297         for (; count && *src; --count) {
298                 s32 code = utf16_get(&src);
299
300                 if (code < 0)
301                         code = '?';
302                 utf8_put(code, dst);
303         }
304         **dst = 0;
305         return 0;
306 }
307
308 s32 utf_to_lower(const s32 code)
309 {
310         struct capitalization_table *pos = capitalization_table;
311         s32 ret = code;
312
313         if (code <= 0x7f) {
314                 if (code >= 'A' && code <= 'Z')
315                         ret += 0x20;
316                 return ret;
317         }
318         for (; pos->upper; ++pos) {
319                 if (pos->upper == code) {
320                         ret = pos->lower;
321                         break;
322                 }
323         }
324         return ret;
325 }
326
327 s32 utf_to_upper(const s32 code)
328 {
329         struct capitalization_table *pos = capitalization_table;
330         s32 ret = code;
331
332         if (code <= 0x7f) {
333                 if (code >= 'a' && code <= 'z')
334                         ret -= 0x20;
335                 return ret;
336         }
337         for (; pos->lower; ++pos) {
338                 if (pos->lower == code) {
339                         ret = pos->upper;
340                         break;
341                 }
342         }
343         return ret;
344 }
345
346 /*
347  * u16_strncmp() - compare two u16 string
348  *
349  * @s1:         first string to compare
350  * @s2:         second string to compare
351  * @n:          maximum number of u16 to compare
352  * Return:      0  if the first n u16 are the same in s1 and s2
353  *              < 0 if the first different u16 in s1 is less than the
354  *              corresponding u16 in s2
355  *              > 0 if the first different u16 in s1 is greater than the
356  *              corresponding u16 in s2
357  */
358 int u16_strncmp(const u16 *s1, const u16 *s2, size_t n)
359 {
360         int ret = 0;
361
362         for (; n; --n, ++s1, ++s2) {
363                 ret = *s1 - *s2;
364                 if (ret || !*s1)
365                         break;
366         }
367
368         return ret;
369 }
370
371 size_t u16_strlen(const void *in)
372 {
373         const char *pos = in;
374         size_t ret;
375
376         for (; pos[0] || pos[1]; pos += 2)
377                 ;
378         ret = pos - (char *)in;
379         ret >>= 1;
380         return ret;
381 }
382
383 size_t __efi_runtime u16_strnlen(const u16 *in, size_t count)
384 {
385         size_t i;
386         for (i = 0; count-- && in[i]; i++);
387         return i;
388 }
389
390 size_t u16_strsize(const void *in)
391 {
392         return (u16_strlen(in) + 1) * sizeof(u16);
393 }
394
395 u16 *u16_strcpy(u16 *dest, const u16 *src)
396 {
397         u16 *tmp = dest;
398
399         for (;; dest++, src++) {
400                 *dest = *src;
401                 if (!*src)
402                         break;
403         }
404
405         return tmp;
406 }
407
408 u16 *u16_strdup(const void *src)
409 {
410         u16 *new;
411         size_t len;
412
413         if (!src)
414                 return NULL;
415         len = (u16_strlen(src) + 1) * sizeof(u16);
416         new = malloc(len);
417         if (!new)
418                 return NULL;
419         memcpy(new, src, len);
420
421         return new;
422 }
423
424 /* Convert UTF-16 to UTF-8.  */
425 uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
426 {
427         uint32_t code_high = 0;
428
429         while (size--) {
430                 uint32_t code = *src++;
431
432                 if (code_high) {
433                         if (code >= 0xDC00 && code <= 0xDFFF) {
434                                 /* Surrogate pair.  */
435                                 code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
436
437                                 *dest++ = (code >> 18) | 0xF0;
438                                 *dest++ = ((code >> 12) & 0x3F) | 0x80;
439                                 *dest++ = ((code >> 6) & 0x3F) | 0x80;
440                                 *dest++ = (code & 0x3F) | 0x80;
441                         } else {
442                                 /* Error...  */
443                                 *dest++ = '?';
444                                 /* *src may be valid. Don't eat it.  */
445                                 src--;
446                         }
447
448                         code_high = 0;
449                 } else {
450                         if (code <= 0x007F) {
451                                 *dest++ = code;
452                         } else if (code <= 0x07FF) {
453                                 *dest++ = (code >> 6) | 0xC0;
454                                 *dest++ = (code & 0x3F) | 0x80;
455                         } else if (code >= 0xD800 && code <= 0xDBFF) {
456                                 code_high = code;
457                                 continue;
458                         } else if (code >= 0xDC00 && code <= 0xDFFF) {
459                                 /* Error... */
460                                 *dest++ = '?';
461                         } else if (code < 0x10000) {
462                                 *dest++ = (code >> 12) | 0xE0;
463                                 *dest++ = ((code >> 6) & 0x3F) | 0x80;
464                                 *dest++ = (code & 0x3F) | 0x80;
465                         } else {
466                                 *dest++ = (code >> 18) | 0xF0;
467                                 *dest++ = ((code >> 12) & 0x3F) | 0x80;
468                                 *dest++ = ((code >> 6) & 0x3F) | 0x80;
469                                 *dest++ = (code & 0x3F) | 0x80;
470                         }
471                 }
472         }
473
474         return dest;
475 }
476
477 /**
478  * utf_to_cp() - translate Unicode code point to 8bit codepage
479  *
480  * Codepoints that do not exist in the codepage are rendered as question mark.
481  *
482  * @c:          pointer to Unicode code point to be translated
483  * @codepage:   Unicode to codepage translation table
484  * Return:      0 on success, -ENOENT if codepoint cannot be translated
485  */
486 int utf_to_cp(s32 *c, const u16 *codepage)
487 {
488         if (*c >= 0x80) {
489                 int j;
490
491                 /* Look up codepage translation */
492                 for (j = 0; j < 0x80; ++j) {
493                         if (*c == codepage[j]) {
494                                 *c = j + 0x80;
495                                 return 0;
496                         }
497                 }
498                 *c = '?';
499                 return -ENOENT;
500         }
501         return 0;
502 }