#ifndef INCLUDED_C_UTF8_H #define INCLUDED_C_UTF8_H #ifndef INCLUDED_C_BASE_H #include #endif /*INCLUDED_C_BASE_H*/ /* ------------------------------------------------------------------------------------------------------------------ */ /* */ #ifndef C_UNICODE_MAX #define C_UNICODE_MAX 0x10FFFFU #endif /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /* --- Unicode Codepoint Type Definition --- */ typedef uint32_t c_ucs4_t; // UCS-4 / UTF-32 representation for a single Unicode Codepoint typedef uint16_t c_uint16_t; /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE bool c_is_valid_unicode(uint32_t code) { // Unicode 码点不能超过 0x10FFFF,且必须排除 UTF-16 代理对范围 (0xD800 ~ 0xDFFF) if (code > C_UNICODE_MAX) return false; if (code >= 0xD800 && code <= 0xDFFF) return false; return true; } /** * @brief 获取一个 UTF-8 字符在当前指针位置所占用的实际字节数 (1 ~ 4 字节) */ C_STATIC_FORCE_INLINE c_size_t c_utf8_char_len(char leading_byte) { unsigned char b = (unsigned char)leading_byte; if (b < 0x80) return 1; // 单字节 ASCII: 0xxxxxxx if ((b & 0xE0) == 0xC0) return 2; // 双字节字符: 110xxxxx if ((b & 0xF0) == 0xE0) return 3; // 三字节字符(大部分汉字): 1110xxxx if ((b & 0xF8) == 0xF0) return 4; // 四字节字符(Emoji等): 11110xxx return 1; // 非法 UTF-8 引导字节,防御性返回 1 防止死循环 } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /** * @brief 计算一个 UTF-8 字符串的有效字形数(字符数),而非字节数 (兼容 strlen) */ c_size_t c_utf8_strlen(const char* str); /** * @brief 查找字符在 UTF-8 字符串中第一次出现的位置 (兼容 strchr) * @param str 源字符串 * @param utf8_char 待查找的 UTF-8 字符(支持多字节字符,如 "中") * @return const char* 指向找到的第一个字节的指针,未找到返回 NULL */ const char* c_utf8_strchr(const char* str, const char* utf8_char); /** * @brief 复制指定字形数量的 UTF-8 字符串 (兼容 strncpy) * @note 能够完美感知 UTF-8 字符边界,绝不会切断汉字,且自动在末尾补 '\0' * @param dest 目标缓冲区 * @param src 源字符串 * @param char_num 要复制的 UTF-8 字符/字形数量 * @return char* 指向目标缓冲区 dest 的指针 */ char* c_utf8_strncpy(char* dest, const char* src, c_size_t char_num); /** * @brief 比较两个 UTF-8 字符串的前 n 个字符 (兼容 strncmp) * @param str1 字符串 1 * @param str2 字符串 2 * @param char_num 要比较的 UTF-8 字符/字形数量 * @return int 小于 0、等于 0 或大于 0 */ int c_utf8_strncmp(const char* str1, const char* str2, c_size_t char_num); /** * @brief Converts a UTF-8 character string to lowercase in-place. * Supports standard ASCII case folding and common multi-byte scripts. * @param str Pointer to the mutable null-terminated UTF-8 string. * @return char* Pointer to the original string. */ char* c_utf8_tolower(char* str); /** * @brief Converts a UTF-8 character string to uppercase in-place. * Supports standard ASCII case folding and common multi-byte scripts. * @param str Pointer to the mutable null-terminated UTF-8 string. * @return char* Pointer to the original string. */ char* c_utf8_toupper(char* str); /** * @brief Appends the source UTF-8 string to the destination string buffer (Compatible with strcat). * @param dest Pointer to the null-terminated destination buffer. * @param src Pointer to the null-terminated source string. * @return char* Pointer to the destination string destination pointer. */ char* c_utf8_strcat(char* dest, const char* src); /** * @brief Finds the first occurrence of a substring in a UTF-8 string (Compatible with strstr). * @param haystack The null-terminated UTF-8 string to scan. * @param needle The null-terminated UTF-8 substring to search for. * @return const char* Pointer to the first byte of the matched substring in haystack, or NULL if not found. */ const char* c_utf8_strstr(const char* haystack, const char* needle); /** * @brief Finds the last occurrence of a specific character in a UTF-8 string (Compatible with strrchr). * @param str The null-terminated UTF-8 string to scan. * @param utf8_char The null-terminated UTF-8 character string to find (can be a multi-byte sequence like "中"). * @return const char* Pointer to the last occurrence of the matched character in str, or NULL if not found. */ const char* c_utf8_strrchr(const char* str, const char* utf8_char); /** * @brief Tokenizes a string into a series of tokens based on multiple multi-byte delimiters. * This function is thread-safe and reentrant, operating similarly to POSIX strtok_r. * @param str The mutable UTF-8 string to tokenize. Pass NULL on subsequent calls. * @param delims A raw byte sequence containing multi-byte UTF-8 delimiters. * @param saveptr A user-allocated tracking pointer to maintain state context across consecutive calls. * @return char* Pointer to the beginning of the next valid token, or NULL when no more tokens are found. */ char* c_utf8_strtok(char* str, const char* delims, char** saveptr); /** * @brief Compares two UTF-8 strings case-insensitively up to a specified number of characters. * @param str1 Pointer to the first null-terminated UTF-8 string. * @param str2 Pointer to the second null-terminated UTF-8 string. * @param char_num Maximum number of UTF-8 characters (codepoints) to compare. * @return int An integer less than, equal to, or greater than zero if str1 is found, * respectively, to be less than, to match, or be greater than str2. */ int c_utf8_strncasecmp(const char* str1, const char* str2, c_size_t char_num); /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /** * @brief Converts the next UTF-8 byte sequence at a given pointer into a single Unicode Codepoint. * @param str Pointer to the current position in a null-terminated UTF-8 string. * @param out_codepoint Pointer to the destination where the decoded Unicode integer is saved. * @param out_bytes_consumed Pointer to save the number of source bytes processed (1 to 4). * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM on invalid/corrupted UTF-8 byte streams. */ c_err_t c_utf8_to_unicode(const char* str, c_ucs4_t* out_codepoint, c_size_t* out_bytes_consumed); /** * @brief Encodes a single Unicode Codepoint (UCS-4) into a destination UTF-8 byte array. * @param codepoint The source Unicode integer character point to encode. * @param dest_buffer Pointer to a char array buffer (must have at least 5 bytes capacity). * @param out_bytes_written Pointer to save the number of encoded bytes stored in dest_buffer. * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM if the codepoint is out of valid Unicode ranges or parameters are NULL. */ c_err_t c_utf8_from_unicode(c_ucs4_t codepoint, char* dest_buffer, c_size_t* out_bytes_written); /** * @brief Decodes an entire null-terminated UTF-8 string into an array of Unicode Codepoints. * @param str Pointer to the null-terminated source UTF-8 string. * @param dest_array Pointer to the destination array where decoded codepoints will be stored. * @param array_capacity Maximum number of elements that dest_array can hold. * @param out_chars_written Pointer to save the total number of codepoints successfully stored. * @return c_err_t C_ERR_OK on success, C_ERR_PARAM on invalid/NULL parameters or if the destination array capacity is exceeded. */ c_err_t c_utf8_to_unicode_array(const char* str, c_ucs4_t* dest_array, c_size_t array_capacity, c_size_t* out_chars_written); /** * @brief Encodes an array of Unicode Codepoints back into a null-terminated UTF-8 byte stream. * @param src_array Pointer to the source array of Unicode codepoints. * @param src_array_len The number of codepoint elements inside src_array to process. * @param dest_buffer Pointer to the destination char buffer. * @param dest_capacity Maximum byte capacity of the destination buffer (including room for '\0'). * @param out_bytes_written Pointer to save the total number of bytes written to dest_buffer (excluding '\0'). * @return c_err_t C_ERR_OK on success, C_ERR_PARAM on invalid/NULL parameters or if dest_capacity is exceeded. */ c_err_t c_utf8_from_unicode_array(const c_ucs4_t* src_array, c_size_t src_array_len, char* dest_buffer, c_size_t dest_capacity, c_size_t* out_bytes_written); /** * @brief Converts an entire null-terminated UTF-8 string into an array of UTF-16 code units. * @param str Pointer to the null-terminated source UTF-8 string. * @param dest_array Pointer to the destination array where UTF-16 code units will be stored. * @param array_capacity Maximum number of 16-bit elements that dest_array can hold. * @param out_units_written Pointer to save the total number of UTF-16 code units successfully stored (excluding terminal '\0'). * @return c_err_t C_ERR_OK on success, C_ERR_PARAM on invalid/NULL parameters or if capacity is exceeded. */ c_err_t c_utf8_to_utf16(const char* str, c_uint16_t* dest_array, c_size_t array_capacity, c_size_t* out_units_written); /** * @brief Converts an array of UTF-16 code units back into a null-terminated UTF-8 byte stream. * @param src_array Pointer to the source array of UTF-16 code units. * @param src_array_len The number of 16-bit elements inside src_array to process. * @param dest_buffer Pointer to the destination char buffer. * @param dest_capacity Maximum byte capacity of the destination buffer (including room for '\0'). * @param out_bytes_written Pointer to save the total number of bytes written to dest_buffer (excluding '\0'). * @return c_err_t C_ERR_OK on success, C_ERR_PARAM on invalid/NULL parameters, malformed surrogates, or if dest_capacity is exceeded. */ c_err_t c_utf8_from_utf16(const c_uint16_t* src_array, c_size_t src_array_len, char* dest_buffer, c_size_t dest_capacity, c_size_t* out_bytes_written); /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /** * @brief Swaps the byte order (endianness) of a UTF-16 string array in-place. * @param utf16_array Pointer to the source/destination array of UTF-16 code units. * @param length The number of 16-bit elements inside the array to process. * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM if the array pointer is NULL. */ c_err_t c_utf16_swap_endian(c_uint16_t* utf16_array, c_size_t length); /** * @brief Decodes a UTF-16 character stream starting at a given pointer into a single Unicode codepoint. * @param src_units Pointer to the current code unit position in a UTF-16 array. * @param src_capacity Remaining elements left available to read inside the source array. * @param out_codepoint Pointer to the destination where the decoded Unicode integer is saved. * @param out_units_read Pointer to save the number of 16-bit code units processed (1 for BMP, 2 for Surrogate Pairs). * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM on malformed surrogate sequences or missing parameters. */ c_err_t c_utf16_to_unicode(const c_uint16_t* src_units, c_size_t src_capacity, c_ucs4_t* out_codepoint, c_size_t* out_units_read); /** * @brief Encodes a single Unicode codepoint into a target UTF-16 array buffer. * @param codepoint The source Unicode integer character point to encode. * @param dest_units Pointer to the destination 16-bit code unit array buffer. * @param dest_capacity Maximum number of 16-bit elements the destination buffer can accept. * @param out_units_written Pointer to save the number of 16-bit code units generated (1 or 2). * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM if the codepoint is invalid or destination space is insufficient. */ c_err_t c_utf16_from_unicode(c_ucs4_t codepoint, c_uint16_t* dest_units, c_size_t dest_capacity, c_size_t* out_units_written); #endif /*INCLUDED_C_UTF8_H*/