162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/ucs2_string.h> 362306a36Sopenharmony_ci#include <linux/module.h> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci/* Return the number of unicode characters in data */ 662306a36Sopenharmony_ciunsigned long 762306a36Sopenharmony_ciucs2_strnlen(const ucs2_char_t *s, size_t maxlength) 862306a36Sopenharmony_ci{ 962306a36Sopenharmony_ci unsigned long length = 0; 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci while (*s++ != 0 && length < maxlength) 1262306a36Sopenharmony_ci length++; 1362306a36Sopenharmony_ci return length; 1462306a36Sopenharmony_ci} 1562306a36Sopenharmony_ciEXPORT_SYMBOL(ucs2_strnlen); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciunsigned long 1862306a36Sopenharmony_ciucs2_strlen(const ucs2_char_t *s) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci return ucs2_strnlen(s, ~0UL); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ciEXPORT_SYMBOL(ucs2_strlen); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Return the number of bytes is the length of this string 2662306a36Sopenharmony_ci * Note: this is NOT the same as the number of unicode characters 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ciunsigned long 2962306a36Sopenharmony_ciucs2_strsize(const ucs2_char_t *data, unsigned long maxlength) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ciEXPORT_SYMBOL(ucs2_strsize); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint 3662306a36Sopenharmony_ciucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci while (1) { 3962306a36Sopenharmony_ci if (len == 0) 4062306a36Sopenharmony_ci return 0; 4162306a36Sopenharmony_ci if (*a < *b) 4262306a36Sopenharmony_ci return -1; 4362306a36Sopenharmony_ci if (*a > *b) 4462306a36Sopenharmony_ci return 1; 4562306a36Sopenharmony_ci if (*a == 0) /* implies *b == 0 */ 4662306a36Sopenharmony_ci return 0; 4762306a36Sopenharmony_ci a++; 4862306a36Sopenharmony_ci b++; 4962306a36Sopenharmony_ci len--; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ciEXPORT_SYMBOL(ucs2_strncmp); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciunsigned long 5562306a36Sopenharmony_ciucs2_utf8size(const ucs2_char_t *src) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci unsigned long i; 5862306a36Sopenharmony_ci unsigned long j = 0; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci for (i = 0; src[i]; i++) { 6162306a36Sopenharmony_ci u16 c = src[i]; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (c >= 0x800) 6462306a36Sopenharmony_ci j += 3; 6562306a36Sopenharmony_ci else if (c >= 0x80) 6662306a36Sopenharmony_ci j += 2; 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci j += 1; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return j; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ciEXPORT_SYMBOL(ucs2_utf8size); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * copy at most maxlength bytes of whole utf8 characters to dest from the 7762306a36Sopenharmony_ci * ucs2 string src. 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * The return value is the number of characters copied, not including the 8062306a36Sopenharmony_ci * final NUL character. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ciunsigned long 8362306a36Sopenharmony_ciucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci unsigned int i; 8662306a36Sopenharmony_ci unsigned long j = 0; 8762306a36Sopenharmony_ci unsigned long limit = ucs2_strnlen(src, maxlength); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci for (i = 0; maxlength && i < limit; i++) { 9062306a36Sopenharmony_ci u16 c = src[i]; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (c >= 0x800) { 9362306a36Sopenharmony_ci if (maxlength < 3) 9462306a36Sopenharmony_ci break; 9562306a36Sopenharmony_ci maxlength -= 3; 9662306a36Sopenharmony_ci dest[j++] = 0xe0 | (c & 0xf000) >> 12; 9762306a36Sopenharmony_ci dest[j++] = 0x80 | (c & 0x0fc0) >> 6; 9862306a36Sopenharmony_ci dest[j++] = 0x80 | (c & 0x003f); 9962306a36Sopenharmony_ci } else if (c >= 0x80) { 10062306a36Sopenharmony_ci if (maxlength < 2) 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci maxlength -= 2; 10362306a36Sopenharmony_ci dest[j++] = 0xc0 | (c & 0x7c0) >> 6; 10462306a36Sopenharmony_ci dest[j++] = 0x80 | (c & 0x03f); 10562306a36Sopenharmony_ci } else { 10662306a36Sopenharmony_ci maxlength -= 1; 10762306a36Sopenharmony_ci dest[j++] = c & 0x7f; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci if (maxlength) 11162306a36Sopenharmony_ci dest[j] = '\0'; 11262306a36Sopenharmony_ci return j; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ciEXPORT_SYMBOL(ucs2_as_utf8); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 117