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