Tom Rini | 70df9d6 | 2018-05-07 17:02:21 -0400 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 2 | /* |
| 3 | * charset conversion utils |
| 4 | * |
| 5 | * Copyright (c) 2017 Rob Clark |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 6 | */ |
| 7 | |
| 8 | #ifndef __CHARSET_H_ |
| 9 | #define __CHARSET_H_ |
| 10 | |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 11 | #include <linux/kernel.h> |
Heinrich Schuchardt | d0faa9e | 2017-10-18 18:13:06 +0200 | [diff] [blame] | 12 | #include <linux/types.h> |
| 13 | |
Heinrich Schuchardt | 1636c9e | 2017-10-09 21:09:05 +0200 | [diff] [blame] | 14 | #define MAX_UTF8_PER_UTF16 3 |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 15 | |
Heinrich Schuchardt | 12d52d2 | 2021-03-28 11:57:31 +0200 | [diff] [blame] | 16 | /* |
Heinrich Schuchardt | a9ff07b | 2021-02-27 14:08:35 +0100 | [diff] [blame] | 17 | * codepage_437 - Unicode to codepage 437 translation table |
| 18 | */ |
Janne Grunau | 3a04388 | 2024-03-16 22:50:20 +0100 | [diff] [blame] | 19 | extern const u16 codepage_437[160]; |
Heinrich Schuchardt | a9ff07b | 2021-02-27 14:08:35 +0100 | [diff] [blame] | 20 | |
| 21 | /** |
Heinrich Schuchardt | fc5f1a1 | 2018-09-12 00:05:32 +0200 | [diff] [blame] | 22 | * console_read_unicode() - read Unicode code point from console |
| 23 | * |
| 24 | * @code: pointer to store Unicode code point |
| 25 | * Return: 0 = success |
| 26 | */ |
| 27 | int console_read_unicode(s32 *code); |
| 28 | |
| 29 | /** |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 30 | * utf8_get() - get next UTF-8 code point from buffer |
| 31 | * |
| 32 | * @src: pointer to current byte, updated to point to next byte |
| 33 | * Return: code point, or 0 for end of string, or -1 if no legal |
| 34 | * code point is found. In case of an error src points to |
| 35 | * the incorrect byte. |
| 36 | */ |
| 37 | s32 utf8_get(const char **src); |
| 38 | |
| 39 | /** |
| 40 | * utf8_put() - write UTF-8 code point to buffer |
| 41 | * |
| 42 | * @code: code point |
| 43 | * @dst: pointer to destination buffer, updated to next position |
| 44 | * Return: -1 if the input parameters are invalid |
| 45 | */ |
| 46 | int utf8_put(s32 code, char **dst); |
| 47 | |
| 48 | /** |
| 49 | * utf8_utf16_strnlen() - length of a truncated utf-8 string after conversion |
| 50 | * to utf-16 |
| 51 | * |
| 52 | * @src: utf-8 string |
| 53 | * @count: maximum number of code points to convert |
Heinrich Schuchardt | 2b88d6c | 2019-05-08 19:34:48 +0200 | [diff] [blame] | 54 | * Return: length in u16 after conversion to utf-16 without the |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 55 | * trailing \0. If an invalid UTF-8 sequence is hit one |
Heinrich Schuchardt | 2b88d6c | 2019-05-08 19:34:48 +0200 | [diff] [blame] | 56 | * u16 will be reserved for a replacement character. |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 57 | */ |
| 58 | size_t utf8_utf16_strnlen(const char *src, size_t count); |
| 59 | |
| 60 | /** |
| 61 | * utf8_utf16_strlen() - length of a utf-8 string after conversion to utf-16 |
| 62 | * |
Heinrich Schuchardt | 12800e0 | 2020-05-09 08:57:42 +0200 | [diff] [blame] | 63 | * @a: utf-8 string |
Heinrich Schuchardt | 2b88d6c | 2019-05-08 19:34:48 +0200 | [diff] [blame] | 64 | * Return: length in u16 after conversion to utf-16 without the |
| 65 | * trailing \0. If an invalid UTF-8 sequence is hit one |
| 66 | * u16 will be reserved for a replacement character. |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 67 | */ |
| 68 | #define utf8_utf16_strlen(a) utf8_utf16_strnlen((a), SIZE_MAX) |
| 69 | |
| 70 | /** |
| 71 | * utf8_utf16_strncpy() - copy utf-8 string to utf-16 string |
| 72 | * |
| 73 | * @dst: destination buffer |
| 74 | * @src: source buffer |
| 75 | * @count: maximum number of code points to copy |
| 76 | * Return: -1 if the input parameters are invalid |
| 77 | */ |
| 78 | int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count); |
| 79 | |
| 80 | /** |
| 81 | * utf8_utf16_strcpy() - copy utf-8 string to utf-16 string |
| 82 | * |
Heinrich Schuchardt | 12800e0 | 2020-05-09 08:57:42 +0200 | [diff] [blame] | 83 | * @d: destination buffer |
| 84 | * @s: source buffer |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 85 | * Return: -1 if the input parameters are invalid |
| 86 | */ |
| 87 | #define utf8_utf16_strcpy(d, s) utf8_utf16_strncpy((d), (s), SIZE_MAX) |
| 88 | |
| 89 | /** |
| 90 | * utf16_get() - get next UTF-16 code point from buffer |
| 91 | * |
| 92 | * @src: pointer to current word, updated to point to next word |
| 93 | * Return: code point, or 0 for end of string, or -1 if no legal |
| 94 | * code point is found. In case of an error src points to |
| 95 | * the incorrect word. |
| 96 | */ |
| 97 | s32 utf16_get(const u16 **src); |
| 98 | |
| 99 | /** |
| 100 | * utf16_put() - write UTF-16 code point to buffer |
| 101 | * |
| 102 | * @code: code point |
| 103 | * @dst: pointer to destination buffer, updated to next position |
| 104 | * Return: -1 if the input parameters are invalid |
| 105 | */ |
| 106 | int utf16_put(s32 code, u16 **dst); |
| 107 | |
| 108 | /** |
| 109 | * utf16_strnlen() - length of a truncated utf-16 string |
| 110 | * |
| 111 | * @src: utf-16 string |
| 112 | * @count: maximum number of code points to convert |
| 113 | * Return: length in code points. If an invalid UTF-16 sequence is |
| 114 | * hit one position will be reserved for a replacement |
| 115 | * character. |
| 116 | */ |
| 117 | size_t utf16_strnlen(const u16 *src, size_t count); |
| 118 | |
| 119 | /** |
| 120 | * utf16_utf8_strnlen() - length of a truncated utf-16 string after conversion |
| 121 | * to utf-8 |
| 122 | * |
| 123 | * @src: utf-16 string |
| 124 | * @count: maximum number of code points to convert |
| 125 | * Return: length in bytes after conversion to utf-8 without the |
| 126 | * trailing \0. If an invalid UTF-16 sequence is hit one |
| 127 | * byte will be reserved for a replacement character. |
| 128 | */ |
| 129 | size_t utf16_utf8_strnlen(const u16 *src, size_t count); |
| 130 | |
| 131 | /** |
| 132 | * utf16_utf8_strlen() - length of a utf-16 string after conversion to utf-8 |
| 133 | * |
Heinrich Schuchardt | 12800e0 | 2020-05-09 08:57:42 +0200 | [diff] [blame] | 134 | * @a: utf-16 string |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 135 | * Return: length in bytes after conversion to utf-8 without the |
Heinrich Schuchardt | 2b88d6c | 2019-05-08 19:34:48 +0200 | [diff] [blame] | 136 | * trailing \0. If an invalid UTF-16 sequence is hit one |
| 137 | * byte will be reserved for a replacement character. |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 138 | */ |
| 139 | #define utf16_utf8_strlen(a) utf16_utf8_strnlen((a), SIZE_MAX) |
| 140 | |
| 141 | /** |
| 142 | * utf16_utf8_strncpy() - copy utf-16 string to utf-8 string |
| 143 | * |
| 144 | * @dst: destination buffer |
| 145 | * @src: source buffer |
| 146 | * @count: maximum number of code points to copy |
| 147 | * Return: -1 if the input parameters are invalid |
| 148 | */ |
| 149 | int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count); |
| 150 | |
| 151 | /** |
| 152 | * utf16_utf8_strcpy() - copy utf-16 string to utf-8 string |
| 153 | * |
Heinrich Schuchardt | 12800e0 | 2020-05-09 08:57:42 +0200 | [diff] [blame] | 154 | * @d: destination buffer |
| 155 | * @s: source buffer |
Heinrich Schuchardt | 97494ea | 2018-08-31 21:31:27 +0200 | [diff] [blame] | 156 | * Return: -1 if the input parameters are invalid |
| 157 | */ |
| 158 | #define utf16_utf8_strcpy(d, s) utf16_utf8_strncpy((d), (s), SIZE_MAX) |
| 159 | |
| 160 | /** |
Heinrich Schuchardt | 58ddcd3 | 2018-09-04 19:34:56 +0200 | [diff] [blame] | 161 | * utf_to_lower() - convert a Unicode letter to lower case |
| 162 | * |
| 163 | * @code: letter to convert |
| 164 | * Return: lower case letter or unchanged letter |
| 165 | */ |
| 166 | s32 utf_to_lower(const s32 code); |
| 167 | |
| 168 | /** |
| 169 | * utf_to_upper() - convert a Unicode letter to upper case |
| 170 | * |
| 171 | * @code: letter to convert |
| 172 | * Return: upper case letter or unchanged letter |
| 173 | */ |
| 174 | s32 utf_to_upper(const s32 code); |
| 175 | |
Heinrich Schuchardt | 12800e0 | 2020-05-09 08:57:42 +0200 | [diff] [blame] | 176 | /** |
Heinrich Schuchardt | 9d1e248 | 2022-12-29 14:44:03 +0100 | [diff] [blame] | 177 | * u16_strcasecmp() - compare two u16 strings case insensitively |
| 178 | * |
| 179 | * @s1: first string to compare |
| 180 | * @s2: second string to compare |
Heinrich Schuchardt | 9d1e248 | 2022-12-29 14:44:03 +0100 | [diff] [blame] | 181 | * Return: 0 if the first n u16 are the same in s1 and s2 |
| 182 | * < 0 if the first different u16 in s1 is less than the |
| 183 | * corresponding u16 in s2 |
| 184 | * > 0 if the first different u16 in s1 is greater than the |
| 185 | */ |
| 186 | int u16_strcasecmp(const u16 *s1, const u16 *s2); |
| 187 | |
| 188 | /** |
AKASHI Takahiro | 02b46b8 | 2019-09-18 10:26:29 +0900 | [diff] [blame] | 189 | * u16_strncmp() - compare two u16 string |
| 190 | * |
| 191 | * @s1: first string to compare |
| 192 | * @s2: second string to compare |
| 193 | * @n: maximum number of u16 to compare |
| 194 | * Return: 0 if the first n u16 are the same in s1 and s2 |
| 195 | * < 0 if the first different u16 in s1 is less than the |
| 196 | * corresponding u16 in s2 |
| 197 | * > 0 if the first different u16 in s1 is greater than the |
| 198 | * corresponding u16 in s2 |
| 199 | */ |
| 200 | int u16_strncmp(const u16 *s1, const u16 *s2, size_t n); |
Heinrich Schuchardt | 12800e0 | 2020-05-09 08:57:42 +0200 | [diff] [blame] | 201 | |
| 202 | /** |
| 203 | * u16_strcmp() - compare two u16 string |
| 204 | * |
| 205 | * @s1: first string to compare |
| 206 | * @s2: second string to compare |
| 207 | * Return: 0 if the first n u16 are the same in s1 and s2 |
| 208 | * < 0 if the first different u16 in s1 is less than the |
| 209 | * corresponding u16 in s2 |
| 210 | * > 0 if the first different u16 in s1 is greater than the |
| 211 | * corresponding u16 in s2 |
| 212 | */ |
AKASHI Takahiro | 02b46b8 | 2019-09-18 10:26:29 +0900 | [diff] [blame] | 213 | #define u16_strcmp(s1, s2) u16_strncmp((s1), (s2), SIZE_MAX) |
| 214 | |
Heinrich Schuchardt | 58ddcd3 | 2018-09-04 19:34:56 +0200 | [diff] [blame] | 215 | /** |
Sughosh Ganu | 989fc14 | 2020-05-06 22:12:41 +0300 | [diff] [blame] | 216 | * u16_strsize() - count size of u16 string in bytes including the null |
| 217 | * character |
| 218 | * |
| 219 | * Counts the number of bytes occupied by a u16 string |
| 220 | * |
| 221 | * @in: null terminated u16 string |
| 222 | * Return: bytes in a u16 string |
Sughosh Ganu | 989fc14 | 2020-05-06 22:12:41 +0300 | [diff] [blame] | 223 | */ |
| 224 | size_t u16_strsize(const void *in); |
| 225 | |
| 226 | /** |
Heinrich Schuchardt | 38ada61 | 2020-10-30 12:14:16 +0100 | [diff] [blame] | 227 | * u16_strnlen() - count non-zero words |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 228 | * |
Heinrich Schuchardt | 597f8f7 | 2018-08-31 21:31:26 +0200 | [diff] [blame] | 229 | * This function matches wscnlen_s() if the -fshort-wchar compiler flag is set. |
| 230 | * In the EFI context we explicitly need a function handling u16 strings. |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 231 | * |
Heinrich Schuchardt | 597f8f7 | 2018-08-31 21:31:26 +0200 | [diff] [blame] | 232 | * @in: null terminated u16 string |
| 233 | * @count: maximum number of words to count |
Heinrich Schuchardt | 12800e0 | 2020-05-09 08:57:42 +0200 | [diff] [blame] | 234 | * Return: number of non-zero words. |
Heinrich Schuchardt | 597f8f7 | 2018-08-31 21:31:26 +0200 | [diff] [blame] | 235 | * This is not the number of utf-16 letters! |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 236 | */ |
Heinrich Schuchardt | 597f8f7 | 2018-08-31 21:31:26 +0200 | [diff] [blame] | 237 | size_t u16_strnlen(const u16 *in, size_t count); |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 238 | |
| 239 | /** |
Heinrich Schuchardt | c054760 | 2022-04-02 11:46:58 +0200 | [diff] [blame] | 240 | * u16_strlen - count non-zero words |
| 241 | * |
| 242 | * This function matches wsclen() if the -fshort-wchar compiler flag is set. |
| 243 | * In the EFI context we explicitly need a function handling u16 strings. |
| 244 | * |
| 245 | * @in: null terminated u16 string |
| 246 | * Return: number of non-zero words. |
| 247 | * This is not the number of utf-16 letters! |
| 248 | */ |
| 249 | size_t u16_strlen(const void *in); |
| 250 | |
| 251 | #define u16_strlen(in) u16_strnlen(in, SIZE_MAX) |
| 252 | |
| 253 | /** |
Akashi, Takahiro | 269a8e2 | 2018-12-14 19:10:38 +0900 | [diff] [blame] | 254 | * u16_strcpy() - copy u16 string |
| 255 | * |
| 256 | * Copy u16 string pointed to by src, including terminating null word, to |
| 257 | * the buffer pointed to by dest. |
| 258 | * |
| 259 | * @dest: destination buffer |
| 260 | * @src: source buffer (null terminated) |
| 261 | * Return: 'dest' address |
| 262 | */ |
| 263 | u16 *u16_strcpy(u16 *dest, const u16 *src); |
| 264 | |
| 265 | /** |
| 266 | * u16_strdup() - duplicate u16 string |
| 267 | * |
| 268 | * Copy u16 string pointed to by src, including terminating null word, to a |
| 269 | * newly allocated buffer. |
| 270 | * |
| 271 | * @src: source buffer (null terminated) |
| 272 | * Return: allocated new buffer on success, NULL on failure |
| 273 | */ |
Heinrich Schuchardt | d1df23b | 2019-07-14 17:28:49 +0200 | [diff] [blame] | 274 | u16 *u16_strdup(const void *src); |
Akashi, Takahiro | 269a8e2 | 2018-12-14 19:10:38 +0900 | [diff] [blame] | 275 | |
| 276 | /** |
Masahisa Kojima | f242db0 | 2022-04-28 17:09:34 +0900 | [diff] [blame] | 277 | * u16_strlcat() - Append a length-limited, %NUL-terminated string to another |
| 278 | * |
| 279 | * Append the source string @src to the destination string @dest, overwriting |
| 280 | * null word at the end of @dest adding a terminating null word. |
| 281 | * |
| 282 | * @dest: zero terminated u16 destination string |
| 283 | * @src: zero terminated u16 source string |
| 284 | * @count: size of buffer in u16 words including taling 0x0000 |
| 285 | * Return: required size including trailing 0x0000 in u16 words |
| 286 | * If return value >= count, truncation occurred. |
| 287 | */ |
Masahisa Kojima | 0caeff5 | 2022-05-16 20:00:42 +0900 | [diff] [blame] | 288 | size_t u16_strlcat(u16 *dest, const u16 *src, size_t count); |
Masahisa Kojima | f242db0 | 2022-04-28 17:09:34 +0900 | [diff] [blame] | 289 | |
| 290 | /** |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 291 | * utf16_to_utf8() - Convert an utf16 string to utf8 |
| 292 | * |
| 293 | * Converts 'size' characters of the utf16 string 'src' to utf8 |
| 294 | * written to the 'dest' buffer. |
| 295 | * |
Heinrich Schuchardt | 1636c9e | 2017-10-09 21:09:05 +0200 | [diff] [blame] | 296 | * NOTE that a single utf16 character can generate up to 3 utf8 |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 297 | * characters. See MAX_UTF8_PER_UTF16. |
| 298 | * |
Heinrich Schuchardt | 12800e0 | 2020-05-09 08:57:42 +0200 | [diff] [blame] | 299 | * @dest: the destination buffer to write the utf8 characters |
| 300 | * @src: the source utf16 string |
| 301 | * @size: the number of utf16 characters to convert |
| 302 | * Return: the pointer to the first unwritten byte in 'dest' |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 303 | */ |
| 304 | uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size); |
| 305 | |
Heinrich Schuchardt | 91fb089 | 2021-02-27 14:08:36 +0100 | [diff] [blame] | 306 | /** |
| 307 | * utf_to_cp() - translate Unicode code point to 8bit codepage |
| 308 | * |
| 309 | * Codepoints that do not exist in the codepage are rendered as question mark. |
| 310 | * |
| 311 | * @c: pointer to Unicode code point to be translated |
| 312 | * @codepage: Unicode to codepage translation table |
| 313 | * Return: 0 on success, -ENOENT if codepoint cannot be translated |
| 314 | */ |
| 315 | int utf_to_cp(s32 *c, const u16 *codepage); |
| 316 | |
Heinrich Schuchardt | 6aa77ac | 2021-02-27 14:08:38 +0100 | [diff] [blame] | 317 | /** |
| 318 | * utf8_to_cp437_stream() - convert UTF-8 stream to codepage 437 |
| 319 | * |
| 320 | * @c: next UTF-8 character to convert |
| 321 | * @buffer: buffer, at least 5 characters |
| 322 | * Return: next codepage 437 character or 0 |
| 323 | */ |
| 324 | int utf8_to_cp437_stream(u8 c, char *buffer); |
| 325 | |
| 326 | /** |
Janne Grunau | 153a8a9 | 2024-02-10 13:46:39 +0100 | [diff] [blame] | 327 | * utf8_to_utf32_stream() - convert UTF-8 byte stream to Unicode code points |
| 328 | * |
| 329 | * The function is called for each byte @c in a UTF-8 stream. The byte is |
| 330 | * appended to the temporary storage @buffer until the UTF-8 stream in |
| 331 | * @buffer describes a Unicode code point. |
| 332 | * |
| 333 | * When a new code point has been decoded it is returned and buffer[0] is |
| 334 | * set to '\0', otherwise the return value is 0. |
| 335 | * |
| 336 | * The buffer must be at least 5 characters long. Before the first function |
| 337 | * invocation buffer[0] must be set to '\0'." |
Heinrich Schuchardt | 6aa77ac | 2021-02-27 14:08:38 +0100 | [diff] [blame] | 338 | * |
| 339 | * @c: next UTF-8 character to convert |
| 340 | * @buffer: buffer, at least 5 characters |
Janne Grunau | 153a8a9 | 2024-02-10 13:46:39 +0100 | [diff] [blame] | 341 | * Return: Unicode code point or 0 |
Heinrich Schuchardt | 6aa77ac | 2021-02-27 14:08:38 +0100 | [diff] [blame] | 342 | */ |
| 343 | int utf8_to_utf32_stream(u8 c, char *buffer); |
| 344 | |
Rob Clark | 0d138cf | 2017-09-09 06:47:40 -0400 | [diff] [blame] | 345 | #endif /* __CHARSET_H_ */ |