From 588a0c9f67924884cc89bd26f12b70a82b3acadf Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 11 Dec 2018 21:43:30 +0100 Subject: [PATCH] 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 Some changes by me to make "index" a byte instead of character index as it needs to be. --- src/kits/interface/Menu.cpp | 52 +++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/kits/interface/Menu.cpp b/src/kits/interface/Menu.cpp index 8a36f77ce0..83d6d7e597 100644 --- a/src/kits/interface/Menu.cpp +++ b/src/kits/interface/Menu.cpp @@ -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, superstippi@gmx.de * Stefano Ceccherini, stefano.ceccherini@gmail.com + * Adrien Destugues, pulkomandy@pulkomandy.tk * Marc Flerackers, mflerackers@androme.be * Rene Gollent, anevilyak@gmail.com * John Scipione, jscipione@gmail.com @@ -15,6 +16,7 @@ #include #include +#include #include #include @@ -35,6 +37,7 @@ #include #include #include +#include #include #include @@ -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 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;