keysym: avoid strtoul in xkb_keysym_from_name

Signed-off-by: Ran Benita <ran@unusedvar.com>
master
Ran Benita 2021-04-01 22:07:28 +03:00
parent 68e69b7deb
commit 8cd688c063
2 changed files with 39 additions and 10 deletions

View File

@ -91,12 +91,37 @@ xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size)
return snprintf(buffer, size, "0x%08x", ks); return snprintf(buffer, size, "0x%08x", ks);
} }
/*
* Parse the numeric part of a 0xXXXX and UXXXX keysym.
* Not using strtoul -- it's slower and accepts a bunch of stuff
* we don't want to allow, like signs, spaces, even locale stuff.
*/
static bool
parse_keysym_hex(const char *s, uint32_t *out)
{
uint32_t result = 0;
int i;
for (i = 0; i < 8 && s[i] != '\0'; i++) {
result <<= 4;
if ('0' <= s[i] && s[i] <= '9')
result += s[i] - '0';
else if ('a' <= s[i] && s[i] <= 'f')
result += 10 + s[i] - 'a';
else if ('A' <= s[i] && s[i] <= 'F')
result += 10 + s[i] - 'A';
else
return false;
}
*out = result;
return s[i] == '\0' && i > 0;
}
XKB_EXPORT xkb_keysym_t XKB_EXPORT xkb_keysym_t
xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags) xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
{ {
const struct name_keysym *entry = NULL; const struct name_keysym *entry = NULL;
char *tmp; char *tmp;
unsigned long val; uint32_t val;
bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE); bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE);
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE) if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
@ -169,9 +194,7 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
} }
if (*name == 'U' || (icase && *name == 'u')) { if (*name == 'U' || (icase && *name == 'u')) {
errno = 0; if (!parse_keysym_hex(&name[1], &val))
val = strtoul(&name[1], &tmp, 16);
if ((tmp && *tmp != '\0') || errno != 0)
return XKB_KEY_NoSymbol; return XKB_KEY_NoSymbol;
if (val < 0x20 || (val > 0x7e && val < 0xa0)) if (val < 0x20 || (val > 0x7e && val < 0xa0))
@ -183,13 +206,8 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
return (xkb_keysym_t) val | 0x01000000; return (xkb_keysym_t) val | 0x01000000;
} }
else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) { else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) {
errno = 0; if (!parse_keysym_hex(&name[2], &val))
val = strtoul(&name[2], &tmp, 16);
if ((tmp && *tmp != '\0') || errno != 0)
return XKB_KEY_NoSymbol; return XKB_KEY_NoSymbol;
if (val > UINT32_MAX)
return XKB_KEY_NoSymbol;
return (xkb_keysym_t) val; return (xkb_keysym_t) val;
} }

View File

@ -136,7 +136,18 @@ main(void)
assert(test_string("XF86_Switch_VT_5", 0x1008FE05)); assert(test_string("XF86_Switch_VT_5", 0x1008FE05));
assert(test_string("VoidSymbol", 0xFFFFFF)); assert(test_string("VoidSymbol", 0xFFFFFF));
assert(test_string("U4567", 0x1004567)); assert(test_string("U4567", 0x1004567));
assert(test_string("U+4567", XKB_KEY_NoSymbol));
assert(test_string("U+4567ffff", XKB_KEY_NoSymbol));
assert(test_string("U+4567ffffff", XKB_KEY_NoSymbol));
assert(test_string("U 4567", XKB_KEY_NoSymbol));
assert(test_string("U +4567", XKB_KEY_NoSymbol));
assert(test_string("0x10203040", 0x10203040)); assert(test_string("0x10203040", 0x10203040));
assert(test_string("0x102030400", XKB_KEY_NoSymbol));
assert(test_string("0x010203040", XKB_KEY_NoSymbol));
assert(test_string("0x+10203040", XKB_KEY_NoSymbol));
assert(test_string("0x 10203040", XKB_KEY_NoSymbol));
assert(test_string("0x +10203040", XKB_KEY_NoSymbol));
assert(test_string("0x-10203040", XKB_KEY_NoSymbol));
assert(test_string("a", 0x61)); assert(test_string("a", 0x61));
assert(test_string("A", 0x41)); assert(test_string("A", 0x41));
assert(test_string("ch", 0xfea0)); assert(test_string("ch", 0xfea0));