1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-18 11:31:00 -05:00

Rework Unicode conversion APIs to use a BinarySink.

The previous mb_to_wc and wc_to_mb had horrible and also buggy APIs.
This commit introduces a fresh pair of functions to replace them,
which generate output by writing to a BinarySink. So it's now up to
the caller to decide whether it wants the output written to a
fixed-size buffer with overflow checking (via buffer_sink), or
dynamically allocated, or even written directly to some other output
channel.

Nothing uses the new functions yet. I plan to migrate things over in
upcoming commits.

What was wrong with the old APIs: they had that awkward undocumented
Windows-specific 'flags' parameter that I described in the previous
commit and took out of the dup_X_to_Y wrappers. But much worse, the
semantics for buffer overflow were not just undocumented but actually
inconsistent. dup_wc_to_mb() in utils assumed that the underlying
wc_to_mb would fill the buffer nearly full and return the size of data
it wrote. In fact, this was untrue in the case where wc_to_mb called
WideCharToMultiByte: that returns straight-up failure, setting the
Windows error code to ERROR_INSUFFICIENT_BUFFER. It _does_ partially
fill the output buffer, but doesn't tell you how much it wrote!

What's wrong with the new API: it's a bit awkward to write a sequence
of wchar_t in native byte order to a byte-oriented BinarySink, so
people using put_mb_to_wc directly have to do some annoying pointer
casting. But I think that's less horrible than the previous APIs.

Another change: in the new API for wc_to_mb, defchr can be "", but not
NULL.
This commit is contained in:
Simon Tatham
2024-09-24 08:18:48 +01:00
parent 32b8da1177
commit 4f756d2a4d
10 changed files with 267 additions and 239 deletions

View File

@ -1603,10 +1603,12 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
const wchar_t *wp;
int wlen;
int ulen;
buffer_sink bs[1];
wlen = mb_to_wc(DEFAULT_CODEPAGE, 0,
event_string, strlen(event_string),
widedata, lenof(widedata)-1);
buffer_sink_init(bs, widedata, sizeof(widedata) - sizeof(wchar_t));
put_mb_to_wc(bs, DEFAULT_CODEPAGE,
event_string, strlen(event_string));
wlen = (wchar_t *)bs->out - widedata;
#ifdef KEY_EVENT_DIAGNOSTICS
{
@ -2954,16 +2956,12 @@ static void clipboard_text_received(GtkClipboard *clipboard,
{
GtkFrontend *inst = (GtkFrontend *)data;
wchar_t *paste;
int paste_len;
int length;
size_t paste_len;
if (!text)
return;
length = strlen(text);
paste = snewn(length, wchar_t);
paste_len = mb_to_wc(CS_UTF8, 0, text, length, paste, length);
paste = dup_mb_to_wc(CS_UTF8, text, length, &paste_len);
term_do_paste(inst->term, paste, paste_len);
@ -3102,17 +3100,15 @@ static void gtkwin_clip_write(
state->pasteout_data_ctext_len = 0;
}
state->pasteout_data = snewn(len*6, char);
state->pasteout_data_len = len*6;
state->pasteout_data_len = wc_to_mb(inst->ucsdata.line_codepage, 0,
data, len, state->pasteout_data,
state->pasteout_data_len, NULL);
if (state->pasteout_data_len == 0) {
sfree(state->pasteout_data);
state->pasteout_data = NULL;
} else {
state->pasteout_data =
sresize(state->pasteout_data, state->pasteout_data_len, char);
{
size_t outlen;
state->pasteout_data = dup_wc_to_mb_c(
inst->ucsdata.line_codepage, data, len, "", &outlen);
/* We can't handle pastes larger than INT_MAX, because
* gtk_selection_data_set_text's length parameter is a gint */
if (outlen > INT_MAX)
outlen = INT_MAX;
state->pasteout_data_len = outlen;
}
#ifndef NOT_X_WINDOWS
@ -3240,7 +3236,7 @@ static void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
const guchar *seldata_data = gtk_selection_data_get_data(seldata);
gint seldata_length = gtk_selection_data_get_length(seldata);
wchar_t *paste;
int paste_len;
size_t paste_len;
struct clipboard_state *state = clipboard_from_atom(
inst, gtk_selection_data_get_selection(seldata));
@ -3333,11 +3329,8 @@ static void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
}
}
paste = snewn(length, wchar_t);
paste_len = mb_to_wc(charset, 0, text, length, paste, length);
paste = dup_mb_to_wc_c(charset, text, length, &paste_len);
term_do_paste(inst->term, paste, paste_len);
sfree(paste);
#ifndef NOT_X_WINDOWS