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