mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
efi_loader: support Unicode text input
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@gmx.de> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
cce289a928
commit
35cbb796aa
4 changed files with 108 additions and 58 deletions
|
@ -13,6 +13,14 @@
|
|||
|
||||
#define MAX_UTF8_PER_UTF16 3
|
||||
|
||||
/**
|
||||
* console_read_unicode() - read Unicode code point from console
|
||||
*
|
||||
* @code: pointer to store Unicode code point
|
||||
* Return: 0 = success
|
||||
*/
|
||||
int console_read_unicode(s32 *code);
|
||||
|
||||
/**
|
||||
* utf8_get() - get next UTF-8 code point from buffer
|
||||
*
|
||||
|
|
137
lib/charset.c
137
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,107 @@ 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 = **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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue