xref: /openbmc/linux/lib/ucs2_string.c (revision 09088a40)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
20635eb8aSMatthew Garrett #include <linux/ucs2_string.h>
30635eb8aSMatthew Garrett #include <linux/module.h>
40635eb8aSMatthew Garrett 
50635eb8aSMatthew Garrett /* Return the number of unicode characters in data */
60635eb8aSMatthew Garrett unsigned long
ucs2_strnlen(const ucs2_char_t * s,size_t maxlength)70635eb8aSMatthew Garrett ucs2_strnlen(const ucs2_char_t *s, size_t maxlength)
80635eb8aSMatthew Garrett {
90635eb8aSMatthew Garrett         unsigned long length = 0;
100635eb8aSMatthew Garrett 
110635eb8aSMatthew Garrett         while (*s++ != 0 && length < maxlength)
120635eb8aSMatthew Garrett                 length++;
130635eb8aSMatthew Garrett         return length;
140635eb8aSMatthew Garrett }
150635eb8aSMatthew Garrett EXPORT_SYMBOL(ucs2_strnlen);
160635eb8aSMatthew Garrett 
170635eb8aSMatthew Garrett unsigned long
ucs2_strlen(const ucs2_char_t * s)180635eb8aSMatthew Garrett ucs2_strlen(const ucs2_char_t *s)
190635eb8aSMatthew Garrett {
200635eb8aSMatthew Garrett         return ucs2_strnlen(s, ~0UL);
210635eb8aSMatthew Garrett }
220635eb8aSMatthew Garrett EXPORT_SYMBOL(ucs2_strlen);
230635eb8aSMatthew Garrett 
240635eb8aSMatthew Garrett /*
250635eb8aSMatthew Garrett  * Return the number of bytes is the length of this string
260635eb8aSMatthew Garrett  * Note: this is NOT the same as the number of unicode characters
270635eb8aSMatthew Garrett  */
280635eb8aSMatthew Garrett unsigned long
ucs2_strsize(const ucs2_char_t * data,unsigned long maxlength)290635eb8aSMatthew Garrett ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength)
300635eb8aSMatthew Garrett {
310635eb8aSMatthew Garrett         return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t);
320635eb8aSMatthew Garrett }
330635eb8aSMatthew Garrett EXPORT_SYMBOL(ucs2_strsize);
340635eb8aSMatthew Garrett 
350635eb8aSMatthew Garrett int
ucs2_strncmp(const ucs2_char_t * a,const ucs2_char_t * b,size_t len)360635eb8aSMatthew Garrett ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
370635eb8aSMatthew Garrett {
380635eb8aSMatthew Garrett         while (1) {
390635eb8aSMatthew Garrett                 if (len == 0)
400635eb8aSMatthew Garrett                         return 0;
410635eb8aSMatthew Garrett                 if (*a < *b)
420635eb8aSMatthew Garrett                         return -1;
430635eb8aSMatthew Garrett                 if (*a > *b)
440635eb8aSMatthew Garrett                         return 1;
450635eb8aSMatthew Garrett                 if (*a == 0) /* implies *b == 0 */
460635eb8aSMatthew Garrett                         return 0;
470635eb8aSMatthew Garrett                 a++;
480635eb8aSMatthew Garrett                 b++;
490635eb8aSMatthew Garrett                 len--;
500635eb8aSMatthew Garrett         }
510635eb8aSMatthew Garrett }
520635eb8aSMatthew Garrett EXPORT_SYMBOL(ucs2_strncmp);
5373500267SPeter Jones 
5473500267SPeter Jones unsigned long
ucs2_utf8size(const ucs2_char_t * src)5573500267SPeter Jones ucs2_utf8size(const ucs2_char_t *src)
5673500267SPeter Jones {
5773500267SPeter Jones 	unsigned long i;
5873500267SPeter Jones 	unsigned long j = 0;
5973500267SPeter Jones 
60cf289cefSLukas Wunner 	for (i = 0; src[i]; i++) {
6173500267SPeter Jones 		u16 c = src[i];
6273500267SPeter Jones 
63a6807590SJason Andryuk 		if (c >= 0x800)
6473500267SPeter Jones 			j += 3;
65a6807590SJason Andryuk 		else if (c >= 0x80)
6673500267SPeter Jones 			j += 2;
6773500267SPeter Jones 		else
6873500267SPeter Jones 			j += 1;
6973500267SPeter Jones 	}
7073500267SPeter Jones 
7173500267SPeter Jones 	return j;
7273500267SPeter Jones }
7373500267SPeter Jones EXPORT_SYMBOL(ucs2_utf8size);
7473500267SPeter Jones 
7573500267SPeter Jones /*
7673500267SPeter Jones  * copy at most maxlength bytes of whole utf8 characters to dest from the
7773500267SPeter Jones  * ucs2 string src.
7873500267SPeter Jones  *
7973500267SPeter Jones  * The return value is the number of characters copied, not including the
8073500267SPeter Jones  * final NUL character.
8173500267SPeter Jones  */
8273500267SPeter Jones unsigned long
ucs2_as_utf8(u8 * dest,const ucs2_char_t * src,unsigned long maxlength)8373500267SPeter Jones ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength)
8473500267SPeter Jones {
8573500267SPeter Jones 	unsigned int i;
8673500267SPeter Jones 	unsigned long j = 0;
8773500267SPeter Jones 	unsigned long limit = ucs2_strnlen(src, maxlength);
8873500267SPeter Jones 
8973500267SPeter Jones 	for (i = 0; maxlength && i < limit; i++) {
9073500267SPeter Jones 		u16 c = src[i];
9173500267SPeter Jones 
92a6807590SJason Andryuk 		if (c >= 0x800) {
9373500267SPeter Jones 			if (maxlength < 3)
9473500267SPeter Jones 				break;
9573500267SPeter Jones 			maxlength -= 3;
9673500267SPeter Jones 			dest[j++] = 0xe0 | (c & 0xf000) >> 12;
97a6807590SJason Andryuk 			dest[j++] = 0x80 | (c & 0x0fc0) >> 6;
9873500267SPeter Jones 			dest[j++] = 0x80 | (c & 0x003f);
99a6807590SJason Andryuk 		} else if (c >= 0x80) {
10073500267SPeter Jones 			if (maxlength < 2)
10173500267SPeter Jones 				break;
10273500267SPeter Jones 			maxlength -= 2;
103a6807590SJason Andryuk 			dest[j++] = 0xc0 | (c & 0x7c0) >> 6;
104a6807590SJason Andryuk 			dest[j++] = 0x80 | (c & 0x03f);
10573500267SPeter Jones 		} else {
10673500267SPeter Jones 			maxlength -= 1;
10773500267SPeter Jones 			dest[j++] = c & 0x7f;
10873500267SPeter Jones 		}
10973500267SPeter Jones 	}
11073500267SPeter Jones 	if (maxlength)
11173500267SPeter Jones 		dest[j] = '\0';
11273500267SPeter Jones 	return j;
11373500267SPeter Jones }
11473500267SPeter Jones EXPORT_SYMBOL(ucs2_as_utf8);
11509088a40SRandy Dunlap 
11609088a40SRandy Dunlap MODULE_LICENSE("GPL v2");
117