BMenu: Use BUnicodeChar for unicode char manipulation.

It is not allowed to use isspace, tolower, etc, on character outside of
the char type range (and EOF). Use BUnicodeChar instead to avoid out of
bound accesses.

Fixes the second crash in #14753.

Signed-off-by: Augustin Cavalier <[email protected]>
Some changes by me to make "index" a byte instead of character index
as it needs to be.
This commit is contained in:
Adrien Destugues
2018-12-22 00:25:10 -05:00
committed by Augustin Cavalier
parent c1917899cd
commit 588a0c9f67
+32 -20
View File
@@ -1,10 +1,11 @@
/*
* Copyright 2001-2015 Haiku, Inc. All rights reserved.
* Copyright 2001-2018 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
* Stephan Aßmus, [email protected]
* Stefano Ceccherini, [email protected]
* Adrien Destugues, [email protected]
* Marc Flerackers, [email protected]
* Rene Gollent, [email protected]
* John Scipione, [email protected]
@@ -15,6 +16,7 @@
#include <algorithm>
#include <new>
#include <set>
#include <ctype.h>
#include <string.h>
@@ -35,6 +37,7 @@
#include <Screen.h>
#include <ScrollBar.h>
#include <SystemCatalog.h>
#include <UnicodeChar.h>
#include <Window.h>
#include <AppServerLink.h>
@@ -69,15 +72,17 @@ public:
TriggerList() {}
~TriggerList() {}
// TODO: make this work with Unicode characters!
bool HasTrigger(uint32 c)
{ return fList.HasItem((void*)(addr_t)tolower(c)); }
{ return fList.find(BUnicodeChar::ToLower(c)) != fList.end(); }
bool AddTrigger(uint32 c)
{ return fList.AddItem((void*)(addr_t)tolower(c)); }
{
fList.insert(BUnicodeChar::ToLower(c));
return true;
}
private:
BList fList;
std::set<uint32> fList;
};
@@ -583,7 +588,7 @@ BMenu::KeyDown(const char* bytes, int32 numBytes)
default:
{
uint32 trigger = UTF8ToCharCode(&bytes);
uint32 trigger = BUnicodeChar::FromUTF8(&bytes);
for (uint32 i = CountItems(); i-- > 0;) {
BMenuItem* item = ItemAt(i);
@@ -2870,27 +2875,34 @@ BMenu::_ChooseTrigger(const char* title, int32& index, uint32& trigger,
if (title == NULL)
return false;
index = 0;
uint32 c;
const char* nextCharacter, *character;
// two runs: first we look out for uppercase letters
// TODO: support Unicode characters correctly!
for (uint32 i = 0; (c = title[i]) != '\0'; i++) {
if (!IsInsideGlyph(c) && isupper(c) && !triggers.HasTrigger(c)) {
index = i;
trigger = tolower(c);
return triggers.AddTrigger(c);
nextCharacter = title;
character = nextCharacter;
while ((c = BUnicodeChar::FromUTF8(&nextCharacter)) != 0) {
if (!BUnicodeChar::IsUpper(c) || triggers.HasTrigger(c)) {
character = nextCharacter;
continue;
}
trigger = BUnicodeChar::ToLower(c);
index = (int32)(character - title);
return triggers.AddTrigger(c);
}
// then, if we still haven't found anything, we accept them all
index = 0;
while ((c = UTF8ToCharCode(&title)) != 0) {
if (!isspace(c) && !triggers.HasTrigger(c)) {
trigger = tolower(c);
return triggers.AddTrigger(c);
nextCharacter = title;
character = nextCharacter;
while ((c = BUnicodeChar::FromUTF8(&nextCharacter)) != 0) {
if (BUnicodeChar::IsSpace(c) || triggers.HasTrigger(c)) {
character = nextCharacter;
continue;
}
index++;
trigger = BUnicodeChar::ToLower(c);
index = (int32)(character - title);
return triggers.AddTrigger(c);
}
return false;