All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrangé" <berrange@redhat.com>
To: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [PATCH 11/60] ui/console-vc: add UTF-8 input decoding with CP437 rendering
Date: Tue, 24 Mar 2026 14:07:33 +0000	[thread overview]
Message-ID: <acKapSJlHBvEiVHh@redhat.com> (raw)
In-Reply-To: <20260317-qemu-vnc-v1-11-48eb1dcf7b76@redhat.com>

On Tue, Mar 17, 2026 at 12:50:25PM +0400, Marc-André Lureau wrote:
> The text console receives bytes that may be UTF-8 encoded (e.g. from
> a guest running a modern distro), but currently treats each byte as a
> raw character index into the VGA/CP437 font, producing garbled output
> for any multi-byte sequence.
> 
> Add a proper UTF-8 decoder using Bjoern Hoehrmann's DFA.
> The DFA inherently rejects overlong encodings, surrogates, and
> codepoints above U+10FFFF.  Completed codepoints are then mapped to
> CP437, unmappable characters are displayed as '?'.

I'm surprised we can't do a charset conversion using GLib APIs ?

Do the g_convert family of  APIs (which IIUC wrap the distro iconv)
not do what we would want ? If not, would direct use of iconv not
be an alternative ?

It feels pretty wrong to need to embed UTF8 decoding code in
QEMU

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  ui/cp437.h      |  13 ++++
>  ui/console-vc.c |  62 +++++++++++++++++
>  ui/cp437.c      | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  ui/meson.build  |   2 +-
>  4 files changed, 281 insertions(+), 1 deletion(-)
> 
> diff --git a/ui/cp437.h b/ui/cp437.h
> new file mode 100644
> index 00000000000..81ace8317c7
> --- /dev/null
> +++ b/ui/cp437.h
> @@ -0,0 +1,13 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Copyright (c) QEMU contributors
> + */
> +#ifndef QEMU_CP437_H
> +#define QEMU_CP437_H
> +
> +#include <stdint.h>
> +
> +int unicode_to_cp437(uint32_t codepoint);
> +
> +#endif /* QEMU_CP437_H */
> diff --git a/ui/console-vc.c b/ui/console-vc.c
> index 8dee1f9bd01..7bbd65dea27 100644
> --- a/ui/console-vc.c
> +++ b/ui/console-vc.c
> @@ -9,6 +9,7 @@
>  #include "qemu/fifo8.h"
>  #include "qemu/option.h"
>  #include "ui/console.h"
> +#include "ui/cp437.h"
>  
>  #include "trace.h"
>  #include "console-priv.h"
> @@ -89,6 +90,8 @@ struct VCChardev {
>      enum TTYState state;
>      int esc_params[MAX_ESC_PARAMS];
>      int nb_esc_params;
> +    uint32_t utf8_state;     /* UTF-8 DFA decoder state */
> +    uint32_t utf8_codepoint; /* accumulated UTF-8 code point */
>      TextAttributes t_attrib; /* currently active text attributes */
>      TextAttributes t_attrib_saved;
>      int x_saved, y_saved;
> @@ -598,6 +601,47 @@ static void vc_clear_xy(VCChardev *vc, int x, int y)
>      vc_update_xy(vc, x, y);
>  }
>  
> +/*
> + * UTF-8 DFA decoder by Bjoern Hoehrmann.
> + * Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
> + * See https://github.com/polijan/utf8_decode for details.
> + *
> + * SPDX-License-Identifier: MIT
> + */
> +#define UTF8_ACCEPT 0
> +#define UTF8_REJECT 12
> +
> +static const uint8_t utf8d[] = {
> +    /* character class lookup */
> +    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> +    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> +    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> +    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> +    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
> +    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
> +    8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
> +   10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
> +
> +    /* state transition lookup */
> +     0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
> +    12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
> +    12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
> +    12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
> +    12,36,12,12,12,12,12,12,12,12,12,12,
> +};
> +
> +static uint32_t utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
> +{
> +    uint32_t type = utf8d[byte];
> +
> +    *codep = (*state != UTF8_ACCEPT) ?
> +        (byte & 0x3fu) | (*codep << 6) :
> +        (0xffu >> type) & (byte);
> +
> +    *state = utf8d[256 + *state + type];
> +    return *state;
> +}
> +
>  static void vc_put_one(VCChardev *vc, int ch)
>  {
>      QemuTextConsole *s = vc->console;
> @@ -761,6 +805,24 @@ static void vc_putchar(VCChardev *vc, int ch)
>  
>      switch(vc->state) {
>      case TTY_STATE_NORM:
> +        /* Feed byte through the UTF-8 DFA decoder */
> +        if (ch >= 0x80) {
> +            switch (utf8_decode(&vc->utf8_state, &vc->utf8_codepoint, ch)) {
> +            case UTF8_ACCEPT:
> +                vc_put_one(vc, unicode_to_cp437(vc->utf8_codepoint));
> +                break;
> +            case UTF8_REJECT:
> +                /* Reset state so the decoder can resync */
> +                vc->utf8_state = UTF8_ACCEPT;
> +                break;
> +            default:
> +                /* Need more bytes */
> +                break;
> +            }
> +            break;
> +        }
> +        /* ASCII byte: abort any pending UTF-8 sequence */
> +        vc->utf8_state = UTF8_ACCEPT;
>          switch(ch) {
>          case '\r':  /* carriage return */
>              s->x = 0;
> diff --git a/ui/cp437.c b/ui/cp437.c
> new file mode 100644
> index 00000000000..8ec38b73419
> --- /dev/null
> +++ b/ui/cp437.c
> @@ -0,0 +1,205 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Copyright (c) QEMU contributors
> + */
> +#include "qemu/osdep.h"
> +#include "cp437.h"
> +
> +/*
> + * Unicode to CP437 page tables.
> + *
> + * Borrowed from the Linux kernel (fs/nls/nls_cp437.c, "Dual BSD/GPL"),
> + * generated from the Unicode Organization tables (www.unicode.org).
> + */
> +static const unsigned char uni2cp437_page00[256] = {
> +    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
> +    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
> +    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
> +    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
> +    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
> +    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
> +    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
> +    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
> +    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
> +    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
> +    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
> +    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
> +    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
> +    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
> +    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
> +    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
> +
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> +    0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */
> +    0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
> +    0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
> +    0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
> +    0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
> +    0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
> +    0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
> +    0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
> +    0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
> +    0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
> +    0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
> +    0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */
> +};
> +
> +static const unsigned char uni2cp437_page01[256] = {
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> +
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> +    0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> +};
> +
> +static const unsigned char uni2cp437_page03[256] = {
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> +
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> +    0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> +    0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> +    0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
> +    0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
> +    0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
> +    0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
> +};
> +
> +static const unsigned char uni2cp437_page20[256] = {
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
> +
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
> +};
> +
> +static const unsigned char uni2cp437_page22[256] = {
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> +    0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> +    0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> +    0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> +    0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
> +};
> +
> +static const unsigned char uni2cp437_page23[256] = {
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> +    0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> +    0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> +};
> +
> +static const unsigned char uni2cp437_page25[256] = {
> +    0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> +    0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> +    0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> +    0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> +    0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> +    0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> +    0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> +    0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> +    0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
> +    0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
> +    0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
> +    0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> +
> +    0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> +    0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> +    0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> +    0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
> +};
> +
> +static const unsigned char *const uni2cp437_page[256] = {
> +    [0x00] = uni2cp437_page00, [0x01] = uni2cp437_page01,
> +    [0x03] = uni2cp437_page03, [0x20] = uni2cp437_page20,
> +    [0x22] = uni2cp437_page22, [0x23] = uni2cp437_page23,
> +    [0x25] = uni2cp437_page25,
> +};
> +
> +/*
> + * Convert a Unicode code point to its CP437 equivalent for
> + * rendering with the VGA font.
> + * Returns '?' for characters that cannot be mapped.
> + */
> +int unicode_to_cp437(uint32_t codepoint)
> +{
> +    const unsigned char *page;
> +    unsigned char hi = (codepoint >> 8) & 0xff;
> +    unsigned char lo = codepoint & 0xff;
> +
> +    if (codepoint > 0xffff) {
> +        return '?';
> +    }
> +
> +    page = uni2cp437_page[hi];
> +    if (page && page[lo]) {
> +        return page[lo];
> +    }
> +
> +    return '?';
> +}
> diff --git a/ui/meson.build b/ui/meson.build
> index 69404bca71a..d4d9312b98c 100644
> --- a/ui/meson.build
> +++ b/ui/meson.build
> @@ -16,7 +16,7 @@ system_ss.add(files(
>    'ui-qmp-cmds.c',
>    'util.c',
>  ))
> -system_ss.add(when: pixman, if_true: files('console-vc.c'), if_false: files('console-vc-stubs.c'))
> +system_ss.add(when: pixman, if_true: files('console-vc.c', 'cp437.c'), if_false: files('console-vc-stubs.c'))
>  if dbus_display
>    system_ss.add(files('dbus-module.c'))
>  endif
> 
> -- 
> 2.53.0
> 
> 

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



  reply	other threads:[~2026-03-24 14:08 UTC|newest]

Thread overview: 152+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-17  8:50 [PATCH 00/60] ui: add standalone VNC server over D-Bus Marc-André Lureau
2026-03-17  8:50 ` [PATCH 01/60] ui/vnc-jobs: fix VncRectEntry leak on job cleanup Marc-André Lureau
2026-03-24 13:43   ` Daniel P. Berrangé
2026-03-31 14:28   ` Michael Tokarev
2026-03-17  8:50 ` [PATCH 02/60] ui/vnc-jobs: clear source tag Marc-André Lureau
2026-03-24 13:44   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 03/60] ui/vnc-jobs: remove needless buffer_reset() before end Marc-André Lureau
2026-03-24 13:45   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 04/60] ui/vnc: clarify intent using buffer_empty() function Marc-André Lureau
2026-03-24 13:45   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 05/60] ui/vnc-jobs: vnc_has_job_locked() argument cannot be NULL Marc-André Lureau
2026-03-24 13:46   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 06/60] ui/vnc-jobs: remove dead VncJobQueue.exit Marc-André Lureau
2026-03-24 13:49   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 07/60] ui/vnc-jobs: remove vnc_queue_clear() Marc-André Lureau
2026-03-24 13:51   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 08/60] ui/vnc-jobs: narrow taking the lock when pushing empty jobs Marc-André Lureau
2026-03-24 13:53   ` Daniel P. Berrangé
2026-03-24 14:04     ` Marc-André Lureau
2026-03-17  8:50 ` [PATCH 09/60] ui/vnc-jobs: drop redundant (and needless) qemu_thread_get_self() Marc-André Lureau
2026-03-24 14:00   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 10/60] ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen) Marc-André Lureau
2026-03-24 14:03   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 11/60] ui/console-vc: add UTF-8 input decoding with CP437 rendering Marc-André Lureau
2026-03-24 14:07   ` Daniel P. Berrangé [this message]
2026-03-24 14:17     ` Marc-André Lureau
2026-03-24 15:42       ` Daniel P. Berrangé
2026-03-25  5:35   ` Markus Armbruster
2026-03-25  6:48     ` Marc-André Lureau
2026-04-02 11:44       ` Marc-André Lureau
2026-04-02 14:39         ` Markus Armbruster
2026-04-03 10:16           ` Marc-André Lureau
2026-03-17  8:50 ` [PATCH 12/60] ui/console-vc: ignore string-type escape sequences Marc-André Lureau
2026-03-17  8:50 ` [PATCH 13/60] ui/console-vc: fix comment shift-out/in comments Marc-André Lureau
2026-03-24 14:11   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 14/60] ui/console: dispatch get_label() through QOM virtual method Marc-André Lureau
2026-03-24 14:14   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 15/60] ui/console-vc: introduce QemuVT100 Marc-André Lureau
2026-04-01  9:08   ` Philippe Mathieu-Daudé
2026-04-01  9:24   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 16/60] ui/console-vc: set vt100 associated pixman image Marc-André Lureau
2026-04-01  9:09   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 17/60] ui/console-vc: vga_putcharxy()->vt100_putcharxy() Marc-André Lureau
2026-04-01  9:10   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 18/60] ui/console-vc: make invalidate_xy() take vt100 Marc-André Lureau
2026-04-01  9:10   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 19/60] ui/console-vc: make show_cursor() " Marc-André Lureau
2026-04-01  9:11   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 20/60] ui/console-vc: decouple VT100 display updates via function pointer Marc-André Lureau
2026-04-01  9:13   ` Philippe Mathieu-Daudé
2026-04-01  9:17   ` Philippe Mathieu-Daudé
2026-04-01 13:45     ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 21/60] ui/console-vc: console_refresh() -> vt100_refresh() Marc-André Lureau
2026-04-01  9:14   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 22/60] ui/console-vc: move cursor blinking logic into VT100 layer Marc-André Lureau
2026-03-17  8:50 ` [PATCH 23/60] ui/console-vc: console_scroll() -> vt100_scroll() Marc-André Lureau
2026-04-01  9:19   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 24/60] ui/console-vc: refactor text_console_resize() into vt100_set_image() Marc-André Lureau
2026-04-01  9:20   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 25/60] ui/console-vc: move vc_put_lf() to VT100 layer as vt100_put_lf() Marc-André Lureau
2026-04-01  9:25   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 26/60] ui/console-vc: unify the write path Marc-André Lureau
2026-04-01 13:37   ` Philippe Mathieu-Daudé
2026-04-01 13:41   ` Philippe Mathieu-Daudé
2026-04-02 13:25     ` Marc-André Lureau
2026-03-17  8:50 ` [PATCH 27/60] ui/console-vc: move VT100 state machine and output FIFO into QemuVT100 Marc-André Lureau
2026-04-01 13:38   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 28/60] ui/console-vc: extract vt100_input() from vc_chr_write() Marc-André Lureau
2026-04-01 13:42   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 29/60] ui/console-vc: extract vt100_keysym() from qemu_text_console_handle_keysym() Marc-André Lureau
2026-04-01 13:43   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 30/60] ui/console-vc: extract vt100_init() and vt100_fini() Marc-André Lureau
2026-04-01 13:46   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 31/60] ui/console: remove console_ch_t typedef and console_write_ch() Marc-André Lureau
2026-04-01 13:48   ` Philippe Mathieu-Daudé
2026-04-02 13:52     ` Marc-André Lureau
2026-03-17  8:50 ` [PATCH 32/60] ui: avoid duplicating vgafont16 in each translation unit Marc-André Lureau
2026-03-24 14:22   ` Daniel P. Berrangé
2026-04-01  9:27   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 33/60] ui/vgafont: add SPDX license header Marc-André Lureau
2026-03-24 14:24   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 34/60] ui: move FONT_WIDTH/HEIGHT to vgafont.h Marc-André Lureau
2026-03-24 14:25   ` Daniel P. Berrangé
2026-04-01  9:28   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 35/60] ui/console-vc: move VT100 emulation into separate unit Marc-André Lureau
2026-04-01  9:28   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 36/60] util: move datadir.c from system/ Marc-André Lureau
2026-03-24 14:27   ` Daniel P. Berrangé
2026-04-01  9:30   ` Philippe Mathieu-Daudé
2026-04-02 14:05     ` Marc-André Lureau
2026-03-17  8:50 ` [PATCH 37/60] ui: move DisplaySurface functions to display-surface.c Marc-André Lureau
2026-04-01  9:31   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 38/60] ui: make qemu_default_pixelformat() static inline Marc-André Lureau
2026-03-24 14:28   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 39/60] ui: make unregister_displaychangelistener() skip unregistered Marc-André Lureau
2026-03-24 14:28   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 40/60] ui: minor code simplification Marc-André Lureau
2026-03-24 14:30   ` Daniel P. Berrangé
2026-04-01  9:33     ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 41/60] system: make qemu_del_vm_change_state_handler accept NULL Marc-André Lureau
2026-03-24 14:31   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 42/60] ui/vnc: assert preconditions instead of silently returning Marc-André Lureau
2026-03-24 14:31   ` Daniel P. Berrangé
2026-04-01  9:33   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 43/60] ui/vnc: simplify vnc_init_func error handling Marc-André Lureau
2026-03-24 14:38   ` Daniel P. Berrangé
2026-04-04 14:00     ` Marc-André Lureau
2026-04-01 13:49   ` Philippe Mathieu-Daudé
2026-03-17  8:50 ` [PATCH 44/60] ui/vnc: VncDisplay.id is not const Marc-André Lureau
2026-03-24 14:39   ` Daniel P. Berrangé
2026-03-17  8:50 ` [PATCH 45/60] ui/vnc: fix vnc_display_init() leak on failure Marc-André Lureau
2026-03-24 14:47   ` Daniel P. Berrangé
2026-04-04 14:19     ` Marc-André Lureau
2026-04-07  8:55       ` Daniel P. Berrangé
2026-04-07 12:10         ` Marc-André Lureau
2026-03-17  8:51 ` [PATCH 46/60] ui/vnc: merge vnc_display_init() and vnc_display_open() Marc-André Lureau
2026-03-24 14:51   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 47/60] ui/vnc: report an error for duplicate display id Marc-André Lureau
2026-03-24 14:52   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 48/60] ui/vnc: defer listener registration until the console is known Marc-André Lureau
2026-03-24 14:53   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 49/60] ui/vnc: explicitly link with png Marc-André Lureau
2026-03-24 14:56   ` Daniel P. Berrangé
2026-04-01  9:35   ` Philippe Mathieu-Daudé
2026-03-17  8:51 ` [PATCH 50/60] ui/vnc: add vnc-system unit, to allow different implementations Marc-André Lureau
2026-03-17  8:51 ` [PATCH 51/60] ui/console: remove qemu_console_is_visible() Marc-André Lureau
2026-03-24 14:57   ` Daniel P. Berrangé
2026-03-17  8:51 ` [PATCH 52/60] ui/console: simplify registering display/console change listener Marc-André Lureau
2026-04-01  9:38   ` Philippe Mathieu-Daudé
2026-03-17  8:51 ` [PATCH 53/60] ui/console: return completion status from gfx_update callback Marc-André Lureau
2026-03-17 11:43   ` BALATON Zoltan
2026-04-04 14:59     ` Marc-André Lureau
2026-03-17  8:51 ` [PATCH 54/60] ui/console: rename public API to use consistent qemu_console_ prefix Marc-André Lureau
2026-03-17 11:46   ` BALATON Zoltan
2026-04-04 15:06     ` Marc-André Lureau
2026-03-17  8:51 ` [PATCH 55/60] ui/console: move console_handle_touch_event() to input Marc-André Lureau
2026-04-01  9:39   ` Philippe Mathieu-Daudé
2026-03-17  8:51 ` [PATCH 56/60] ui: extract common sources into a static library Marc-André Lureau
2026-04-01  9:40   ` Philippe Mathieu-Daudé
2026-03-17  8:51 ` [PATCH 57/60] tests: rename the dbus-daemon helper script Marc-André Lureau
2026-03-24 15:05   ` Daniel P. Berrangé
2026-04-01  9:40   ` Philippe Mathieu-Daudé
2026-03-17  8:51 ` [PATCH 58/60] tests/qtest: fix dbus-vmstate-test compilation Marc-André Lureau
2026-03-17 12:28   ` Fabiano Rosas
2026-03-17 12:39     ` Marc-André Lureau
2026-03-17  8:51 ` [PATCH 59/60] tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR Marc-André Lureau
2026-03-17  8:51 ` [PATCH 60/60] contrib/qemu-vnc: add standalone VNC server over D-Bus Marc-André Lureau
2026-03-24 15:24   ` Daniel P. Berrangé
2026-03-24 15:44     ` Peter Maydell
2026-03-25  8:32     ` Marc-André Lureau
2026-04-01  9:43   ` Philippe Mathieu-Daudé
2026-03-24 17:36 ` [PATCH 00/60] ui: " Daniel P. Berrangé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=acKapSJlHBvEiVHh@redhat.com \
    --to=berrange@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.