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