1*1f54f0bbSToomas Soome /*
2*1f54f0bbSToomas Soome  * Copyright (c) 2010 Marcel Moolenaar
3*1f54f0bbSToomas Soome  * All rights reserved.
4*1f54f0bbSToomas Soome  *
5*1f54f0bbSToomas Soome  * Redistribution and use in source and binary forms, with or without
6*1f54f0bbSToomas Soome  * modification, are permitted provided that the following conditions
7*1f54f0bbSToomas Soome  * are met:
8*1f54f0bbSToomas Soome  * 1. Redistributions of source code must retain the above copyright
9*1f54f0bbSToomas Soome  *    notice, this list of conditions and the following disclaimer.
10*1f54f0bbSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
11*1f54f0bbSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
12*1f54f0bbSToomas Soome  *    documentation and/or other materials provided with the distribution.
13*1f54f0bbSToomas Soome  *
14*1f54f0bbSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*1f54f0bbSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*1f54f0bbSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*1f54f0bbSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*1f54f0bbSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*1f54f0bbSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*1f54f0bbSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*1f54f0bbSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*1f54f0bbSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*1f54f0bbSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*1f54f0bbSToomas Soome  * SUCH DAMAGE.
25*1f54f0bbSToomas Soome  */
26*1f54f0bbSToomas Soome 
27*1f54f0bbSToomas Soome #include <sys/cdefs.h>
28*1f54f0bbSToomas Soome 
29*1f54f0bbSToomas Soome #include <sys/types.h>
30*1f54f0bbSToomas Soome #include <errno.h>
31*1f54f0bbSToomas Soome #include <stand.h>
32*1f54f0bbSToomas Soome #include <efichar.h>
33*1f54f0bbSToomas Soome 
34*1f54f0bbSToomas Soome int
ucs2len(const CHAR16 * str)35*1f54f0bbSToomas Soome ucs2len(const CHAR16 *str)
36*1f54f0bbSToomas Soome {
37*1f54f0bbSToomas Soome 	int i;
38*1f54f0bbSToomas Soome 
39*1f54f0bbSToomas Soome 	i = 0;
40*1f54f0bbSToomas Soome 	while (*str++)
41*1f54f0bbSToomas Soome 		i++;
42*1f54f0bbSToomas Soome 	return (i);
43*1f54f0bbSToomas Soome }
44*1f54f0bbSToomas Soome 
45*1f54f0bbSToomas Soome /*
46*1f54f0bbSToomas Soome  * If nm were converted to utf8, what what would strlen
47*1f54f0bbSToomas Soome  * return on the resulting string?
48*1f54f0bbSToomas Soome  */
49*1f54f0bbSToomas Soome static size_t
utf8_len_of_ucs2(const CHAR16 * nm)50*1f54f0bbSToomas Soome utf8_len_of_ucs2(const CHAR16 *nm)
51*1f54f0bbSToomas Soome {
52*1f54f0bbSToomas Soome 	size_t len;
53*1f54f0bbSToomas Soome 	CHAR16 c;
54*1f54f0bbSToomas Soome 
55*1f54f0bbSToomas Soome 	len = 0;
56*1f54f0bbSToomas Soome 	while (*nm) {
57*1f54f0bbSToomas Soome 		c = *nm++;
58*1f54f0bbSToomas Soome 		if (c > 0x7ff)
59*1f54f0bbSToomas Soome 			len += 3;
60*1f54f0bbSToomas Soome 		else if (c > 0x7f)
61*1f54f0bbSToomas Soome 			len += 2;
62*1f54f0bbSToomas Soome 		else
63*1f54f0bbSToomas Soome 			len++;
64*1f54f0bbSToomas Soome 	}
65*1f54f0bbSToomas Soome 
66*1f54f0bbSToomas Soome 	return (len);
67*1f54f0bbSToomas Soome }
68*1f54f0bbSToomas Soome 
69*1f54f0bbSToomas Soome int
ucs2_to_utf8(const CHAR16 * nm,char ** name)70*1f54f0bbSToomas Soome ucs2_to_utf8(const CHAR16 *nm, char **name)
71*1f54f0bbSToomas Soome {
72*1f54f0bbSToomas Soome 	size_t len, sz;
73*1f54f0bbSToomas Soome 	CHAR16 c;
74*1f54f0bbSToomas Soome 	char *cp;
75*1f54f0bbSToomas Soome 	int freeit = *name == NULL;
76*1f54f0bbSToomas Soome 
77*1f54f0bbSToomas Soome 	sz = utf8_len_of_ucs2(nm) + 1;
78*1f54f0bbSToomas Soome 	len = 0;
79*1f54f0bbSToomas Soome 	if (*name != NULL)
80*1f54f0bbSToomas Soome 		cp = *name;
81*1f54f0bbSToomas Soome 	else
82*1f54f0bbSToomas Soome 		cp = *name = malloc(sz);
83*1f54f0bbSToomas Soome 	if (*name == NULL)
84*1f54f0bbSToomas Soome 		return (ENOMEM);
85*1f54f0bbSToomas Soome 
86*1f54f0bbSToomas Soome 	while (*nm) {
87*1f54f0bbSToomas Soome 		c = *nm++;
88*1f54f0bbSToomas Soome 		if (c > 0x7ff) {
89*1f54f0bbSToomas Soome 			if (len++ < sz)
90*1f54f0bbSToomas Soome 				*cp++ = (char)(0xE0 | (c >> 12));
91*1f54f0bbSToomas Soome 			if (len++ < sz)
92*1f54f0bbSToomas Soome 				*cp++ = (char)(0x80 | ((c >> 6) & 0x3f));
93*1f54f0bbSToomas Soome 			if (len++ < sz)
94*1f54f0bbSToomas Soome 				*cp++ = (char)(0x80 | (c & 0x3f));
95*1f54f0bbSToomas Soome 		} else if (c > 0x7f) {
96*1f54f0bbSToomas Soome 			if (len++ < sz)
97*1f54f0bbSToomas Soome 				*cp++ = (char)(0xC0 | ((c >> 6) & 0x1f));
98*1f54f0bbSToomas Soome 			if (len++ < sz)
99*1f54f0bbSToomas Soome 				*cp++ = (char)(0x80 | (c & 0x3f));
100*1f54f0bbSToomas Soome 		} else {
101*1f54f0bbSToomas Soome 			if (len++ < sz)
102*1f54f0bbSToomas Soome 				*cp++ = (char)(c & 0x7f);
103*1f54f0bbSToomas Soome 		}
104*1f54f0bbSToomas Soome 	}
105*1f54f0bbSToomas Soome 
106*1f54f0bbSToomas Soome 	if (len >= sz) {
107*1f54f0bbSToomas Soome 		/* Absent bugs, we'll never return EOVERFLOW */
108*1f54f0bbSToomas Soome 		if (freeit) {
109*1f54f0bbSToomas Soome 			free(*name);
110*1f54f0bbSToomas Soome 			*name = NULL;
111*1f54f0bbSToomas Soome 		}
112*1f54f0bbSToomas Soome 		return (EOVERFLOW);
113*1f54f0bbSToomas Soome 	}
114*1f54f0bbSToomas Soome 	*cp++ = '\0';
115*1f54f0bbSToomas Soome 
116*1f54f0bbSToomas Soome 	return (0);
117*1f54f0bbSToomas Soome }
118*1f54f0bbSToomas Soome 
119*1f54f0bbSToomas Soome int
utf8_to_ucs2(const char * name,CHAR16 ** nmp,size_t * len)120*1f54f0bbSToomas Soome utf8_to_ucs2(const char *name, CHAR16 **nmp, size_t *len)
121*1f54f0bbSToomas Soome {
122*1f54f0bbSToomas Soome 	CHAR16 *nm;
123*1f54f0bbSToomas Soome 	size_t sz;
124*1f54f0bbSToomas Soome 	uint32_t ucs4;
125*1f54f0bbSToomas Soome 	int c, bytes;
126*1f54f0bbSToomas Soome 	int freeit = *nmp == NULL;
127*1f54f0bbSToomas Soome 
128*1f54f0bbSToomas Soome 	sz = strlen(name) * 2 + 2;
129*1f54f0bbSToomas Soome 	if (*nmp == NULL)
130*1f54f0bbSToomas Soome 		*nmp = malloc(sz);
131*1f54f0bbSToomas Soome 	if (*nmp == NULL)
132*1f54f0bbSToomas Soome 		return (ENOMEM);
133*1f54f0bbSToomas Soome 	nm = *nmp;
134*1f54f0bbSToomas Soome 	*len = sz;
135*1f54f0bbSToomas Soome 
136*1f54f0bbSToomas Soome 	ucs4 = 0;
137*1f54f0bbSToomas Soome 	bytes = 0;
138*1f54f0bbSToomas Soome 	while (sz > 1 && *name != '\0') {
139*1f54f0bbSToomas Soome 		c = *name++;
140*1f54f0bbSToomas Soome 		/*
141*1f54f0bbSToomas Soome 		 * Conditionalize on the two major character types:
142*1f54f0bbSToomas Soome 		 * initial and followup characters.
143*1f54f0bbSToomas Soome 		 */
144*1f54f0bbSToomas Soome 		if ((c & 0xc0) != 0x80) {
145*1f54f0bbSToomas Soome 			/* Initial characters. */
146*1f54f0bbSToomas Soome 			if (bytes != 0)
147*1f54f0bbSToomas Soome 				goto ilseq;
148*1f54f0bbSToomas Soome 			if ((c & 0xf8) == 0xf0) {
149*1f54f0bbSToomas Soome 				ucs4 = c & 0x07;
150*1f54f0bbSToomas Soome 				bytes = 3;
151*1f54f0bbSToomas Soome 			} else if ((c & 0xf0) == 0xe0) {
152*1f54f0bbSToomas Soome 				ucs4 = c & 0x0f;
153*1f54f0bbSToomas Soome 				bytes = 2;
154*1f54f0bbSToomas Soome 			} else if ((c & 0xe0) == 0xc0) {
155*1f54f0bbSToomas Soome 				ucs4 = c & 0x1f;
156*1f54f0bbSToomas Soome 				bytes = 1;
157*1f54f0bbSToomas Soome 			} else {
158*1f54f0bbSToomas Soome 				ucs4 = c & 0x7f;
159*1f54f0bbSToomas Soome 				bytes = 0;
160*1f54f0bbSToomas Soome 			}
161*1f54f0bbSToomas Soome 		} else {
162*1f54f0bbSToomas Soome 			/* Followup characters. */
163*1f54f0bbSToomas Soome 			if (bytes > 0) {
164*1f54f0bbSToomas Soome 				ucs4 = (ucs4 << 6) + (c & 0x3f);
165*1f54f0bbSToomas Soome 				bytes--;
166*1f54f0bbSToomas Soome 			} else if (bytes == 0) {
167*1f54f0bbSToomas Soome 				goto ilseq;
168*1f54f0bbSToomas Soome 			}
169*1f54f0bbSToomas Soome 		}
170*1f54f0bbSToomas Soome 		if (bytes == 0) {
171*1f54f0bbSToomas Soome 			if (ucs4 > 0xffff)
172*1f54f0bbSToomas Soome 				goto ilseq;
173*1f54f0bbSToomas Soome 			*nm++ = (CHAR16)ucs4;
174*1f54f0bbSToomas Soome 			sz -= 2;
175*1f54f0bbSToomas Soome 		}
176*1f54f0bbSToomas Soome 	}
177*1f54f0bbSToomas Soome 	if (sz < 2) {
178*1f54f0bbSToomas Soome 		if (freeit) {
179*1f54f0bbSToomas Soome 			free(nm);
180*1f54f0bbSToomas Soome 			*nmp = NULL;
181*1f54f0bbSToomas Soome 		}
182*1f54f0bbSToomas Soome 		return (EDOOFUS);
183*1f54f0bbSToomas Soome 	}
184*1f54f0bbSToomas Soome 	sz -= 2;
185*1f54f0bbSToomas Soome 	*nm = 0;
186*1f54f0bbSToomas Soome 	*len -= sz;
187*1f54f0bbSToomas Soome 	return (0);
188*1f54f0bbSToomas Soome ilseq:
189*1f54f0bbSToomas Soome 	if (freeit) {
190*1f54f0bbSToomas Soome 		free(nm);
191*1f54f0bbSToomas Soome 		*nmp = NULL;
192*1f54f0bbSToomas Soome 	}
193*1f54f0bbSToomas Soome 	return (EILSEQ);
194*1f54f0bbSToomas Soome }
195