[U-Boot] [PATCH v3 01/13] efi_loader: support Unicode text input
Heinrich Schuchardt
xypron.glpk at gmx.de
Tue Sep 11 20:38:02 UTC 2018
Up to now the EFI_TEXT_INPUT_PROTOCOL only supported ASCII characters.
With the patch it can consume UTF-8 from the console.
Currently only the serial console and the console can deliver UTF-8.
Local consoles are restricted to ASCII.
Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
---
v2:
drop support for German keyboard
move reading of Unicode code to charset.c
---
include/charset.h | 9 +++
lib/charset.c | 136 ++++++++++++++++++++++-------------
lib/efi_loader/efi_console.c | 13 ++--
test/unicode_ut.c | 8 +--
4 files changed, 108 insertions(+), 58 deletions(-)
diff --git a/include/charset.h b/include/charset.h
index 686db5a1fe..a7de5f6948 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -8,11 +8,20 @@
#ifndef __CHARSET_H_
#define __CHARSET_H_
+#include <efi.h>
#include <linux/kernel.h>
#include <linux/types.h>
#define MAX_UTF8_PER_UTF16 3
+/**
+ * console_read_unicode() - read Unicode code point from console
+ *
+ * @code: code point
+ * Return: 0 = success
+ */
+int console_read_unicode(s32 *code);
+
/**
* utf8_get() - get next UTF-8 code point from buffer
*
diff --git a/lib/charset.c b/lib/charset.c
index 72c808ce64..1806b41cc3 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -5,6 +5,7 @@
* Copyright (c) 2017 Rob Clark
*/
+#include <common.h>
#include <charset.h>
#include <capitalization.h>
#include <malloc.h>
@@ -18,67 +19,106 @@ static struct capitalization_table capitalization_table[] =
CP437_CAPITALIZATION_TABLE;
#endif
-s32 utf8_get(const char **src)
+/**
+ * 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 = (unsigned char)**src;
++*src;
- return code;
+ return c;
+}
+
+/**
+ * read_console() - read byte from console
+ *
+ * @src - not used, needed to match interface
+ * Return: - byte read
+ */
+static u8 read_console(void *data)
+{
+ return getc();
+}
+
+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)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 3ca6fe536c..6af083984c 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -449,23 +449,24 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
struct efi_simple_text_input_protocol *this,
struct efi_input_key *key)
{
+ efi_status_t ret;
struct efi_input_key pressed_key = {
.scan_code = 0,
.unicode_char = 0,
};
- char ch;
+ s32 ch;
EFI_ENTRY("%p, %p", this, key);
/* We don't do interrupts, so check for timers cooperatively */
efi_timer_check();
- if (!tstc()) {
- /* No key pressed */
+ ret = console_read_unicode(&ch);
+ if (ret)
return EFI_EXIT(EFI_NOT_READY);
- }
-
- ch = getc();
+ /* We do not support multi-word codes */
+ if (ch >= 0x10000)
+ ch = '?';
if (ch == cESC) {
/*
* Xterm Control Sequences
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index b94b4a651f..b115d18afd 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -178,7 +178,7 @@ static int ut_utf8_utf16_strlen(struct unit_test_state *uts)
/* illegal utf-8 sequences */
ut_asserteq(4, utf8_utf16_strlen(j1));
- ut_asserteq(5, utf8_utf16_strlen(j2));
+ ut_asserteq(4, utf8_utf16_strlen(j2));
ut_asserteq(3, utf8_utf16_strlen(j3));
return 0;
@@ -196,7 +196,7 @@ static int ut_utf8_utf16_strnlen(struct unit_test_state *uts)
/* illegal utf-8 sequences */
ut_asserteq(4, utf8_utf16_strnlen(j1, 16));
- ut_asserteq(5, utf8_utf16_strnlen(j2, 16));
+ ut_asserteq(4, utf8_utf16_strnlen(j2, 16));
ut_asserteq(3, utf8_utf16_strnlen(j3, 16));
return 0;
@@ -255,8 +255,8 @@ static int ut_utf8_utf16_strcpy(struct unit_test_state *uts)
pos = buf;
utf8_utf16_strcpy(&pos, j2);
- ut_asserteq(5, pos - buf);
- ut_assert(!ut_u16_strcmp(buf, L"j2??l", SIZE_MAX));
+ ut_asserteq(4, pos - buf);
+ ut_assert(!ut_u16_strcmp(buf, L"j2?l", SIZE_MAX));
pos = buf;
utf8_utf16_strcpy(&pos, j3);
--
2.18.0
More information about the U-Boot
mailing list