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