#include "chinese_text.h" #include #define CHINESE_GLYPH_FIRST 128 static const uint32_t s_chinese_codepoints[] = { #define CHINESE_GLYPH(codepoint) codepoint, #include "def_chinese_glyph_table.h" #undef CHINESE_GLYPH }; _Static_assert( sizeof(s_chinese_codepoints) / sizeof(s_chinese_codepoints[0]) <= 256 - CHINESE_GLYPH_FIRST, "Chinese glyph table exceeds the single-byte encoding range" ); static uint32_t decode_utf8_codepoint(const unsigned char** cursor) { const unsigned char* text = *cursor; if (text[0] < 0x80) { *cursor += 1; return text[0]; } if ((text[0] & 0xE0) == 0xC0 && (text[1] & 0xC0) == 0x80) { *cursor += 2; return ((uint32_t)(text[0] & 0x1F) << 6) | (text[1] & 0x3F); } if ((text[0] & 0xF0) == 0xE0 && (text[1] & 0xC0) == 0x80 && (text[2] & 0xC0) == 0x80) { *cursor += 3; return ((uint32_t)(text[0] & 0x0F) << 12) | ((uint32_t)(text[1] & 0x3F) << 6) | (text[2] & 0x3F); } *cursor += 1; return '?'; } static uint32_t codepoint_to_glyph(uint32_t codepoint) { for (size_t i = 0; i < sizeof(s_chinese_codepoints) / sizeof(s_chinese_codepoints[0]); i++) { if (s_chinese_codepoints[i] == codepoint) { return CHINESE_GLYPH_FIRST + i; } } return '?'; } static size_t encode_tte_codepoint(uint32_t codepoint, char* output, size_t output_size) { if (codepoint < 0x80) { if (output_size < 1) { return 0; } output[0] = (char)codepoint; return 1; } if (codepoint <= 0x7FF) { if (output_size < 2) { return 0; } output[0] = (char)(0xC0 | (codepoint >> 6)); output[1] = (char)(0x80 | (codepoint & 0x3F)); return 2; } return 0; } size_t chinese_text_encode(const char* utf8, char* output, size_t output_size) { if (utf8 == NULL || output == NULL || output_size == 0) { return 0; } const unsigned char* cursor = (const unsigned char*)utf8; size_t output_len = 0; while (*cursor != '\0') { uint32_t codepoint = decode_utf8_codepoint(&cursor); uint32_t tte_codepoint = codepoint < 0x80 ? codepoint : codepoint_to_glyph(codepoint); size_t encoded_size = encode_tte_codepoint(tte_codepoint, output + output_len, output_size - output_len - 1); if (encoded_size == 0) { break; } output_len += encoded_size; } output[output_len] = '\0'; return output_len; }