Merge pull request #3121 from OpenRCT2/fix-3091

fix #3091: Korean words corrupted if over byte limit
This commit is contained in:
Ted John 2016-03-10 18:49:28 +00:00
commit 53cd4c7935
16 changed files with 269 additions and 134 deletions

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
001085F01C90FD030075A2AD /* textinputbuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 001085EE1C90FD030075A2AD /* textinputbuffer.c */; };
C62A08D51C787C2A00F3AA76 /* drawing_fast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C62A08D41C787C2A00F3AA76 /* drawing_fast.cpp */; };
D41B73EF1C2101890080A7B9 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B73EE1C2101890080A7B9 /* libcurl.tbd */; };
D41B73F11C21018C0080A7B9 /* libssl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B73F01C21018C0080A7B9 /* libssl.tbd */; };
@ -221,6 +222,8 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
001085EE1C90FD030075A2AD /* textinputbuffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = textinputbuffer.c; sourceTree = "<group>"; };
001085EF1C90FD030075A2AD /* textinputbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = textinputbuffer.h; sourceTree = "<group>"; };
C62A08D41C787C2A00F3AA76 /* drawing_fast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = drawing_fast.cpp; sourceTree = "<group>"; };
D4163F671C2A044D00B83136 /* version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = version.h; path = src/version.h; sourceTree = "<group>"; };
D41B73EE1C2101890080A7B9 /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; };
@ -734,6 +737,8 @@
D4EC46E51C26342F0024B507 /* core */ = {
isa = PBXGroup;
children = (
001085EE1C90FD030075A2AD /* textinputbuffer.c */,
001085EF1C90FD030075A2AD /* textinputbuffer.h */,
D4B63B931C43028200367A37 /* Console.cpp */,
D4B63B941C43028200367A37 /* Console.hpp */,
D4A3511A1C6067B000CBCBA4 /* Diagnostics.hpp */,
@ -1383,6 +1388,7 @@
D4EC481A1C26342F0024B507 /* posix.c in Sources */,
D4D35E2C1C45BD9B00AAFCB4 /* Path.cpp in Sources */,
D4B63B981C43028F00367A37 /* String.cpp in Sources */,
001085F01C90FD030075A2AD /* textinputbuffer.c in Sources */,
D4A351211C60680300CBCBA4 /* Theme.cpp in Sources */,
D4EC47E31C26342F0024B507 /* cmdline_sprite.c in Sources */,
D4EC48611C26342F0024B507 /* text_input.c in Sources */,

View File

@ -34,6 +34,7 @@
<ClCompile Include="src\core\Path.cpp" />
<ClCompile Include="src\core\Stopwatch.cpp" />
<ClCompile Include="src\core\String.cpp" />
<ClCompile Include="src\core\textinputbuffer.c" />
<ClCompile Include="src\cursors.c" />
<ClCompile Include="src\diagnostic.c" />
<ClCompile Include="src\drawing\drawing.c" />
@ -217,6 +218,7 @@
<ClInclude Include="src\core\String.hpp" />
<ClInclude Include="src\core\StringBuilder.hpp" />
<ClInclude Include="src\core\StringReader.hpp" />
<ClInclude Include="src\core\textinputbuffer.h" />
<ClInclude Include="src\core\Util.hpp" />
<ClInclude Include="src\cursors.h" />
<ClInclude Include="src\diagnostic.h" />

View File

@ -584,6 +584,9 @@
<ClCompile Include="src\drawing\drawing_fast.cpp">
<Filter>Source\Drawing</Filter>
</ClCompile>
<ClCompile Include="src\core\textinputbuffer.c">
<Filter>Source\Core</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\management\award.h">
@ -890,5 +893,8 @@
<ClInclude Include="src\core\Guard.hpp" />
<ClInclude Include="src\core\Diagnostics.hpp" />
<ClInclude Include="src\core\Json.hpp" />
<ClInclude Include="src\core\textinputbuffer.h">
<Filter>Source\Core</Filter>
</ClInclude>
</ItemGroup>
</Project>

114
src/core/textinputbuffer.c Normal file
View File

@ -0,0 +1,114 @@
#include "../localisation/localisation.h"
#include "textinputbuffer.h"
void textinputbuffer_init(textinputbuffer * tib, utf8 * buffer, size_t size)
{
assert(buffer != NULL);
assert(size > 0);
tib->buffer = buffer;
tib->max_size = size - 1;
tib->current_size = strlen(buffer);
tib->selection_offset = tib->current_size;
tib->selection_size = 0;
textinputbuffer_recalculate_length(tib);
}
void textinputbuffer_clear(textinputbuffer * tib)
{
tib->buffer[0] = 0;
tib->current_size = 0;
tib->length = 0;
tib->selection_offset = 0;
tib->selection_size = 0;
}
void textinputbuffer_remove_selected(textinputbuffer * tib)
{
utf8 * targetShiftPtr = tib->buffer + tib->selection_offset;
utf8 * sourceShiftPtr = targetShiftPtr + tib->selection_size;
size_t shiftSize = tib->current_size - tib->selection_offset - tib->selection_size + 1;
memmove(targetShiftPtr, sourceShiftPtr, shiftSize);
tib->selection_size = 0;
textinputbuffer_recalculate_length(tib);
}
void textinputbuffer_insert_codepoint(textinputbuffer * tib, uint32 codepoint)
{
size_t codepointLength = utf8_get_codepoint_length(codepoint);
size_t remainingSize = tib->max_size - tib->current_size;
if (codepointLength <= remainingSize) {
utf8 * insertPtr = tib->buffer + tib->selection_offset;
if (tib->selection_offset < tib->current_size) {
// Shift bytes (including null terminator) right to make room for new codepoint
utf8 * targetShiftPtr = insertPtr + codepointLength;
size_t shiftSize = tib->current_size - tib->selection_offset + 1;
memmove(targetShiftPtr, insertPtr, shiftSize);
} else {
// Character is appended onto the end, so set byte after it to null terminator
tib->buffer[tib->current_size + codepointLength] = 0;
}
utf8_write_codepoint(insertPtr, codepoint);
tib->selection_offset += codepointLength;
tib->current_size += codepointLength;
tib->length++;
}
}
void textinputbuffer_insert(textinputbuffer * tib, utf8 * source)
{
const utf8 *ch = source;
uint32 codepoint;
while ((codepoint = utf8_get_next(ch, &ch)) != 0) {
textinputbuffer_insert_codepoint(tib, codepoint);
}
}
void textinputbuffer_cursor_left(textinputbuffer * tib)
{
size_t selectionOffset = tib->selection_offset;
if (selectionOffset > 0) {
const utf8 * ch = tib->buffer + selectionOffset;
do {
ch--;
selectionOffset--;
} while (!utf8_is_codepoint_start(ch) && selectionOffset > 0);
tib->selection_offset = selectionOffset;
}
}
void textinputbuffer_cursor_right(textinputbuffer * tib)
{
size_t selectionOffset = tib->selection_offset;
size_t selectionMaxOffset = tib->current_size;
if (selectionOffset < selectionMaxOffset) {
const utf8 * ch = tib->buffer + selectionOffset;
do {
ch++;
selectionOffset++;
} while (!utf8_is_codepoint_start(ch) && selectionOffset < selectionMaxOffset);
tib->selection_size = max(0, tib->selection_size - (selectionOffset - tib->selection_offset));
tib->selection_offset = selectionOffset;
}
}
void textinputbuffer_cursor_home(textinputbuffer * tib)
{
tib->selection_offset = 0;
}
void textinputbuffer_cursor_end(textinputbuffer * tib)
{
tib->selection_offset = tib->current_size;
}
void textinputbuffer_recalculate_length(textinputbuffer * tib)
{
tib->current_size = strlen(tib->buffer);
tib->length = utf8_length(tib->buffer);
}

View File

@ -0,0 +1,28 @@
#ifndef _TEXTINPUTBUFFER_H_
#define _TEXTINPUTBUFFER_H_
#include "../common.h"
typedef struct {
utf8 * buffer;
size_t max_size; // Maximum number of bytes (excluding null terminator)
size_t current_size; // Number of bytes (excluding null terminator)
uint32 length; // Number of codepoints
size_t selection_offset; // Selection start, in bytes
size_t selection_size; // Selection length in bytes
} textinputbuffer;
void textinputbuffer_init(textinputbuffer * tib, utf8 * buffer, size_t size);
void textinputbuffer_clear(textinputbuffer * tib);
void textinputbuffer_remove_selected(textinputbuffer * tib);
void textinputbuffer_insert_codepoint(textinputbuffer * tib, uint32 codepoint);
void textinputbuffer_insert(textinputbuffer * tib, utf8 * source);
void textinputbuffer_cursor_left(textinputbuffer * tib);
void textinputbuffer_cursor_right(textinputbuffer * tib);
void textinputbuffer_cursor_home(textinputbuffer * tib);
void textinputbuffer_cursor_end(textinputbuffer * tib);
void textinputbuffer_recalculate_length(textinputbuffer * tib);
#endif

View File

@ -91,8 +91,8 @@ void chat_draw()
gfx_set_dirty_blocks(x, y, x + gfx_get_string_width(lineBuffer) + 7, y + 12);
gfx_draw_string(dpi, lineBuffer, 255, x, y);
if (_chatCaretTicks < 15) {
memcpy(lineBuffer, _chatCurrentLine, gTextInputCursorPosition);
lineBuffer[gTextInputCursorPosition] = 0;
memcpy(lineBuffer, _chatCurrentLine, gTextInput.selection_offset);
lineBuffer[gTextInput.selection_offset] = 0;
int caretX = x + gfx_get_string_width(lineBuffer);
int caretY = y + 15;

View File

@ -214,8 +214,8 @@ void console_draw(rct_drawpixelinfo *dpi)
// Draw caret
if (_consoleCaretTicks < 15) {
memcpy(lineBuffer, _consoleCurrentLine, gTextInputCursorPosition);
lineBuffer[gTextInputCursorPosition] = 0;
memcpy(lineBuffer, _consoleCurrentLine, gTextInput.selection_offset);
lineBuffer[gTextInput.selection_offset] = 0;
int caretX = x + gfx_get_string_width(lineBuffer);
int caretY = y + lineHeight;
@ -249,15 +249,15 @@ void console_input(int c)
_consoleHistoryIndex--;
memcpy(_consoleCurrentLine, _consoleHistory[_consoleHistoryIndex], 256);
}
gTextInputCursorPosition = strlen(_consoleCurrentLine);
gTextInputLength = gTextInputCursorPosition;
textinputbuffer_recalculate_length(&gTextInput);
gTextInput.selection_offset = strlen(_consoleCurrentLine);
break;
case SDL_SCANCODE_DOWN:
if (_consoleHistoryIndex < _consoleHistoryCount - 1) {
_consoleHistoryIndex++;
memcpy(_consoleCurrentLine, _consoleHistory[_consoleHistoryIndex], 256);
gTextInputCursorPosition = strlen(_consoleCurrentLine);
gTextInputLength = gTextInputCursorPosition;
textinputbuffer_recalculate_length(&gTextInput);
gTextInput.selection_offset = strlen(_consoleCurrentLine);
} else {
_consoleHistoryIndex = _consoleHistoryCount;
console_clear_input();
@ -389,8 +389,9 @@ void console_refresh_caret()
static void console_clear_input()
{
_consoleCurrentLine[0] = 0;
gTextInputCursorPosition = 0;
gTextInputLength = 0;
gTextInput.selection_offset = 0;
gTextInput.selection_size = 0;
textinputbuffer_recalculate_length(&gTextInput);
}
static void console_history_add(const utf8 *src)

View File

@ -1191,15 +1191,15 @@ static void widget_text_box_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg
// Make a copy of the string for measuring the width.
char temp_string[512] = { 0 };
memcpy(temp_string, wrapped_string, min(string_length, gTextInputCursorPosition));
memcpy(temp_string, wrapped_string, min((size_t)string_length, gTextInput.selection_offset));
int cur_x = l + gfx_get_string_width(temp_string) + 3;
int width = 6;
if ((uint32)gTextInputCursorPosition < strlen(gTextBoxInput)){
if ((uint32)gTextInput.selection_offset < strlen(gTextBoxInput)){
// Make a new 1 character wide string for measuring the width
// of the character that the cursor is under.
temp_string[1] = '\0';
temp_string[0] = gTextBoxInput[gTextInputCursorPosition];
temp_string[0] = gTextBoxInput[gTextInput.selection_offset];
width = max(gfx_get_string_width(temp_string) - 2, 4);
}

View File

@ -78,7 +78,7 @@ rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/
uint32 utf8_get_next(const utf8 *char_ptr, const utf8 **nextchar_ptr);
utf8 *utf8_write_codepoint(utf8 *dst, uint32 codepoint);
int utf8_insert_codepoint(utf8 *dst, uint32 codepoint);
bool utf8_is_codepoint_start(utf8 *text);
bool utf8_is_codepoint_start(const utf8 *text);
void utf8_remove_format_codes(utf8 *text, bool allowcolours);
int utf8_get_codepoint_length(int codepoint);
int utf8_length(const utf8 *text);

View File

@ -55,7 +55,7 @@ rct_string_id user_string_allocate(int base, const utf8 *text)
if (userString[0] != 0)
continue;
safe_strcpy(userString, text, USER_STRING_MAX_LENGTH - 1);
safe_strcpy(userString, text, USER_STRING_MAX_LENGTH);
return 0x8000 + (i | highBits);
}
RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_MANY_NAMES_DEFINED;

View File

@ -65,7 +65,7 @@ int utf8_insert_codepoint(utf8 *dst, uint32 codepoint)
return shift;
}
bool utf8_is_codepoint_start(utf8 *text)
bool utf8_is_codepoint_start(const utf8 *text)
{
if ((text[0] & 0x80) == 0) return true;
if ((text[0] & 0xC0) == 0xC0) return true;

View File

@ -29,6 +29,7 @@
#include <SDL.h>
#include "../core/textinputbuffer.h"
#include "../drawing/font.h"
#ifndef MAX_PATH
@ -92,9 +93,8 @@ extern openrct2_cursor gCursorState;
extern const unsigned char *gKeysState;
extern unsigned char *gKeysPressed;
extern unsigned int gLastKeyPressed;
extern int gTextInputCursorPosition;
extern int gTextInputLength;
extern textinputbuffer gTextInput;
extern bool gTextInputCompositionActive;
extern utf8 gTextInputComposition[32];
extern int gTextInputCompositionStart;

View File

@ -42,10 +42,7 @@ openrct2_cursor gCursorState;
const unsigned char *gKeysState;
unsigned char *gKeysPressed;
unsigned int gLastKeyPressed;
utf8 *gTextInput;
int gTextInputLength;
int gTextInputMaxLength;
int gTextInputCursorPosition = 0;
textinputbuffer gTextInput;
bool gTextInputCompositionActive;
utf8 gTextInputComposition[32];
@ -594,90 +591,59 @@ void platform_process_messages()
}
// Text input
if (gTextInput.buffer == NULL) break;
// Clear the input on <CTRL>Backspace (Windows/Linux) or <MOD>Backspace (OS X)
if (gTextInput != NULL && e.key.keysym.sym == SDLK_BACKSPACE && (e.key.keysym.mod & KEYBOARD_PRIMARY_MODIFIER)) {
memset(gTextInput, '\0', gTextInputMaxLength);
gTextInputCursorPosition = 0;
gTextInputLength = 0;
if (e.key.keysym.sym == SDLK_BACKSPACE && (e.key.keysym.mod & KEYBOARD_PRIMARY_MODIFIER)) {
textinputbuffer_clear(&gTextInput);
console_refresh_caret();
window_update_textbox();
}
// If backspace and we have input text with a cursor position none zero
if (e.key.keysym.sym == SDLK_BACKSPACE && gTextInputLength > 0 && gTextInput != NULL && gTextInputCursorPosition) {
int dstIndex = gTextInputCursorPosition;
do {
if (dstIndex == 0) break;
dstIndex--;
} while (!utf8_is_codepoint_start(&gTextInput[dstIndex]));
int removedCodepointSize = gTextInputCursorPosition - dstIndex;
if (e.key.keysym.sym == SDLK_BACKSPACE) {
if (gTextInput.selection_offset > 0) {
size_t endOffset = gTextInput.selection_offset;
textinputbuffer_cursor_left(&gTextInput);
gTextInput.selection_size = endOffset - gTextInput.selection_offset;
textinputbuffer_remove_selected(&gTextInput);
// When at max length don't shift the data left
// as it would buffer overflow.
if (gTextInputCursorPosition != gTextInputMaxLength) {
memmove(gTextInput + dstIndex, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - dstIndex);
console_refresh_caret();
window_update_textbox();
}
gTextInput[gTextInputLength - removedCodepointSize] = '\0';
gTextInputCursorPosition -= removedCodepointSize;
gTextInputLength -= removedCodepointSize;
console_refresh_caret();
window_update_textbox();
}
if (e.key.keysym.sym == SDLK_END){
gTextInputCursorPosition = gTextInputLength;
console_refresh_caret();
}
if (e.key.keysym.sym == SDLK_HOME) {
gTextInputCursorPosition = 0;
textinputbuffer_cursor_home(&gTextInput);
console_refresh_caret();
}
if (e.key.keysym.sym == SDLK_DELETE && gTextInputLength > 0 && gTextInput != NULL && gTextInputCursorPosition != gTextInputLength) {
int dstIndex = gTextInputCursorPosition;
do {
if (dstIndex == gTextInputLength) break;
dstIndex++;
} while (!utf8_is_codepoint_start(&gTextInput[dstIndex]));
int removedCodepointSize = dstIndex - gTextInputCursorPosition;
memmove(gTextInput + gTextInputCursorPosition, gTextInput + dstIndex, gTextInputMaxLength - dstIndex);
gTextInput[gTextInputMaxLength - removedCodepointSize] = '\0';
gTextInputLength -= removedCodepointSize;
if (e.key.keysym.sym == SDLK_END) {
textinputbuffer_cursor_end(&gTextInput);
console_refresh_caret();
}
if (e.key.keysym.sym == SDLK_DELETE) {
size_t startOffset = gTextInput.selection_offset;
textinputbuffer_cursor_right(&gTextInput);
gTextInput.selection_size = gTextInput.selection_offset - startOffset;
gTextInput.selection_offset = startOffset;
textinputbuffer_remove_selected(&gTextInput);
console_refresh_caret();
window_update_textbox();
}
if (e.key.keysym.sym == SDLK_RETURN && gTextInput != NULL) {
if (e.key.keysym.sym == SDLK_RETURN) {
window_cancel_textbox();
}
if (e.key.keysym.sym == SDLK_LEFT && gTextInput != NULL) {
do {
if (gTextInputCursorPosition == 0) break;
gTextInputCursorPosition--;
} while (!utf8_is_codepoint_start(&gTextInput[gTextInputCursorPosition]));
if (e.key.keysym.sym == SDLK_LEFT) {
textinputbuffer_cursor_left(&gTextInput);
console_refresh_caret();
}
else if (e.key.keysym.sym == SDLK_RIGHT && gTextInput != NULL) {
do {
if (gTextInputCursorPosition == gTextInputLength) break;
gTextInputCursorPosition++;
} while (!utf8_is_codepoint_start(&gTextInput[gTextInputCursorPosition]));
else if (e.key.keysym.sym == SDLK_RIGHT) {
textinputbuffer_cursor_right(&gTextInput);
console_refresh_caret();
}
else if (e.key.keysym.sym == SDLK_v && (SDL_GetModState() & KEYBOARD_PRIMARY_MODIFIER) && gTextInput != NULL) {
else if (e.key.keysym.sym == SDLK_v && (SDL_GetModState() & KEYBOARD_PRIMARY_MODIFIER)) {
if (SDL_HasClipboardText()) {
utf8 *text = SDL_GetClipboardText();
for (int i = 0; text[i] != '\0' && gTextInputLength < gTextInputMaxLength; i++) {
// If inserting in center of string make space for new letter
if (gTextInputLength > gTextInputCursorPosition){
memmove(gTextInput + gTextInputCursorPosition + 1, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - gTextInputCursorPosition - 1);
gTextInput[gTextInputCursorPosition] = text[i];
gTextInputLength++;
} else {
gTextInput[gTextInputLength++] = text[i];
}
gTextInputCursorPosition++;
}
gTextInput[gTextInputLength] = '\0';
textinputbuffer_insert(&gTextInput, text);
window_update_textbox();
}
}
@ -713,33 +679,22 @@ void platform_process_messages()
// so, set gTextInputCompositionActive to false.
gTextInputCompositionActive = false;
if (gTextInputLength < gTextInputMaxLength && gTextInput){
// HACK ` will close console, so don't input any text
if (e.text.text[0] == '`' && gConsoleOpen)
break;
if (gTextInput.buffer == NULL) break;
// Entering formatting characters is not allowed
if (utf8_is_format_code(utf8_get_next(e.text.text, NULL)))
break;
utf8 *newText = e.text.text;
int newTextLength = strlen(newText);
// If inserting in center of string make space for new letter
if (gTextInputLength > gTextInputCursorPosition) {
memmove(gTextInput + gTextInputCursorPosition + newTextLength, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - gTextInputCursorPosition - newTextLength);
memcpy(&gTextInput[gTextInputCursorPosition], newText, newTextLength);
gTextInputLength += newTextLength;
} else {
memcpy(&gTextInput[gTextInputLength], newText, newTextLength);
gTextInputLength += newTextLength;
gTextInput[gTextInputLength] = 0;
}
gTextInputCursorPosition += newTextLength;
console_refresh_caret();
window_update_textbox();
// HACK ` will close console, so don't input any text
if (e.text.text[0] == '`' && gConsoleOpen) {
break;
}
// Entering formatting characters is not allowed
if (utf8_is_format_code(utf8_get_next(e.text.text, NULL))) {
break;
}
utf8 *newText = e.text.text;
textinputbuffer_insert(&gTextInput, newText);
console_refresh_caret();
window_update_textbox();
break;
default:
break;
@ -863,16 +818,14 @@ void platform_start_text_input(char* buffer, int max_length)
SDL_SetTextInputRect(&rect);
SDL_StartTextInput();
gTextInputMaxLength = max_length - 1;
gTextInput = buffer;
gTextInputCursorPosition = strnlen(gTextInput, max_length);
gTextInputLength = gTextInputCursorPosition;
textinputbuffer_init(&gTextInput, buffer, max_length);
}
void platform_stop_text_input()
{
SDL_StopTextInput();
gTextInput = NULL;
gTextInput.buffer = NULL;
gTextInputCompositionActive = false;
}

View File

@ -18,9 +18,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "util.h"
// Include common.h before SDL, otherwise M_PI gets redefined
#include "../common.h"
#include <SDL.h>
#include "../localisation/localisation.h"
#include "../platform/platform.h"
#include "util.h"
#include "zlib.h"
bool gUseRLE = true;
@ -202,31 +206,51 @@ int strcicmp(char const *a, char const *b)
}
}
utf8 * safe_strtrunc(utf8 * text, size_t size)
{
assert(text != NULL);
if (size == 0) return text;
const char *sourceLimit = text + size - 1;
char *ch = text;
char *last = text;
uint32 codepoint;
while ((codepoint = utf8_get_next(ch, &ch)) != 0) {
if (ch <= sourceLimit) {
last = ch;
} else {
break;
}
}
*last = 0;
return text;
}
char *safe_strcpy(char * destination, const char * source, size_t size)
{
assert(destination != NULL);
assert(source != NULL);
if (size == 0)
{
return destination;
}
char *result = destination;
bool terminated = false;
for (size_t i = 0; i < size; i++)
{
if (*source != '\0')
{
*destination++ = *source++;
if (size == 0) return destination;
char * result = destination;
bool truncated = false;
const char *sourceLimit = source + size - 1;
const char *ch = source;
uint32 codepoint;
while ((codepoint = utf8_get_next(ch, &ch)) != 0) {
if (ch <= sourceLimit) {
destination = utf8_write_codepoint(destination, codepoint);
} else {
*destination = *source;
terminated = true;
break;
truncated = true;
}
}
if (!terminated)
{
result[size - 1] = '\0';
*destination = 0;
if (truncated) {
log_warning("Truncating string \"%s\" to %d bytes.", result, size);
}
return result;

View File

@ -43,6 +43,7 @@ int bitscanforward(int source);
int bitcount(int source);
bool strequals(const char *a, const char *b, int length, bool caseInsensitive);
int strcicmp(char const *a, char const *b);
utf8 * safe_strtrunc(utf8 * text, size_t size);
char *safe_strcpy(char * destination, const char * source, size_t num);
char *safe_strcat(char *destination, const char *source, size_t size);
char *safe_strcat_path(char *destination, const char *source, size_t size);

View File

@ -293,19 +293,19 @@ static void window_text_input_paint(rct_window *w, rct_drawpixelinfo *dpi)
int string_length = get_string_size(wrap_pointer) - 1;
if (!cur_drawn && (gTextInputCursorPosition <= char_count + string_length)) {
if (!cur_drawn && (gTextInput.selection_offset <= (size_t)(char_count + string_length))) {
// Make a copy of the string for measuring the width.
char temp_string[512] = { 0 };
memcpy(temp_string, wrap_pointer, gTextInputCursorPosition - char_count);
memcpy(temp_string, wrap_pointer, gTextInput.selection_offset - char_count);
cursorX = w->x + 13 + gfx_get_string_width(temp_string);
cursorY = y;
int width = 6;
if ((uint32)gTextInputCursorPosition < strlen(text_input)){
if ((uint32)gTextInput.selection_offset < strlen(text_input)){
// Make a new 1 character wide string for measuring the width
// of the character that the cursor is under.
temp_string[1] = '\0';
temp_string[0] = text_input[gTextInputCursorPosition];
temp_string[0] = text_input[gTextInput.selection_offset];
width = max(gfx_get_string_width(temp_string) - 2, 4);
}