mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 01:18:00 +00:00
9e01de7c2b
Now you can optionally get back an enum value indicating whether the character was successfully decoded, or whether U+FFFD was substituted due to some kind of problem, and if the latter, what problem. For a start, this allows distinguishing 'real' U+FFFD (encoded legitimately in the input) from one invented by the decoder. Also, it allows the recipient of the decode to treat failures differently, either by passing on a useful error report to the user (as utf8_unknown_char now does) or by doing something special. In particular, there are two distinct error codes for a truncated UTF-8 encoding, depending on whether it was truncated by the end of the input or by encountering a non-continuation byte. The former code means that the string is not legal UTF-8 _as it is_, but doesn't rule out it being a (bytewise) prefix of a legal UTF-8 string - so if a client is receiving UTF-8 data a byte at a time, they can treat that error code specially and not make it a fatal error.
60 lines
1.7 KiB
C
60 lines
1.7 KiB
C
/*
|
|
* Check a UTF-8 string to ensure every character in it is part of the
|
|
* version of Unicode that we understand.
|
|
*
|
|
* (If it isn't, then we don't know what combining properties it has,
|
|
* so we can't safely NFC it and rely on the result not changing when
|
|
* we later update our Unicode version.)
|
|
*/
|
|
|
|
#include "misc.h"
|
|
#include "unicode/version.h"
|
|
|
|
static bool known(unsigned c)
|
|
{
|
|
struct range {
|
|
unsigned start, end;
|
|
};
|
|
static const struct range ranges[] = {
|
|
#include "unicode/known_chars.h"
|
|
};
|
|
|
|
const struct range *start = ranges, *end = start + lenof(ranges);
|
|
|
|
while (end > start) {
|
|
const struct range *curr = start + (end-start) / 2;
|
|
if (c < curr->start)
|
|
end = curr;
|
|
else if (c > curr->end)
|
|
start = curr + 1;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
char *utf8_unknown_char(ptrlen input)
|
|
{
|
|
BinarySource src[1];
|
|
BinarySource_BARE_INIT_PL(src, input);
|
|
|
|
for (size_t nchars = 0; get_avail(src); nchars++) {
|
|
DecodeUTF8Failure err;
|
|
unsigned c = decode_utf8(src, &err);
|
|
if (err != DUTF8_SUCCESS)
|
|
return dupprintf(
|
|
"cannot normalise this string: UTF-8 decoding error "
|
|
"at character position %"SIZEu", byte position %"SIZEu": %s",
|
|
nchars, src->pos, decode_utf8_error_strings[err]);
|
|
if (!known(c))
|
|
return dupprintf(
|
|
"cannot stably normalise this string: code point %04X "
|
|
"(at character position %"SIZEu", byte position %"SIZEu") "
|
|
"is not in Unicode %s", c, nchars, src->pos,
|
|
UNICODE_VERSION_SHORT);
|
|
}
|
|
|
|
return NULL;
|
|
}
|