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