├── .gitignore ├── tests ├── test.c └── test.sh ├── LICENSE └── frog_utf.h /.gitignore: -------------------------------------------------------------------------------- 1 | tests/test_builds/* 2 | -------------------------------------------------------------------------------- /tests/test.c: -------------------------------------------------------------------------------- 1 | #include "../frog_utf.h" 2 | 3 | #include 4 | 5 | int main(void) 6 | { 7 | frog_uchar32_t my_string_32[128]; 8 | frog_uchar16_t my_string_16[128]; 9 | frog_uchar8_t my_string_8_1[128]; 10 | frog_uchar8_t my_string_8_2[128]; 11 | 12 | const frog_uchar8_t test_string[] = 13 | { 14 | 0x54,0x68,0x65,0xe2,0x9c,0xa8,0xe3,0x81,0x8b,0xe3,0x81,0x88,0xe3,0x82, 15 | 0x8b,0xe3,0x82,0xab,0xe3,0x82,0xa8,0xe3,0x83,0xab,0xe8,0x9b,0x99,0xf0, 16 | 0x9f,0x90,0xb8,0xf0,0x9f,0x90,0xb8,0xf0,0x9f,0x90,0xb8,0xf0,0x9f,0x90, 17 | 0xb8,0xf0,0x9f,0x90,0xb8,0xf0,0x9f,0x90,0xb8,0x00, 18 | }; 19 | 20 | frog_str_gen_to_gen(my_string_8_1, sizeof(frog_uchar8_t), 128, test_string, sizeof(frog_uchar8_t), 128); 21 | 22 | frog_str_utf8_to_utf16(my_string_16, 128, my_string_8_1, frog_strlen_utf8(my_string_8_1) + 1); 23 | frog_str_utf16_to_utf32(my_string_32, 128, my_string_16, frog_strlen_utf16(my_string_16) + 1); 24 | frog_str_utf32_to_utf8(my_string_8_2, 128, my_string_32, frog_strlen_utf32(my_string_32) + 1); 25 | 26 | printf("%s\n", my_string_8_2); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tests/test.sh: -------------------------------------------------------------------------------- 1 | mkdir -p test_builds 2 | 3 | export GCC_ARGS="-Wall -Wextra -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wdeclaration-after-statement -pedantic" 4 | 5 | gcc test.c $GCC_ARGS -std=c89 -o test_builds/test_gcc_c89 6 | gcc test.c $GCC_ARGS -std=gnu89 -o test_builds/test_gcc_gnu89 7 | gcc test.c $GCC_ARGS -std=c99 -o test_builds/test_gcc_c99 8 | gcc test.c $GCC_ARGS -std=gnu99 -o test_builds/test_gcc_gnu99 9 | gcc test.c $GCC_ARGS -std=c11 -o test_builds/test_gcc_c11 10 | gcc test.c $GCC_ARGS -std=gnu11 -o test_builds/test_gcc_gnu11 11 | gcc test.c $GCC_ARGS -std=c17 -o test_builds/test_gcc_c17 12 | gcc test.c $GCC_ARGS -std=gnu17 -o test_builds/test_gcc_gnu17 13 | 14 | clang test.c $GCC_ARGS -std=c89 -o test_builds/test_clang_c89 15 | clang test.c $GCC_ARGS -std=gnu89 -o test_builds/test_clang_gnu89 16 | clang test.c $GCC_ARGS -std=c99 -o test_builds/test_clang_c99 17 | clang test.c $GCC_ARGS -std=gnu99 -o test_builds/test_clang_gnu99 18 | clang test.c $GCC_ARGS -std=c11 -o test_builds/test_clang_c11 19 | clang test.c $GCC_ARGS -std=gnu11 -o test_builds/test_clang_gnu11 20 | clang test.c $GCC_ARGS -std=c17 -o test_builds/test_clang_c17 21 | clang test.c $GCC_ARGS -std=gnu17 -o test_builds/test_clang_gnu17 22 | 23 | tcc test.c -o test_builds/test_tcc 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Joshua Ashton 2 | 3 | zlib/libpng license 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | – The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 18 | – Altered source versions must be plainly marked as such, and must not 19 | be misrepresented as being the original software. 20 | 21 | – This notice may not be removed or altered from any source distribution. 22 | 23 | This code is based on code taken from the DXVK project available at 24 | https://github.com/doitsujin/dxvk 25 | under the following license: 26 | 27 | Copyright (c) 2017 Philip Rebohle 28 | Copyright (c) 2019 Joshua Ashton 29 | 30 | zlib/libpng license 31 | 32 | This software is provided 'as-is', without any express or implied 33 | warranty. In no event will the authors be held liable for any damages 34 | arising from the use of this software. 35 | 36 | Permission is granted to anyone to use this software for any purpose, 37 | including commercial applications, and to alter it and redistribute it 38 | freely, subject to the following restrictions: 39 | 40 | – The origin of this software must not be misrepresented; you must not 41 | claim that you wrote the original software. If you use this software 42 | in a product, an acknowledgment in the product documentation would be 43 | appreciated but is not required. 44 | 45 | – Altered source versions must be plainly marked as such, and must not 46 | be misrepresented as being the original software. 47 | 48 | – This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /frog_utf.h: -------------------------------------------------------------------------------- 1 | #ifndef FROG_UTF8_H 2 | #define FROG_UTF8_H 3 | 4 | /* FROG UTF 5 | * 6 | * Single file C header for UTF-x-to-y conversions + helpers. 7 | * Licensed under zlib/libpng license (based on some DXVK code). 8 | * 9 | * Provides methods for conversions from any UTF-x to any UTF-y + strlen. 10 | * 11 | * This library has two modes, entirely static inline functions (recommended, default) 12 | * or single C-file include with FROG_UTF_IMPLEMENTATION + prototypes with FROG_UTF_DISABLE_INLINE. 13 | */ 14 | 15 | #include 16 | #include 17 | 18 | typedef uint8_t frog_uchar8_t; 19 | typedef uint16_t frog_uchar16_t; 20 | typedef uint32_t frog_uchar32_t; 21 | 22 | #if !defined(__has_builtin) 23 | # define __has_builtin(x) 0 24 | #endif 25 | 26 | #if defined(HAVE___BUILTIN_EXPECT) || __has_builtin(__builtin_expect) 27 | # define frog_utf_likely(x) __builtin_expect(!!(x),1) 28 | # define frog_utf_unlikely(x) __builtin_expect(!!(x),0) 29 | #else 30 | # define frog_utf_likely(x) (x) 31 | # define frog_utf_unlikely(x) (x) 32 | #endif 33 | 34 | #if defined(HAVE___BUILTIN_UNREACHABLE) || __has_builtin(__builtin_unreachable) 35 | # define frog_utf_unreachable() __builtin_unreachable() 36 | #elif defined(_MSC_VER) 37 | # define frog_utf_unreachable() __assume(0) 38 | #else 39 | # define frog_utf_unreachable() do { } while (0) 40 | #endif 41 | 42 | #if defined(__cplusplus) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) 43 | # define frog_utf_inline inline 44 | #elif defined(_MSC_VER) 45 | # define frog_utf_inline __inline 46 | #elif defined(__GNUC__) || defined(__clang__) 47 | # define frog_utf_inline __inline__ 48 | #else 49 | # define frog_utf_inline 50 | # ifndef FROG_UTF_DISABLE_INLINE 51 | # error "Frog UTF: Platform does not support inline but FROG_UTF_DISABLE_INLINE is not defined." 52 | # endif 53 | #endif 54 | 55 | #if !defined(FROG_UTF_DISABLE_INLINE) 56 | # define frog_utf_func static frog_utf_inline 57 | # define frog_utf_inline_func static frog_utf_inline 58 | # ifndef FROG_UTF_IMPLEMENTATION 59 | # define FROG_UTF_IMPLEMENTATION 60 | # endif 61 | #else 62 | # define frog_utf_func 63 | # define frog_utf_inline_func static frog_utf_inline 64 | #endif 65 | 66 | #ifdef __cplusplus 67 | extern "C" { 68 | #endif 69 | 70 | #if !defined(FROG_UTF_IMPLEMENTATION) 71 | /* Function prototypes for include when not using inline mode. 72 | * In this mode, no implementation details such as tzcnt or gen are exposed. */ 73 | frog_utf_func size_t frog_strlen_utf8(const frog_uchar8_t *str); 74 | 75 | frog_utf_func size_t frog_strlen_utf16(const frog_uchar16_t *str); 76 | 77 | frog_utf_func size_t frog_strlen_utf32(const frog_uchar32_t *str); 78 | 79 | frog_utf_func const frog_uchar8_t *frog_decode_utf8( 80 | const frog_uchar8_t *begin, 81 | const frog_uchar8_t *end, 82 | frog_uchar32_t *out_char); 83 | 84 | frog_utf_func const frog_uchar16_t *frog_decode_utf16( 85 | const frog_uchar16_t *begin, 86 | const frog_uchar16_t *end, 87 | frog_uchar32_t *out_char); 88 | 89 | frog_utf_func const frog_uchar32_t *frog_decode_utf32( 90 | const frog_uchar32_t *begin, 91 | const frog_uchar32_t *end, 92 | frog_uchar32_t *out_char); 93 | 94 | frog_utf_func size_t frog_encode_utf8( 95 | frog_uchar8_t* begin, 96 | frog_uchar8_t* end, 97 | frog_uchar32_t ch); 98 | 99 | frog_utf_func size_t frog_encode_utf16( 100 | frog_uchar16_t* begin, 101 | frog_uchar16_t* end, 102 | frog_uchar32_t ch); 103 | 104 | frog_utf_func size_t frog_encode_utf32( 105 | frog_uchar32_t* begin, 106 | frog_uchar32_t* end, 107 | frog_uchar32_t ch); 108 | 109 | frog_utf_func size_t frog_str_utf8_to_utf16( 110 | frog_uchar16_t *dst_begin, 111 | size_t dst_length, 112 | const frog_uchar8_t *src_begin, 113 | size_t src_length); 114 | 115 | frog_utf_func size_t frog_str_utf8_to_utf32( 116 | frog_uchar32_t *dst_begin, 117 | size_t dst_length, 118 | const frog_uchar8_t *src_begin, 119 | size_t src_length); 120 | 121 | frog_utf_func size_t frog_str_utf16_to_utf8( 122 | frog_uchar8_t *dst_begin, 123 | size_t dst_length, 124 | const frog_uchar16_t *src_begin, 125 | size_t src_length); 126 | 127 | frog_utf_func size_t frog_str_utf16_to_utf32( 128 | frog_uchar32_t *dst_begin, 129 | size_t dst_length, 130 | const frog_uchar16_t *src_begin, 131 | size_t src_length); 132 | 133 | frog_utf_func size_t frog_str_utf32_to_utf8( 134 | frog_uchar8_t *dst_begin, 135 | size_t dst_length, 136 | const frog_uchar32_t *src_begin, 137 | size_t src_length); 138 | 139 | frog_utf_func size_t frog_str_utf32_to_utf16( 140 | frog_uchar16_t *dst_begin, 141 | size_t dst_length, 142 | const frog_uchar32_t *src_begin, 143 | size_t src_length); 144 | #else 145 | /* Inline this even if not using inline functions if possible. */ 146 | frog_utf_inline_func uint32_t frog_utf_lzcnt(uint32_t n) 147 | { 148 | #if (defined(_MSC_VER) && !defined(__clang__)) || defined(__LZCNT__) 149 | return _lzcnt_u32(n); 150 | #elif defined(__GNUC__) || defined(__clang__) 151 | return n != 0 ? __builtin_clz(n) : 32; 152 | #else 153 | uint32_t r = 0; 154 | 155 | if (n == 0) return 32; 156 | 157 | if (n <= 0x0000FFFF) { r += 16; n <<= 16; } 158 | if (n <= 0x00FFFFFF) { r += 8; n <<= 8; } 159 | if (n <= 0x0FFFFFFF) { r += 4; n <<= 4; } 160 | if (n <= 0x3FFFFFFF) { r += 2; n <<= 2; } 161 | if (n <= 0x7FFFFFFF) { r += 1; n <<= 1; } 162 | 163 | return r; 164 | #endif 165 | } 166 | 167 | #define FROG_UTF32_REPLACEMENT_CHARACTER ((frog_uchar32_t)0x0000FFFD) 168 | 169 | frog_utf_func size_t frog_strlen_utf8(const frog_uchar8_t *str) 170 | { 171 | size_t length = 0; 172 | while (*str++) length++; 173 | return length; 174 | } 175 | 176 | frog_utf_func size_t frog_strlen_utf16(const frog_uchar16_t *str) 177 | { 178 | size_t length = 0; 179 | while (*str++) length++; 180 | return length; 181 | } 182 | 183 | frog_utf_func size_t frog_strlen_utf32(const frog_uchar32_t *str) 184 | { 185 | size_t length = 0; 186 | while (*str++) length++; 187 | return length; 188 | } 189 | 190 | frog_utf_func const frog_uchar8_t *frog_decode_utf8( 191 | const frog_uchar8_t *begin, 192 | const frog_uchar8_t *end, 193 | frog_uchar32_t *out_char) 194 | { 195 | frog_uchar32_t first = (frog_uchar32_t)begin[0]; 196 | 197 | if (frog_utf_likely(first < 0x80)) 198 | { 199 | /* Basic ASCII character */ 200 | *out_char = first; 201 | return begin + 1; 202 | } 203 | else if (frog_utf_unlikely(first < 0xC0)) 204 | { 205 | /* Character starts with a continuation byte, 206 | * just skip until we find the next valid prefix */ 207 | while ((begin < end) && (((*begin) & 0xC0) == 0x80)) 208 | begin += 1; 209 | 210 | *out_char = FROG_UTF32_REPLACEMENT_CHARACTER; 211 | return begin; 212 | } 213 | else 214 | { 215 | /* The number of leading 1 bits in the first byte 216 | * determines the length of this character */ 217 | size_t length = frog_utf_lzcnt((~first) << 24); 218 | 219 | if (frog_utf_unlikely(begin + length > end)) 220 | { 221 | *out_char = FROG_UTF32_REPLACEMENT_CHARACTER; 222 | return end; 223 | } 224 | 225 | if (first < 0xE0) 226 | { 227 | *out_char = (((frog_uchar32_t)(begin[0]) & 0x1F) << 6) 228 | | (((frog_uchar32_t)(begin[1]) & 0x3F)); 229 | } 230 | else if (first < 0xF0) 231 | { 232 | *out_char = (((frog_uchar32_t)(begin[0]) & 0x0F) << 12) 233 | | (((frog_uchar32_t)(begin[1]) & 0x3F) << 6) 234 | | (((frog_uchar32_t)(begin[2]) & 0x3F)); 235 | } 236 | else if (first < 0xF8) 237 | { 238 | *out_char = (((frog_uchar32_t)(begin[0]) & 0x07) << 18) 239 | | (((frog_uchar32_t)(begin[1]) & 0x3F) << 12) 240 | | (((frog_uchar32_t)(begin[2]) & 0x3F) << 6) 241 | | (((frog_uchar32_t)(begin[3]) & 0x3F)); 242 | } 243 | else 244 | { 245 | /* Invalid prefix */ 246 | *out_char = FROG_UTF32_REPLACEMENT_CHARACTER; 247 | } 248 | 249 | return begin + length; 250 | } 251 | } 252 | 253 | frog_utf_func const frog_uchar16_t *frog_decode_utf16( 254 | const frog_uchar16_t *begin, 255 | const frog_uchar16_t *end, 256 | frog_uchar32_t *out_char) 257 | { 258 | frog_uchar32_t first = (frog_uchar32_t)begin[0]; 259 | 260 | if (frog_utf_likely(first < 0xD800)) 261 | { 262 | *out_char = first; 263 | return begin + 1; 264 | } 265 | else if (first < 0xDC00) 266 | { 267 | if (frog_utf_unlikely(begin + 2 > end)) 268 | { 269 | *out_char = FROG_UTF32_REPLACEMENT_CHARACTER; 270 | return end; 271 | } 272 | 273 | *out_char = 0x10000 274 | + (((frog_uchar32_t)(begin[0]) & 0x3FF) << 10) 275 | + (((frog_uchar32_t)(begin[1]) & 0x3FF)); 276 | return begin + 2; 277 | } 278 | else if (frog_utf_unlikely(first < 0xE000)) 279 | { 280 | /* Stray low surrogate */ 281 | *out_char = FROG_UTF32_REPLACEMENT_CHARACTER; 282 | return begin + 1; 283 | } 284 | else 285 | { 286 | *out_char = first; 287 | return begin + 1; 288 | } 289 | } 290 | 291 | frog_utf_func const frog_uchar32_t *frog_decode_utf32( 292 | const frog_uchar32_t *begin, 293 | const frog_uchar32_t *end, 294 | frog_uchar32_t *out_char) 295 | { 296 | (void)(end); 297 | 298 | *out_char = begin[0]; 299 | return begin + 1; 300 | } 301 | 302 | frog_utf_func size_t frog_encode_utf8( 303 | frog_uchar8_t* begin, 304 | frog_uchar8_t* end, 305 | frog_uchar32_t ch) 306 | { 307 | if (frog_utf_likely(ch < 0x80)) 308 | { 309 | if (begin) 310 | { 311 | if (frog_utf_unlikely(begin + 1 > end)) 312 | return 0; 313 | 314 | begin[0] = (frog_uchar8_t)(ch); 315 | } 316 | 317 | return 1; 318 | } 319 | else if (ch < 0x800) 320 | { 321 | if (begin) 322 | { 323 | if (frog_utf_unlikely(begin + 2 > end)) 324 | return 0; 325 | 326 | begin[0] = (frog_uchar8_t)(0xC0 | (ch >> 6)); 327 | begin[1] = (frog_uchar8_t)(0x80 | (ch & 0x3F)); 328 | } 329 | 330 | return 2; 331 | } 332 | else if (ch < 0x10000) 333 | { 334 | if (begin) 335 | { 336 | if (frog_utf_unlikely(begin + 3 > end)) 337 | return 0; 338 | 339 | begin[0] = (frog_uchar8_t)(0xE0 | ((ch >> 12))); 340 | begin[1] = (frog_uchar8_t)(0x80 | ((ch >> 6) & 0x3F)); 341 | begin[2] = (frog_uchar8_t)(0x80 | ((ch >> 0) & 0x3F)); 342 | } 343 | 344 | return 3; 345 | } 346 | else if (ch < 0x200000) 347 | { 348 | if (begin) 349 | { 350 | if (frog_utf_unlikely(begin + 4 > end)) 351 | return 0; 352 | 353 | begin[0] = (frog_uchar8_t)(0xF0 | ((ch >> 18))); 354 | begin[1] = (frog_uchar8_t)(0x80 | ((ch >> 12) & 0x3F)); 355 | begin[2] = (frog_uchar8_t)(0x80 | ((ch >> 6) & 0x3F)); 356 | begin[3] = (frog_uchar8_t)(0x80 | ((ch >> 0) & 0x3F)); 357 | } 358 | 359 | return 4; 360 | } 361 | else 362 | { 363 | /* Invalid code point for UTF-8 */ 364 | return 0; 365 | } 366 | } 367 | 368 | frog_utf_func size_t frog_encode_utf16( 369 | frog_uchar16_t* begin, 370 | frog_uchar16_t* end, 371 | frog_uchar32_t ch) 372 | { 373 | if (frog_utf_likely(ch < 0xD800)) 374 | { 375 | if (begin) 376 | { 377 | if (frog_utf_unlikely(begin + 1 > end)) 378 | return 0; 379 | 380 | begin[0] = ch; 381 | } 382 | 383 | return 1; 384 | } 385 | else if (ch < 0xE000) 386 | { 387 | /* Private use code points, 388 | * we can't encode these */ 389 | return 0; 390 | } 391 | else if (ch < 0x10000) 392 | { 393 | if (begin) 394 | { 395 | if (frog_utf_unlikely(begin + 1 > end)) 396 | return 0; 397 | 398 | begin[0] = ch; 399 | } 400 | 401 | return 1; 402 | } 403 | else if (ch < 0x110000) 404 | { 405 | if (begin) 406 | { 407 | if (frog_utf_unlikely(begin + 2 > end)) 408 | return 0; 409 | 410 | ch -= 0x10000; 411 | begin[0] = (frog_uchar16_t)(0xD800 + (ch >> 10)); 412 | begin[1] = (frog_uchar16_t)(0xDC00 + (ch & 0x3FF)); 413 | } 414 | 415 | return 2; 416 | } 417 | else 418 | { 419 | /* Invalid code point */ 420 | return 0; 421 | } 422 | } 423 | 424 | frog_utf_func size_t frog_encode_utf32( 425 | frog_uchar32_t* begin, 426 | frog_uchar32_t* end, 427 | frog_uchar32_t ch) 428 | { 429 | if (begin) 430 | { 431 | if (frog_utf_unlikely(begin + 1 > end)) 432 | return 0; 433 | 434 | begin[0] = ch; 435 | } 436 | 437 | return 1; 438 | } 439 | 440 | /* All gen functions should be inlined .*/ 441 | frog_utf_inline_func const void *frog_decode_gen( 442 | const void *begin, 443 | const void *end, 444 | size_t in_char_size, 445 | frog_uchar32_t *out_char) 446 | { 447 | if (in_char_size == sizeof(frog_uchar8_t)) 448 | return frog_decode_utf8(begin, end, out_char); 449 | else if (in_char_size == sizeof(frog_uchar16_t)) 450 | return frog_decode_utf16(begin, end, out_char); 451 | else if (in_char_size == sizeof(frog_uchar32_t)) 452 | return frog_decode_utf32(begin, end, out_char); 453 | else 454 | frog_utf_unreachable(); 455 | 456 | /* Silence warnings on some compilers 457 | * without support for unreachable. */ 458 | return NULL; 459 | } 460 | 461 | frog_utf_inline_func size_t frog_encode_gen( 462 | void *begin, 463 | void *end, 464 | size_t out_char_size, 465 | frog_uchar32_t ch) 466 | { 467 | if (out_char_size == sizeof(frog_uchar8_t)) 468 | return frog_encode_utf8(begin, end, ch); 469 | else if (out_char_size == sizeof(frog_uchar16_t)) 470 | return frog_encode_utf16(begin, end, ch); 471 | else if (out_char_size == sizeof(frog_uchar32_t)) 472 | return frog_encode_utf32(begin, end, ch); 473 | else 474 | frog_utf_unreachable(); 475 | 476 | /* Silence warnings on some compilers 477 | * without support for unreachable. */ 478 | return 0; 479 | } 480 | 481 | frog_utf_inline_func size_t frog_str_gen_to_gen( 482 | void *dst_begin, 483 | size_t dst_char_size, 484 | size_t dst_length, 485 | const void *src_begin, 486 | size_t src_char_size, 487 | size_t src_length) 488 | { 489 | size_t total_length = 0; 490 | 491 | void* dst_end = ((uint8_t*)dst_begin) + dst_char_size * dst_length; 492 | const void* src_end = ((uint8_t*)src_begin) + src_char_size * src_length; 493 | 494 | while (src_begin < src_end) 495 | { 496 | frog_uchar32_t ch; 497 | 498 | src_begin = frog_decode_gen(src_begin, src_end, src_char_size, &ch); 499 | 500 | if (dst_begin) 501 | total_length += frog_encode_gen(((uint8_t*)dst_begin) + dst_char_size * total_length, dst_end, dst_char_size, ch); 502 | else 503 | total_length += frog_encode_gen(NULL, NULL, dst_char_size, ch); 504 | 505 | if (!ch) 506 | break; 507 | } 508 | 509 | return total_length; 510 | } 511 | 512 | frog_utf_func size_t frog_str_utf8_to_utf16( 513 | frog_uchar16_t *dst_begin, 514 | size_t dst_length, 515 | const frog_uchar8_t *src_begin, 516 | size_t src_length) 517 | { 518 | return frog_str_gen_to_gen(dst_begin, sizeof(frog_uchar16_t), dst_length, src_begin, sizeof(frog_uchar8_t), src_length); 519 | } 520 | 521 | frog_utf_func size_t frog_str_utf8_to_utf32( 522 | frog_uchar32_t *dst_begin, 523 | size_t dst_length, 524 | const frog_uchar8_t *src_begin, 525 | size_t src_length) 526 | { 527 | return frog_str_gen_to_gen(dst_begin, sizeof(frog_uchar32_t), dst_length, src_begin, sizeof(frog_uchar8_t), src_length); 528 | } 529 | 530 | frog_utf_func size_t frog_str_utf16_to_utf8( 531 | frog_uchar8_t *dst_begin, 532 | size_t dst_length, 533 | const frog_uchar16_t *src_begin, 534 | size_t src_length) 535 | { 536 | return frog_str_gen_to_gen(dst_begin, sizeof(frog_uchar8_t), dst_length, src_begin, sizeof(frog_uchar16_t), src_length); 537 | } 538 | 539 | frog_utf_func size_t frog_str_utf16_to_utf32( 540 | frog_uchar32_t *dst_begin, 541 | size_t dst_length, 542 | const frog_uchar16_t *src_begin, 543 | size_t src_length) 544 | { 545 | return frog_str_gen_to_gen(dst_begin, sizeof(frog_uchar32_t), dst_length, src_begin, sizeof(frog_uchar16_t), src_length); 546 | } 547 | 548 | frog_utf_func size_t frog_str_utf32_to_utf8( 549 | frog_uchar8_t *dst_begin, 550 | size_t dst_length, 551 | const frog_uchar32_t *src_begin, 552 | size_t src_length) 553 | { 554 | return frog_str_gen_to_gen(dst_begin, sizeof(frog_uchar8_t), dst_length, src_begin, sizeof(frog_uchar32_t), src_length); 555 | } 556 | 557 | frog_utf_func size_t frog_str_utf32_to_utf16( 558 | frog_uchar16_t *dst_begin, 559 | size_t dst_length, 560 | const frog_uchar32_t *src_begin, 561 | size_t src_length) 562 | { 563 | return frog_str_gen_to_gen(dst_begin, sizeof(frog_uchar16_t), dst_length, src_begin, sizeof(frog_uchar32_t), src_length); 564 | } 565 | 566 | #endif 567 | 568 | #ifdef __cplusplus 569 | } 570 | #endif 571 | 572 | #endif 573 | --------------------------------------------------------------------------------