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 36size_t 37ucs2len(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 */ 51static size_t 52utf8_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 71int 72ucs2_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 121int 122utf8_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; 189ilseq: 190 if (freeit) { 191 FreePool(nm); 192 *nmp = NULL; 193 } 194 return EILSEQ; 195} 196