* Copyright (c) 2017 Rob Clark
*/
+#include <common.h>
#include <charset.h>
+#include <capitalization.h>
#include <malloc.h>
-s32 utf8_get(const char **src)
+static struct capitalization_table capitalization_table[] =
+#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
+ UNICODE_CAPITALIZATION_TABLE;
+#elif CONFIG_FAT_DEFAULT_CODEPAGE == 1250
+ CP1250_CAPITALIZATION_TABLE;
+#else
+ CP437_CAPITALIZATION_TABLE;
+#endif
+
+/**
+ * get_code() - read Unicode code point from UTF-8 stream
+ *
+ * @read_u8: - stream reader
+ * @src: - string buffer passed to stream reader, optional
+ * Return: - Unicode code point
+ */
+static int get_code(u8 (*read_u8)(void *data), void *data)
{
- s32 code = 0;
- unsigned char c;
+ s32 ch = 0;
- if (!src || !*src)
- return -1;
- if (!**src)
+ ch = read_u8(data);
+ if (!ch)
return 0;
- c = **src;
- if (c >= 0x80) {
- ++*src;
- if (!**src)
- return -1;
- /*
- * We do not expect a continuation byte (0x80 - 0xbf).
- * 0x80 is coded as 0xc2 0x80, so we cannot have less then 0xc2
- * here.
- * The highest code point is 0x10ffff which is coded as
- * 0xf4 0x8f 0xbf 0xbf. So we cannot have a byte above 0xf4.
- */
- if (c < 0xc2 || code > 0xf4)
- return -1;
- if (c >= 0xe0) {
- if (c >= 0xf0) {
+ if (ch >= 0xc2 && ch <= 0xf4) {
+ int code = 0;
+
+ if (ch >= 0xe0) {
+ if (ch >= 0xf0) {
/* 0xf0 - 0xf4 */
- c &= 0x07;
- code = c << 18;
- c = **src;
- ++*src;
- if (!**src)
- return -1;
- if (c < 0x80 || c > 0xbf)
- return -1;
- c &= 0x3f;
+ ch &= 0x07;
+ code = ch << 18;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
+ ch &= 0x3f;
} else {
/* 0xe0 - 0xef */
- c &= 0x0f;
+ ch &= 0x0f;
}
- code += c << 12;
+ code += ch << 12;
if ((code >= 0xD800 && code <= 0xDFFF) ||
code >= 0x110000)
- return -1;
- c = **src;
- ++*src;
- if (!**src)
- return -1;
- if (c < 0x80 || c > 0xbf)
- return -1;
+ goto error;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
}
/* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
- c &= 0x3f;
- code += c << 6;
- c = **src;
- if (c < 0x80 || c > 0xbf)
- return -1;
- c &= 0x3f;
+ ch &= 0x3f;
+ code += ch << 6;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
+ ch &= 0x3f;
+ ch += code;
+ } else if (ch >= 0x80) {
+ goto error;
}
- code += c;
+ return ch;
+error:
+ return '?';
+}
+
+/**
+ * read_string() - read byte from character string
+ *
+ * @data: - pointer to string
+ * Return: - byte read
+ *
+ * The string pointer is incremented if it does not point to '\0'.
+ */
+static u8 read_string(void *data)
+
+{
+ const char **src = (const char **)data;
+ u8 c;
+
+ if (!src || !*src || !**src)
+ return 0;
+ c = **src;
++*src;
- return code;
+ return c;
+}
+
+/**
+ * read_console() - read byte from console
+ *
+ * @data - not used, needed to match interface
+ * Return: - byte read or 0 on error
+ */
+static u8 read_console(void *data)
+{
+ int ch;
+
+ ch = getc();
+ if (ch < 0)
+ ch = 0;
+ return ch;
+}
+
+int console_read_unicode(s32 *code)
+{
+ if (!tstc()) {
+ /* No input available */
+ return 1;
+ }
+
+ /* Read Unicode code */
+ *code = get_code(read_console, NULL);
+ return 0;
+}
+
+s32 utf8_get(const char **src)
+{
+ return get_code(read_string, src);
}
int utf8_put(s32 code, char **dst)
return 0;
}
+s32 utf_to_lower(const s32 code)
+{
+ struct capitalization_table *pos = capitalization_table;
+ s32 ret = code;
+
+ if (code <= 0x7f) {
+ if (code >= 'A' && code <= 'Z')
+ ret += 0x20;
+ return ret;
+ }
+ for (; pos->upper; ++pos) {
+ if (pos->upper == code) {
+ ret = pos->lower;
+ break;
+ }
+ }
+ return ret;
+}
-size_t u16_strlen(const u16 *in)
+s32 utf_to_upper(const s32 code)
{
- size_t i;
- for (i = 0; in[i]; i++);
- return i;
+ struct capitalization_table *pos = capitalization_table;
+ s32 ret = code;
+
+ if (code <= 0x7f) {
+ if (code >= 'a' && code <= 'z')
+ ret -= 0x20;
+ return ret;
+ }
+ for (; pos->lower; ++pos) {
+ if (pos->lower == code) {
+ ret = pos->upper;
+ break;
+ }
+ }
+ return ret;
+}
+
+size_t u16_strlen(const void *in)
+{
+ const char *pos = in;
+ size_t ret;
+
+ for (; pos[0] || pos[1]; pos += 2)
+ ;
+ ret = pos - (char *)in;
+ ret >>= 1;
+ return ret;
}
size_t u16_strnlen(const u16 *in, size_t count)
return i;
}
+u16 *u16_strcpy(u16 *dest, const u16 *src)
+{
+ u16 *tmp = dest;
+
+ for (;; dest++, src++) {
+ *dest = *src;
+ if (!*src)
+ break;
+ }
+
+ return tmp;
+}
+
+u16 *u16_strdup(const void *src)
+{
+ u16 *new;
+ size_t len;
+
+ if (!src)
+ return NULL;
+ len = (u16_strlen(src) + 1) * sizeof(u16);
+ new = malloc(len);
+ if (!new)
+ return NULL;
+ memcpy(new, src, len);
+
+ return new;
+}
+
/* Convert UTF-16 to UTF-8. */
uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
{