1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/ucs2_string.h> 3 #include <linux/module.h> 4 5 /* Return the number of unicode characters in data */ 6 unsigned long 7 ucs2_strnlen(const ucs2_char_t *s, size_t maxlength) 8 { 9 unsigned long length = 0; 10 11 while (*s++ != 0 && length < maxlength) 12 length++; 13 return length; 14 } 15 EXPORT_SYMBOL(ucs2_strnlen); 16 17 unsigned long 18 ucs2_strlen(const ucs2_char_t *s) 19 { 20 return ucs2_strnlen(s, ~0UL); 21 } 22 EXPORT_SYMBOL(ucs2_strlen); 23 24 /* 25 * Return the number of bytes is the length of this string 26 * Note: this is NOT the same as the number of unicode characters 27 */ 28 unsigned long 29 ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength) 30 { 31 return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t); 32 } 33 EXPORT_SYMBOL(ucs2_strsize); 34 35 /** 36 * ucs2_strscpy() - Copy a UCS2 string into a sized buffer. 37 * 38 * @dst: Pointer to the destination buffer where to copy the string to. 39 * @src: Pointer to the source buffer where to copy the string from. 40 * @count: Size of the destination buffer, in UCS2 (16-bit) characters. 41 * 42 * Like strscpy(), only for UCS2 strings. 43 * 44 * Copy the source string @src, or as much of it as fits, into the destination 45 * buffer @dst. The behavior is undefined if the string buffers overlap. The 46 * destination buffer @dst is always NUL-terminated, unless it's zero-sized. 47 * 48 * Return: The number of characters copied into @dst (excluding the trailing 49 * %NUL terminator) or -E2BIG if @count is 0 or @src was truncated due to the 50 * destination buffer being too small. 51 */ 52 ssize_t ucs2_strscpy(ucs2_char_t *dst, const ucs2_char_t *src, size_t count) 53 { 54 long res; 55 56 /* 57 * Ensure that we have a valid amount of space. We need to store at 58 * least one NUL-character. 59 */ 60 if (count == 0 || WARN_ON_ONCE(count > INT_MAX / sizeof(*dst))) 61 return -E2BIG; 62 63 /* 64 * Copy at most 'count' characters, return early if we find a 65 * NUL-terminator. 66 */ 67 for (res = 0; res < count; res++) { 68 ucs2_char_t c; 69 70 c = src[res]; 71 dst[res] = c; 72 73 if (!c) 74 return res; 75 } 76 77 /* 78 * The loop above terminated without finding a NUL-terminator, 79 * exceeding the 'count': Enforce proper NUL-termination and return 80 * error. 81 */ 82 dst[count - 1] = 0; 83 return -E2BIG; 84 } 85 EXPORT_SYMBOL(ucs2_strscpy); 86 87 int 88 ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len) 89 { 90 while (1) { 91 if (len == 0) 92 return 0; 93 if (*a < *b) 94 return -1; 95 if (*a > *b) 96 return 1; 97 if (*a == 0) /* implies *b == 0 */ 98 return 0; 99 a++; 100 b++; 101 len--; 102 } 103 } 104 EXPORT_SYMBOL(ucs2_strncmp); 105 106 unsigned long 107 ucs2_utf8size(const ucs2_char_t *src) 108 { 109 unsigned long i; 110 unsigned long j = 0; 111 112 for (i = 0; src[i]; i++) { 113 u16 c = src[i]; 114 115 if (c >= 0x800) 116 j += 3; 117 else if (c >= 0x80) 118 j += 2; 119 else 120 j += 1; 121 } 122 123 return j; 124 } 125 EXPORT_SYMBOL(ucs2_utf8size); 126 127 /* 128 * copy at most maxlength bytes of whole utf8 characters to dest from the 129 * ucs2 string src. 130 * 131 * The return value is the number of characters copied, not including the 132 * final NUL character. 133 */ 134 unsigned long 135 ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) 136 { 137 unsigned int i; 138 unsigned long j = 0; 139 unsigned long limit = ucs2_strnlen(src, maxlength); 140 141 for (i = 0; maxlength && i < limit; i++) { 142 u16 c = src[i]; 143 144 if (c >= 0x800) { 145 if (maxlength < 3) 146 break; 147 maxlength -= 3; 148 dest[j++] = 0xe0 | (c & 0xf000) >> 12; 149 dest[j++] = 0x80 | (c & 0x0fc0) >> 6; 150 dest[j++] = 0x80 | (c & 0x003f); 151 } else if (c >= 0x80) { 152 if (maxlength < 2) 153 break; 154 maxlength -= 2; 155 dest[j++] = 0xc0 | (c & 0x7c0) >> 6; 156 dest[j++] = 0x80 | (c & 0x03f); 157 } else { 158 maxlength -= 1; 159 dest[j++] = c & 0x7f; 160 } 161 } 162 if (maxlength) 163 dest[j] = '\0'; 164 return j; 165 } 166 EXPORT_SYMBOL(ucs2_as_utf8); 167 168 MODULE_LICENSE("GPL v2"); 169