xref: /illumos-gate/usr/src/boot/efi/libefi/efichar.c (revision 22028508)
11f54f0bbSToomas Soome /*
21f54f0bbSToomas Soome  * Copyright (c) 2010 Marcel Moolenaar
31f54f0bbSToomas Soome  * All rights reserved.
41f54f0bbSToomas Soome  *
51f54f0bbSToomas Soome  * Redistribution and use in source and binary forms, with or without
61f54f0bbSToomas Soome  * modification, are permitted provided that the following conditions
71f54f0bbSToomas Soome  * are met:
81f54f0bbSToomas Soome  * 1. Redistributions of source code must retain the above copyright
91f54f0bbSToomas Soome  *    notice, this list of conditions and the following disclaimer.
101f54f0bbSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
111f54f0bbSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
121f54f0bbSToomas Soome  *    documentation and/or other materials provided with the distribution.
131f54f0bbSToomas Soome  *
141f54f0bbSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151f54f0bbSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161f54f0bbSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171f54f0bbSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181f54f0bbSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191f54f0bbSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201f54f0bbSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211f54f0bbSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221f54f0bbSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231f54f0bbSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241f54f0bbSToomas Soome  * SUCH DAMAGE.
251f54f0bbSToomas Soome  */
261f54f0bbSToomas Soome 
271f54f0bbSToomas Soome #include <sys/cdefs.h>
281f54f0bbSToomas Soome 
291f54f0bbSToomas Soome #include <sys/types.h>
301f54f0bbSToomas Soome #include <errno.h>
311f54f0bbSToomas Soome #include <stand.h>
321f54f0bbSToomas Soome #include <efichar.h>
331f54f0bbSToomas Soome 
341f54f0bbSToomas Soome int
ucs2len(const CHAR16 * str)351f54f0bbSToomas Soome ucs2len(const CHAR16 *str)
361f54f0bbSToomas Soome {
371f54f0bbSToomas Soome 	int i;
381f54f0bbSToomas Soome 
391f54f0bbSToomas Soome 	i = 0;
401f54f0bbSToomas Soome 	while (*str++)
411f54f0bbSToomas Soome 		i++;
421f54f0bbSToomas Soome 	return (i);
431f54f0bbSToomas Soome }
441f54f0bbSToomas Soome 
451f54f0bbSToomas Soome /*
461f54f0bbSToomas Soome  * If nm were converted to utf8, what what would strlen
471f54f0bbSToomas Soome  * return on the resulting string?
481f54f0bbSToomas Soome  */
491f54f0bbSToomas Soome static size_t
utf8_len_of_ucs2(const CHAR16 * nm)501f54f0bbSToomas Soome utf8_len_of_ucs2(const CHAR16 *nm)
511f54f0bbSToomas Soome {
521f54f0bbSToomas Soome 	size_t len;
531f54f0bbSToomas Soome 	CHAR16 c;
541f54f0bbSToomas Soome 
551f54f0bbSToomas Soome 	len = 0;
561f54f0bbSToomas Soome 	while (*nm) {
571f54f0bbSToomas Soome 		c = *nm++;
581f54f0bbSToomas Soome 		if (c > 0x7ff)
591f54f0bbSToomas Soome 			len += 3;
601f54f0bbSToomas Soome 		else if (c > 0x7f)
611f54f0bbSToomas Soome 			len += 2;
621f54f0bbSToomas Soome 		else
631f54f0bbSToomas Soome 			len++;
641f54f0bbSToomas Soome 	}
651f54f0bbSToomas Soome 
661f54f0bbSToomas Soome 	return (len);
671f54f0bbSToomas Soome }
681f54f0bbSToomas Soome 
691f54f0bbSToomas Soome int
ucs2_to_utf8(const CHAR16 * nm,char ** name)701f54f0bbSToomas Soome ucs2_to_utf8(const CHAR16 *nm, char **name)
711f54f0bbSToomas Soome {
721f54f0bbSToomas Soome 	size_t len, sz;
731f54f0bbSToomas Soome 	CHAR16 c;
741f54f0bbSToomas Soome 	char *cp;
751f54f0bbSToomas Soome 	int freeit = *name == NULL;
761f54f0bbSToomas Soome 
771f54f0bbSToomas Soome 	sz = utf8_len_of_ucs2(nm) + 1;
781f54f0bbSToomas Soome 	len = 0;
791f54f0bbSToomas Soome 	if (*name != NULL)
801f54f0bbSToomas Soome 		cp = *name;
811f54f0bbSToomas Soome 	else
821f54f0bbSToomas Soome 		cp = *name = malloc(sz);
831f54f0bbSToomas Soome 	if (*name == NULL)
841f54f0bbSToomas Soome 		return (ENOMEM);
851f54f0bbSToomas Soome 
861f54f0bbSToomas Soome 	while (*nm) {
871f54f0bbSToomas Soome 		c = *nm++;
881f54f0bbSToomas Soome 		if (c > 0x7ff) {
891f54f0bbSToomas Soome 			if (len++ < sz)
901f54f0bbSToomas Soome 				*cp++ = (char)(0xE0 | (c >> 12));
911f54f0bbSToomas Soome 			if (len++ < sz)
921f54f0bbSToomas Soome 				*cp++ = (char)(0x80 | ((c >> 6) & 0x3f));
931f54f0bbSToomas Soome 			if (len++ < sz)
941f54f0bbSToomas Soome 				*cp++ = (char)(0x80 | (c & 0x3f));
951f54f0bbSToomas Soome 		} else if (c > 0x7f) {
961f54f0bbSToomas Soome 			if (len++ < sz)
971f54f0bbSToomas Soome 				*cp++ = (char)(0xC0 | ((c >> 6) & 0x1f));
981f54f0bbSToomas Soome 			if (len++ < sz)
991f54f0bbSToomas Soome 				*cp++ = (char)(0x80 | (c & 0x3f));
1001f54f0bbSToomas Soome 		} else {
1011f54f0bbSToomas Soome 			if (len++ < sz)
1021f54f0bbSToomas Soome 				*cp++ = (char)(c & 0x7f);
1031f54f0bbSToomas Soome 		}
1041f54f0bbSToomas Soome 	}
1051f54f0bbSToomas Soome 
1061f54f0bbSToomas Soome 	if (len >= sz) {
1071f54f0bbSToomas Soome 		/* Absent bugs, we'll never return EOVERFLOW */
1081f54f0bbSToomas Soome 		if (freeit) {
1091f54f0bbSToomas Soome 			free(*name);
1101f54f0bbSToomas Soome 			*name = NULL;
1111f54f0bbSToomas Soome 		}
1121f54f0bbSToomas Soome 		return (EOVERFLOW);
1131f54f0bbSToomas Soome 	}
1141f54f0bbSToomas Soome 	*cp++ = '\0';
1151f54f0bbSToomas Soome 
1161f54f0bbSToomas Soome 	return (0);
1171f54f0bbSToomas Soome }
1181f54f0bbSToomas Soome 
1191f54f0bbSToomas Soome int
utf8_to_ucs2(const char * name,CHAR16 ** nmp,size_t * len)1201f54f0bbSToomas Soome utf8_to_ucs2(const char *name, CHAR16 **nmp, size_t *len)
1211f54f0bbSToomas Soome {
1221f54f0bbSToomas Soome 	CHAR16 *nm;
1231f54f0bbSToomas Soome 	size_t sz;
1241f54f0bbSToomas Soome 	uint32_t ucs4;
1251f54f0bbSToomas Soome 	int c, bytes;
1261f54f0bbSToomas Soome 	int freeit = *nmp == NULL;
1271f54f0bbSToomas Soome 
1281f54f0bbSToomas Soome 	sz = strlen(name) * 2 + 2;
1291f54f0bbSToomas Soome 	if (*nmp == NULL)
1301f54f0bbSToomas Soome 		*nmp = malloc(sz);
1311f54f0bbSToomas Soome 	if (*nmp == NULL)
1321f54f0bbSToomas Soome 		return (ENOMEM);
1331f54f0bbSToomas Soome 	nm = *nmp;
1341f54f0bbSToomas Soome 	*len = sz;
1351f54f0bbSToomas Soome 
1361f54f0bbSToomas Soome 	ucs4 = 0;
1371f54f0bbSToomas Soome 	bytes = 0;
1381f54f0bbSToomas Soome 	while (sz > 1 && *name != '\0') {
1391f54f0bbSToomas Soome 		c = *name++;
1401f54f0bbSToomas Soome 		/*
1411f54f0bbSToomas Soome 		 * Conditionalize on the two major character types:
1421f54f0bbSToomas Soome 		 * initial and followup characters.
1431f54f0bbSToomas Soome 		 */
1441f54f0bbSToomas Soome 		if ((c & 0xc0) != 0x80) {
1451f54f0bbSToomas Soome 			/* Initial characters. */
1461f54f0bbSToomas Soome 			if (bytes != 0)
1471f54f0bbSToomas Soome 				goto ilseq;
1481f54f0bbSToomas Soome 			if ((c & 0xf8) == 0xf0) {
1491f54f0bbSToomas Soome 				ucs4 = c & 0x07;
1501f54f0bbSToomas Soome 				bytes = 3;
1511f54f0bbSToomas Soome 			} else if ((c & 0xf0) == 0xe0) {
1521f54f0bbSToomas Soome 				ucs4 = c & 0x0f;
1531f54f0bbSToomas Soome 				bytes = 2;
1541f54f0bbSToomas Soome 			} else if ((c & 0xe0) == 0xc0) {
1551f54f0bbSToomas Soome 				ucs4 = c & 0x1f;
1561f54f0bbSToomas Soome 				bytes = 1;
1571f54f0bbSToomas Soome 			} else {
1581f54f0bbSToomas Soome 				ucs4 = c & 0x7f;
1591f54f0bbSToomas Soome 				bytes = 0;
1601f54f0bbSToomas Soome 			}
1611f54f0bbSToomas Soome 		} else {
1621f54f0bbSToomas Soome 			/* Followup characters. */
1631f54f0bbSToomas Soome 			if (bytes > 0) {
1641f54f0bbSToomas Soome 				ucs4 = (ucs4 << 6) + (c & 0x3f);
1651f54f0bbSToomas Soome 				bytes--;
1661f54f0bbSToomas Soome 			} else if (bytes == 0) {
1671f54f0bbSToomas Soome 				goto ilseq;
1681f54f0bbSToomas Soome 			}
1691f54f0bbSToomas Soome 		}
1701f54f0bbSToomas Soome 		if (bytes == 0) {
1711f54f0bbSToomas Soome 			if (ucs4 > 0xffff)
1721f54f0bbSToomas Soome 				goto ilseq;
1731f54f0bbSToomas Soome 			*nm++ = (CHAR16)ucs4;
1741f54f0bbSToomas Soome 			sz -= 2;
1751f54f0bbSToomas Soome 		}
1761f54f0bbSToomas Soome 	}
1771f54f0bbSToomas Soome 	if (sz < 2) {
1781f54f0bbSToomas Soome 		if (freeit) {
1791f54f0bbSToomas Soome 			free(nm);
1801f54f0bbSToomas Soome 			*nmp = NULL;
1811f54f0bbSToomas Soome 		}
1821f54f0bbSToomas Soome 		return (EDOOFUS);
1831f54f0bbSToomas Soome 	}
1841f54f0bbSToomas Soome 	sz -= 2;
1851f54f0bbSToomas Soome 	*nm = 0;
1861f54f0bbSToomas Soome 	*len -= sz;
1871f54f0bbSToomas Soome 	return (0);
1881f54f0bbSToomas Soome ilseq:
1891f54f0bbSToomas Soome 	if (freeit) {
1901f54f0bbSToomas Soome 		free(nm);
1911f54f0bbSToomas Soome 		*nmp = NULL;
1921f54f0bbSToomas Soome 	}
1931f54f0bbSToomas Soome 	return (EILSEQ);
1941f54f0bbSToomas Soome }
195