11f54f0bbSToomas Soome /*
21f54f0bbSToomas Soome * Copyright (c) 2010 Marcel Moolenaar
31f54f0bbSToomas Soome * All rights reserved.
41f54f0bbSToomas Soome *
51f54f0bbSToomas Soome * Redistribution and use in source and binary forms, with or without
61f54f0bbSToomas Soome * modification, are permitted provided that the following conditions
71f54f0bbSToomas Soome * are met:
81f54f0bbSToomas Soome * 1. Redistributions of source code must retain the above copyright
91f54f0bbSToomas Soome * notice, this list of conditions and the following disclaimer.
101f54f0bbSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
111f54f0bbSToomas Soome * notice, this list of conditions and the following disclaimer in the
121f54f0bbSToomas Soome * documentation and/or other materials provided with the distribution.
131f54f0bbSToomas Soome *
141f54f0bbSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151f54f0bbSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161f54f0bbSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171f54f0bbSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181f54f0bbSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191f54f0bbSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201f54f0bbSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211f54f0bbSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221f54f0bbSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231f54f0bbSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241f54f0bbSToomas Soome * SUCH DAMAGE.
251f54f0bbSToomas Soome */
261f54f0bbSToomas Soome
271f54f0bbSToomas Soome #include <sys/cdefs.h>
281f54f0bbSToomas Soome
291f54f0bbSToomas Soome #include <sys/types.h>
301f54f0bbSToomas Soome #include <errno.h>
311f54f0bbSToomas Soome #include <stand.h>
321f54f0bbSToomas Soome #include <efichar.h>
331f54f0bbSToomas Soome
341f54f0bbSToomas Soome int
ucs2len(const CHAR16 * str)351f54f0bbSToomas Soome ucs2len(const CHAR16 *str)
361f54f0bbSToomas Soome {
371f54f0bbSToomas Soome int i;
381f54f0bbSToomas Soome
391f54f0bbSToomas Soome i = 0;
401f54f0bbSToomas Soome while (*str++)
411f54f0bbSToomas Soome i++;
421f54f0bbSToomas Soome return (i);
431f54f0bbSToomas Soome }
441f54f0bbSToomas Soome
451f54f0bbSToomas Soome /*
461f54f0bbSToomas Soome * If nm were converted to utf8, what what would strlen
471f54f0bbSToomas Soome * return on the resulting string?
481f54f0bbSToomas Soome */
491f54f0bbSToomas Soome static size_t
utf8_len_of_ucs2(const CHAR16 * nm)501f54f0bbSToomas Soome utf8_len_of_ucs2(const CHAR16 *nm)
511f54f0bbSToomas Soome {
521f54f0bbSToomas Soome size_t len;
531f54f0bbSToomas Soome CHAR16 c;
541f54f0bbSToomas Soome
551f54f0bbSToomas Soome len = 0;
561f54f0bbSToomas Soome while (*nm) {
571f54f0bbSToomas Soome c = *nm++;
581f54f0bbSToomas Soome if (c > 0x7ff)
591f54f0bbSToomas Soome len += 3;
601f54f0bbSToomas Soome else if (c > 0x7f)
611f54f0bbSToomas Soome len += 2;
621f54f0bbSToomas Soome else
631f54f0bbSToomas Soome len++;
641f54f0bbSToomas Soome }
651f54f0bbSToomas Soome
661f54f0bbSToomas Soome return (len);
671f54f0bbSToomas Soome }
681f54f0bbSToomas Soome
691f54f0bbSToomas Soome int
ucs2_to_utf8(const CHAR16 * nm,char ** name)701f54f0bbSToomas Soome ucs2_to_utf8(const CHAR16 *nm, char **name)
711f54f0bbSToomas Soome {
721f54f0bbSToomas Soome size_t len, sz;
731f54f0bbSToomas Soome CHAR16 c;
741f54f0bbSToomas Soome char *cp;
751f54f0bbSToomas Soome int freeit = *name == NULL;
761f54f0bbSToomas Soome
771f54f0bbSToomas Soome sz = utf8_len_of_ucs2(nm) + 1;
781f54f0bbSToomas Soome len = 0;
791f54f0bbSToomas Soome if (*name != NULL)
801f54f0bbSToomas Soome cp = *name;
811f54f0bbSToomas Soome else
821f54f0bbSToomas Soome cp = *name = malloc(sz);
831f54f0bbSToomas Soome if (*name == NULL)
841f54f0bbSToomas Soome return (ENOMEM);
851f54f0bbSToomas Soome
861f54f0bbSToomas Soome while (*nm) {
871f54f0bbSToomas Soome c = *nm++;
881f54f0bbSToomas Soome if (c > 0x7ff) {
891f54f0bbSToomas Soome if (len++ < sz)
901f54f0bbSToomas Soome *cp++ = (char)(0xE0 | (c >> 12));
911f54f0bbSToomas Soome if (len++ < sz)
921f54f0bbSToomas Soome *cp++ = (char)(0x80 | ((c >> 6) & 0x3f));
931f54f0bbSToomas Soome if (len++ < sz)
941f54f0bbSToomas Soome *cp++ = (char)(0x80 | (c & 0x3f));
951f54f0bbSToomas Soome } else if (c > 0x7f) {
961f54f0bbSToomas Soome if (len++ < sz)
971f54f0bbSToomas Soome *cp++ = (char)(0xC0 | ((c >> 6) & 0x1f));
981f54f0bbSToomas Soome if (len++ < sz)
991f54f0bbSToomas Soome *cp++ = (char)(0x80 | (c & 0x3f));
1001f54f0bbSToomas Soome } else {
1011f54f0bbSToomas Soome if (len++ < sz)
1021f54f0bbSToomas Soome *cp++ = (char)(c & 0x7f);
1031f54f0bbSToomas Soome }
1041f54f0bbSToomas Soome }
1051f54f0bbSToomas Soome
1061f54f0bbSToomas Soome if (len >= sz) {
1071f54f0bbSToomas Soome /* Absent bugs, we'll never return EOVERFLOW */
1081f54f0bbSToomas Soome if (freeit) {
1091f54f0bbSToomas Soome free(*name);
1101f54f0bbSToomas Soome *name = NULL;
1111f54f0bbSToomas Soome }
1121f54f0bbSToomas Soome return (EOVERFLOW);
1131f54f0bbSToomas Soome }
1141f54f0bbSToomas Soome *cp++ = '\0';
1151f54f0bbSToomas Soome
1161f54f0bbSToomas Soome return (0);
1171f54f0bbSToomas Soome }
1181f54f0bbSToomas Soome
1191f54f0bbSToomas Soome int
utf8_to_ucs2(const char * name,CHAR16 ** nmp,size_t * len)1201f54f0bbSToomas Soome utf8_to_ucs2(const char *name, CHAR16 **nmp, size_t *len)
1211f54f0bbSToomas Soome {
1221f54f0bbSToomas Soome CHAR16 *nm;
1231f54f0bbSToomas Soome size_t sz;
1241f54f0bbSToomas Soome uint32_t ucs4;
1251f54f0bbSToomas Soome int c, bytes;
1261f54f0bbSToomas Soome int freeit = *nmp == NULL;
1271f54f0bbSToomas Soome
1281f54f0bbSToomas Soome sz = strlen(name) * 2 + 2;
1291f54f0bbSToomas Soome if (*nmp == NULL)
1301f54f0bbSToomas Soome *nmp = malloc(sz);
1311f54f0bbSToomas Soome if (*nmp == NULL)
1321f54f0bbSToomas Soome return (ENOMEM);
1331f54f0bbSToomas Soome nm = *nmp;
1341f54f0bbSToomas Soome *len = sz;
1351f54f0bbSToomas Soome
1361f54f0bbSToomas Soome ucs4 = 0;
1371f54f0bbSToomas Soome bytes = 0;
1381f54f0bbSToomas Soome while (sz > 1 && *name != '\0') {
1391f54f0bbSToomas Soome c = *name++;
1401f54f0bbSToomas Soome /*
1411f54f0bbSToomas Soome * Conditionalize on the two major character types:
1421f54f0bbSToomas Soome * initial and followup characters.
1431f54f0bbSToomas Soome */
1441f54f0bbSToomas Soome if ((c & 0xc0) != 0x80) {
1451f54f0bbSToomas Soome /* Initial characters. */
1461f54f0bbSToomas Soome if (bytes != 0)
1471f54f0bbSToomas Soome goto ilseq;
1481f54f0bbSToomas Soome if ((c & 0xf8) == 0xf0) {
1491f54f0bbSToomas Soome ucs4 = c & 0x07;
1501f54f0bbSToomas Soome bytes = 3;
1511f54f0bbSToomas Soome } else if ((c & 0xf0) == 0xe0) {
1521f54f0bbSToomas Soome ucs4 = c & 0x0f;
1531f54f0bbSToomas Soome bytes = 2;
1541f54f0bbSToomas Soome } else if ((c & 0xe0) == 0xc0) {
1551f54f0bbSToomas Soome ucs4 = c & 0x1f;
1561f54f0bbSToomas Soome bytes = 1;
1571f54f0bbSToomas Soome } else {
1581f54f0bbSToomas Soome ucs4 = c & 0x7f;
1591f54f0bbSToomas Soome bytes = 0;
1601f54f0bbSToomas Soome }
1611f54f0bbSToomas Soome } else {
1621f54f0bbSToomas Soome /* Followup characters. */
1631f54f0bbSToomas Soome if (bytes > 0) {
1641f54f0bbSToomas Soome ucs4 = (ucs4 << 6) + (c & 0x3f);
1651f54f0bbSToomas Soome bytes--;
1661f54f0bbSToomas Soome } else if (bytes == 0) {
1671f54f0bbSToomas Soome goto ilseq;
1681f54f0bbSToomas Soome }
1691f54f0bbSToomas Soome }
1701f54f0bbSToomas Soome if (bytes == 0) {
1711f54f0bbSToomas Soome if (ucs4 > 0xffff)
1721f54f0bbSToomas Soome goto ilseq;
1731f54f0bbSToomas Soome *nm++ = (CHAR16)ucs4;
1741f54f0bbSToomas Soome sz -= 2;
1751f54f0bbSToomas Soome }
1761f54f0bbSToomas Soome }
1771f54f0bbSToomas Soome if (sz < 2) {
1781f54f0bbSToomas Soome if (freeit) {
1791f54f0bbSToomas Soome free(nm);
1801f54f0bbSToomas Soome *nmp = NULL;
1811f54f0bbSToomas Soome }
1821f54f0bbSToomas Soome return (EDOOFUS);
1831f54f0bbSToomas Soome }
1841f54f0bbSToomas Soome sz -= 2;
1851f54f0bbSToomas Soome *nm = 0;
1861f54f0bbSToomas Soome *len -= sz;
1871f54f0bbSToomas Soome return (0);
1881f54f0bbSToomas Soome ilseq:
1891f54f0bbSToomas Soome if (freeit) {
1901f54f0bbSToomas Soome free(nm);
1911f54f0bbSToomas Soome *nmp = NULL;
1921f54f0bbSToomas Soome }
1931f54f0bbSToomas Soome return (EILSEQ);
1941f54f0bbSToomas Soome }
195