diff --git a/src/cmdline/RootCommands.cpp b/src/cmdline/RootCommands.cpp index 131518a4ab..25bf1ee15d 100644 --- a/src/cmdline/RootCommands.cpp +++ b/src/cmdline/RootCommands.cpp @@ -344,7 +344,7 @@ static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator) // Check user path that will contain the config utf8 userPath[MAX_PATH]; platform_resolve_user_data_path(); - platform_get_user_directory(userPath, NULL); + platform_get_user_directory(userPath, NULL, sizeof(userPath)); if (!platform_ensure_directory_exists(userPath)) { Console::Error::WriteLine("Unable to access or create directory '%s'.", userPath); return EXITCODE_FAIL; diff --git a/src/cmdline_sprite.c b/src/cmdline_sprite.c index 33eb6f371e..82895773dd 100644 --- a/src/cmdline_sprite.c +++ b/src/cmdline_sprite.c @@ -547,7 +547,7 @@ int cmdline_for_sprite(const char **argv, int argc) for (int x = 0; x < numbers; x++){ outputPath[pathLen + x] = '0'; } - safe_strcpy(outputPath + pathLen + numbers, ".png", MAX_PATH); + safe_strcpy(outputPath + pathLen + numbers, ".png", MAX_PATH - pathLen - numbers); for (int spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++){ @@ -651,7 +651,9 @@ int cmdline_for_sprite(const char **argv, int argc) safe_strcpy(imagePath, resourcePath, MAX_PATH); if (resourcePath[resourceLength - 1] == '/' || resourcePath[resourceLength - 1] == '\\') imagePath[resourceLength - 1] = 0; - sprintf(imagePath, "%s%c%d.png", imagePath, platform_get_path_separator(), i); + char filename[16]; + snprintf(filename, 16, "%d.png", i); + safe_strcat_path(imagePath, filename, MAX_PATH); file = SDL_RWFromFile(imagePath, "r"); if (file != NULL) { diff --git a/src/config.c b/src/config.c index 736028511f..13d0e8631a 100644 --- a/src/config.c +++ b/src/config.c @@ -371,7 +371,7 @@ static void rwopsprintf(SDL_RWops *file, const char *format, ...) va_start(args, format); char buffer[64]; - vsprintf(buffer, format, args); + vsnprintf(buffer, 64, format, args); SDL_RWwrite(file, buffer, strlen(buffer), 1); @@ -380,7 +380,7 @@ static void rwopsprintf(SDL_RWops *file, const char *format, ...) static void rwopswritenewline(SDL_RWops *file) { - rwopswritestr(file, platform_get_new_line()); + rwopswritestr(file, PLATFORM_NEWLINE); } static void rwopswritestresc(SDL_RWops *file, const char *str) { @@ -468,17 +468,17 @@ void config_release() } } -void config_get_default_path(utf8 *outPath) +void config_get_default_path(utf8 *outPath, size_t size) { - platform_get_user_directory(outPath, NULL); - strcat(outPath, "config.ini"); + platform_get_user_directory(outPath, NULL, size); + safe_strcat_path(outPath, "config.ini", size); } bool config_open_default() { utf8 path[MAX_PATH]; - config_get_default_path(path); + config_get_default_path(path, sizeof(path)); if (config_open(path)) { currency_load_custom_currency_config(); return true; @@ -491,7 +491,7 @@ bool config_save_default() { utf8 path[MAX_PATH]; - config_get_default_path(path); + config_get_default_path(path, sizeof(path)); if (config_save(path)) { return true; } @@ -950,9 +950,8 @@ bool config_find_or_browse_install_directory() if (platform_original_game_data_exists(installPath)) return true; - utf8 message[MAX_PATH] = { 0 }; - char separator = platform_get_path_separator(); - sprintf(message, "Could not find %s%cData%cg1.dat at this path", installPath, separator, separator); + utf8 message[MAX_PATH]; + snprintf(message, MAX_PATH, "Could not find %s" PATH_SEPARATOR "Data" PATH_SEPARATOR "g1.dat at this path", installPath); platform_show_messagebox(message); } } @@ -1043,10 +1042,10 @@ void config_reset_shortcut_keys() memcpy(gShortcutKeys, _defaultShortcutKeys, sizeof(gShortcutKeys)); } -static void config_shortcut_keys_get_path(utf8 *outPath) +static void config_shortcut_keys_get_path(utf8 *outPath, size_t size) { - platform_get_user_directory(outPath, NULL); - strcat(outPath, "hotkeys.cfg"); + platform_get_user_directory(outPath, NULL, size); + safe_strcat_path(outPath, "hotkeys.cfg", size); } bool config_shortcut_keys_load() @@ -1056,7 +1055,7 @@ bool config_shortcut_keys_load() bool result; uint16 version; - config_shortcut_keys_get_path(path); + config_shortcut_keys_get_path(path, sizeof(path)); file = SDL_RWFromFile(path, "rb"); if (file != NULL) { @@ -1086,7 +1085,7 @@ bool config_shortcut_keys_save() SDL_RWops *file; bool result; - config_shortcut_keys_get_path(path); + config_shortcut_keys_get_path(path, sizeof(path)); file = SDL_RWFromFile(path, "wb"); if (file != NULL) { @@ -1112,34 +1111,39 @@ void title_sequences_set_default() { char path[MAX_PATH]; char dataPath[MAX_PATH]; - char sep = platform_get_path_separator(); - platform_get_user_directory(path, "title sequences"); + platform_get_user_directory(path, "title sequences", sizeof(path)); platform_ensure_directory_exists(path); gConfigTitleSequences.presets = malloc(0); gConfigTitleSequences.num_presets = 0; - platform_get_openrct_data_path(dataPath); + platform_get_openrct_data_path(dataPath, sizeof(dataPath)); + safe_strcat_path(dataPath, "title", MAX_PATH); // RCT1 title sequence - sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "rct1", sep); + safe_strcpy(path, dataPath, MAX_PATH); + safe_strcat_path(path, "rct1", MAX_PATH); title_sequence_open(path, language_get_string(STR_TITLE_SEQUENCE_RCT1)); // RCT1 (AA) title sequence - sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "rct1aa", sep); + safe_strcpy(path, dataPath, MAX_PATH); + safe_strcat_path(path, "rct1aa", MAX_PATH); title_sequence_open(path, language_get_string(STR_TITLE_SEQUENCE_RCT1_AA)); // RCT1 (AA + LL) title sequence - sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "rct1aall", sep); + safe_strcpy(path, dataPath, MAX_PATH); + safe_strcat_path(path, "rct1aall", MAX_PATH); title_sequence_open(path, language_get_string(STR_TITLE_SEQUENCE_RCT1_AA_LL)); // RCT2 title sequence - sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "rct2", sep); + safe_strcpy(path, dataPath, MAX_PATH); + safe_strcat_path(path, "rct2", MAX_PATH); title_sequence_open(path, language_get_string(STR_TITLE_SEQUENCE_RCT2)); // OpenRCT2 title sequence - sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "openrct2", sep); + safe_strcpy(path, dataPath, MAX_PATH); + safe_strcat_path(path, "openrct2", MAX_PATH); title_sequence_open(path, language_get_string(STR_TITLE_SEQUENCE_OPENRCT2)); } @@ -1149,11 +1153,11 @@ void title_sequences_load_presets() int dirEnumHandle, i; // Find all directories in the title sequences folder - platform_get_user_directory(path, "title sequences"); + platform_get_user_directory(path, "title sequences", sizeof(path)); dirEnumHandle = platform_enumerate_directories_begin(path); while (platform_enumerate_directories_next(dirEnumHandle, titleDir)) { - platform_get_user_directory(path, "title sequences"); - strcat(path, titleDir); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat(path, titleDir, sizeof(path)); title_sequence_open(path, NULL); } platform_enumerate_directories_end(dirEnumHandle); @@ -1197,8 +1201,8 @@ static void title_sequence_open(const char *path, const char *customName) char parts[3 * 128], *token, *part1, *part2; // Check for the script file - safe_strcpy(scriptPath, path, MAX_PATH); - strcat(scriptPath, "script.txt"); + safe_strcpy(scriptPath, path, sizeof(scriptPath)); + safe_strcat_path(scriptPath, "script.txt", sizeof(scriptPath)); if (!platform_file_exists(scriptPath)) { // No script file, title sequence is invalid return; @@ -1221,9 +1225,9 @@ static void title_sequence_open(const char *path, const char *customName) safe_strcpy(nameBuffer, path, MAX_PATH); // Get folder name // First strip off the last folder separator - *strrchr(nameBuffer, platform_get_path_separator()) = '\0'; + *strrchr(nameBuffer, *PATH_SEPARATOR) = '\0'; // Then find the name of the folder - char *name = strrchr(nameBuffer, platform_get_path_separator()) + 1; + char *name = strrchr(nameBuffer, *PATH_SEPARATOR) + 1; safe_strcpy(gConfigTitleSequences.presets[preset].name, name, TITLE_SEQUENCE_NAME_SIZE); gConfigTitleSequences.presets[preset].path[0] = 0; } @@ -1239,8 +1243,8 @@ static void title_sequence_open(const char *path, const char *customName) } // Get the save file list - safe_strcpy(titlePath, path, MAX_PATH); - strcat(titlePath, "*.sv6"); + safe_strcpy(titlePath, path, sizeof(titlePath)); + safe_strcat_path(titlePath, "*.sv6", sizeof(titlePath)); fileEnumHandle = platform_enumerate_files_begin(titlePath); while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { gConfigTitleSequences.presets[preset].num_saves++; @@ -1249,8 +1253,8 @@ static void title_sequence_open(const char *path, const char *customName) gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1][TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1] = '\0'; } platform_enumerate_files_end(fileEnumHandle); - safe_strcpy(titlePath, path, MAX_PATH); - strcat(titlePath, "*.sc6"); + safe_strcpy(titlePath, path, sizeof(titlePath)); + safe_strcat_path(titlePath, "*.sc6", sizeof(titlePath)); fileEnumHandle = platform_enumerate_files_begin(titlePath); while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { gConfigTitleSequences.presets[preset].num_saves++; @@ -1321,13 +1325,11 @@ void title_sequence_save_preset_script(int preset) utf8 path[MAX_PATH]; SDL_RWops *file; int i; - char separator = platform_get_path_separator(); - platform_get_user_directory(path, "title sequences"); - strcat(path, gConfigTitleSequences.presets[preset].name); - strncat(path, &separator, 1); - strcat(path, "script.txt"); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[preset].name, MAX_PATH); + safe_strcat_path(path, "script.txt", MAX_PATH); file = SDL_RWFromFile(path, "wb"); if (file == NULL) { diff --git a/src/config.h b/src/config.h index dcf76859bb..750e1692bd 100644 --- a/src/config.h +++ b/src/config.h @@ -345,7 +345,7 @@ extern title_sequences_configuration gConfigTitleSequences; extern uint16 gShortcutKeys[SHORTCUT_COUNT]; -void config_get_default_path(utf8 *outPath); +void config_get_default_path(utf8 *outPath, size_t size); void config_set_defaults(); void config_release(); bool config_open_default(); diff --git a/src/core/Console.cpp b/src/core/Console.cpp index 5c75d249a0..d9d90b1bf0 100644 --- a/src/core/Console.cpp +++ b/src/core/Console.cpp @@ -88,7 +88,7 @@ namespace Console void WriteLine() { - fputs(platform_get_new_line(), stderr); + fputs(PLATFORM_NEWLINE, stderr); } void WriteLine(const utf8 * format, ...) @@ -105,4 +105,4 @@ namespace Console puts(""); } } -} \ No newline at end of file +} diff --git a/src/core/Guard.cpp b/src/core/Guard.cpp index 710a4d90e8..2b6518aa39 100644 --- a/src/core/Guard.cpp +++ b/src/core/Guard.cpp @@ -75,7 +75,8 @@ namespace Guard if (message != nullptr) { strcat(buffer, "\r\n"); - vsprintf((char *)strchr(buffer, 0), message, args); + char *bufend = (char *)strchr(buffer, 0); + vsnprintf(bufend, sizeof(buffer) - (bufend - buffer), message, args); } int result = MessageBox(nullptr, buffer, OPENRCT2_NAME, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION); if (result == IDABORT) diff --git a/src/core/Path.cpp b/src/core/Path.cpp index ccbcd6a952..f0e6735381 100644 --- a/src/core/Path.cpp +++ b/src/core/Path.cpp @@ -36,8 +36,7 @@ namespace Path utf8 * GetDirectory(utf8 * buffer, size_t bufferSize, const utf8 * path) { - const char pathSeperator = platform_get_path_separator(); - size_t lastPathSepIndex = String::LastIndexOf(path, pathSeperator); + size_t lastPathSepIndex = String::LastIndexOf(path, *PATH_SEPARATOR); if (lastPathSepIndex == SIZE_MAX) { return String::Set(buffer, bufferSize, String::Empty); @@ -54,7 +53,7 @@ namespace Path const utf8 * lastPathSeperator = nullptr; for (const utf8 * ch = path; *ch != '\0'; ch++) { - if (*ch == platform_get_path_separator()) + if (*ch == *PATH_SEPARATOR) { lastPathSeperator = ch; } diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 971d9951e5..3587d0afeb 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -277,7 +277,7 @@ public: if (_context == nullptr) { char szRequiredVersion[32]; - sprintf(szRequiredVersion, "OpenGL %d.%d", requiredVersion.Major, requiredVersion.Minor); + snprintf(szRequiredVersion, 32, "OpenGL %d.%d", requiredVersion.Major, requiredVersion.Minor); throw Exception(std::string(szRequiredVersion) + std::string(" not available.")); } SDL_GL_MakeCurrent(_window, _context); diff --git a/src/drawing/engines/opengl/OpenGLShaderProgram.cpp b/src/drawing/engines/opengl/OpenGLShaderProgram.cpp index 922b3af625..575804c76e 100644 --- a/src/drawing/engines/opengl/OpenGLShaderProgram.cpp +++ b/src/drawing/engines/opengl/OpenGLShaderProgram.cpp @@ -70,7 +70,7 @@ GLuint OpenGLShader::GetShaderId() void OpenGLShader::GetPath(char * buffer, size_t bufferSize, const char * name) { - platform_get_openrct_data_path(buffer); + platform_get_openrct_data_path(buffer, bufferSize); Path::Append(buffer, bufferSize, "shaders"); Path::Append(buffer, bufferSize, name); if (_type == GL_VERTEX_SHADER) diff --git a/src/drawing/scrolling_text.c b/src/drawing/scrolling_text.c index b5597b9ead..df8d2e0a98 100644 --- a/src/drawing/scrolling_text.c +++ b/src/drawing/scrolling_text.c @@ -133,12 +133,12 @@ static uint8 scrolling_text_get_colour(uint32 character) } } -static void scrolling_text_format(utf8 *dst, rct_draw_scroll_text *scrollText) +static void scrolling_text_format(utf8 *dst, size_t size, rct_draw_scroll_text *scrollText) { if (gConfigGeneral.upper_case_banners) { - format_string_to_upper(dst, scrollText->string_id, &scrollText->string_args_0); + format_string_to_upper(dst, size, scrollText->string_id, &scrollText->string_args_0); } else { - format_string(dst, scrollText->string_id, &scrollText->string_args_0); + format_string(dst, size, scrollText->string_id, &scrollText->string_args_0); } } @@ -1442,7 +1442,7 @@ int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrolling // Create the string to draw utf8 scrollString[256]; - scrolling_text_format(scrollString, scrollText); + scrolling_text_format(scrollString, 256, scrollText); const sint16* scrollingModePositions = _scrollPositions[scrollingMode]; diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index 495e6a4c21..c806d56aa7 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.c @@ -19,6 +19,7 @@ #include "../openrct2.h" #include "../platform/platform.h" #include "../sprites.h" +#include "../util/util.h" #include "drawing.h" void *_g1Buffer = NULL; @@ -152,10 +153,9 @@ bool gfx_load_g2() unsigned int i; char path[MAX_PATH]; - char dataPath[MAX_PATH]; - platform_get_openrct_data_path(dataPath); - sprintf(path, "%s%cg2.dat", dataPath, platform_get_path_separator()); + platform_get_openrct_data_path(path, sizeof(path)); + safe_strcat_path(path, "g2.dat", MAX_PATH); file = SDL_RWFromFile(path, "rb"); if (file != NULL) { if (SDL_RWread(file, &g2.header, 8, 1) == 1) { diff --git a/src/drawing/string.c b/src/drawing/string.c index 77977ae4f4..a6e4980965 100644 --- a/src/drawing/string.c +++ b/src/drawing/string.c @@ -247,7 +247,7 @@ int gfx_wrap_string(utf8 *text, int width, int *outNumLines, int *outFontHeight) void gfx_draw_string_left_clipped(rct_drawpixelinfo* dpi, rct_string_id format, void* args, int colour, int x, int y, int width) { char* buffer = gCommonStringFormatBuffer; - format_string(buffer, format, args); + format_string(buffer, 256, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; @@ -272,7 +272,7 @@ void gfx_draw_string_left_clipped(rct_drawpixelinfo* dpi, rct_string_id format, void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y, int width) { char* buffer = gCommonStringFormatBuffer; - format_string(buffer, format, args); + format_string(buffer, 256, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; @@ -301,7 +301,7 @@ void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, rct_string_id forma void gfx_draw_string_right(rct_drawpixelinfo* dpi, rct_string_id format, void* args, int colour, int x, int y) { char* buffer = gCommonStringFormatBuffer; - format_string(buffer, format, args); + format_string(buffer, 256, format, args); // Measure text width short text_width = gfx_get_string_width(buffer); @@ -347,7 +347,7 @@ int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, i char *buffer = gCommonStringFormatBuffer; gfx_draw_string(dpi, "", colour, dpi->x, dpi->y); - format_string(buffer, format, args); + format_string(buffer, 256, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; @@ -394,7 +394,7 @@ int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int char *buffer = gCommonStringFormatBuffer; gfx_draw_string(dpi, "", colour, dpi->x, dpi->y); - format_string(buffer, format, args); + format_string(buffer, 256, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase); @@ -423,7 +423,7 @@ int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int void gfx_draw_string_left(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y) { char* buffer = gCommonStringFormatBuffer; - format_string(buffer, format, args); + format_string(buffer, 256, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_draw_string(dpi, buffer, colour, x, y); } @@ -435,7 +435,7 @@ void gfx_draw_string_left_centred(rct_drawpixelinfo *dpi, rct_string_id format, { gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; char *buffer = gCommonStringFormatBuffer; - format_string(buffer, format, args); + format_string(buffer, 256, format, args); int height = string_get_height_raw(buffer); gfx_draw_string(dpi, buffer, colour, x, y - (height / 2)); } @@ -500,7 +500,7 @@ void draw_string_left_underline(rct_drawpixelinfo *dpi, rct_string_id format, vo char buffer[128]; int width; - format_string(buffer, format, args); + format_string(buffer, 128, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; width = gfx_get_string_width(buffer); gfx_draw_string(dpi, buffer, colour, x, y); @@ -514,7 +514,7 @@ void draw_string_right_underline(rct_drawpixelinfo *dpi, rct_string_id format, v char buffer[128]; int width; - format_string(buffer, format, args); + format_string(buffer, 128, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; width = gfx_get_string_width(buffer); x -= width; @@ -529,7 +529,7 @@ void draw_string_centred_underline(rct_drawpixelinfo *dpi, rct_string_id format, char buffer[128]; int width; - format_string(buffer, format, args); + format_string(buffer, 128, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; width = gfx_get_string_width(buffer); x -= width / 2; @@ -655,7 +655,7 @@ void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, int x, int gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_draw_string(dpi, "", colour, dpi->x, dpi->y); - format_string(buffer, format, args); + format_string(buffer, 256, format, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; @@ -844,7 +844,7 @@ bool ttf_initialise() TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]); utf8 fontPath[MAX_PATH]; - if (!platform_get_font_path(fontDesc, fontPath)) { + if (!platform_get_font_path(fontDesc, fontPath, sizeof(fontPath))) { log_error("Unable to load font '%s'", fontDesc->font_name); return false; } @@ -1345,7 +1345,7 @@ void shorten_path(utf8 *buffer, size_t bufferSize, const utf8 *path, int availab // Count path separators int path_separators = 0; for (size_t x = 0; x < length; x++) { - if (path[x] == platform_get_path_separator()) { + if (path[x] == *PATH_SEPARATOR) { path_separators++; } } @@ -1358,7 +1358,7 @@ void shorten_path(utf8 *buffer, size_t bufferSize, const utf8 *path, int availab for (int x = 0; x < path_separators; x++){ do { begin++; - } while (path[begin] != platform_get_path_separator()); + } while (path[begin] != *PATH_SEPARATOR); safe_strcpy(buffer + 3, path + begin, bufferSize - 3); if (gfx_get_string_width(buffer) <= availableWidth) { diff --git a/src/game.c b/src/game.c index fc332dc45a..4de4948727 100644 --- a/src/game.c +++ b/src/game.c @@ -675,8 +675,7 @@ static void rct2_to_utf8_self(char *buffer, size_t length) char tempBuffer[512]; if (length > 0) { rct2_to_utf8(tempBuffer, buffer); - strncpy(buffer, tempBuffer, length - 1); - buffer[length - 1] = '\0'; + safe_strcpy(buffer, tempBuffer, length); } } @@ -954,8 +953,8 @@ static void limit_autosave_count(const size_t numberOfFilesToKeep) size_t i=0; - platform_get_user_directory(filter, "save"); - strncat(filter, "autosave_*.sv6", sizeof(filter) - strnlen(filter, MAX_PATH) - 1); + platform_get_user_directory(filter, "save", sizeof(filter)); + safe_strcat_path(filter, "autosave_*.sv6", sizeof(filter)); // At first, count how many autosaves there are fileEnumHandle = platform_enumerate_files_begin(filter); @@ -977,8 +976,8 @@ static void limit_autosave_count(const size_t numberOfFilesToKeep) memset(autosaveFiles[i], 0, sizeof(utf8) * MAX_PATH); if(platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { - platform_get_user_directory(autosaveFiles[i], "save"); - strcat(autosaveFiles[i], fileInfo.path); + platform_get_user_directory(autosaveFiles[i], "save", sizeof(utf8) * MAX_PATH); + safe_strcat_path(autosaveFiles[i], fileInfo.path, sizeof(utf8) * MAX_PATH); } } platform_enumerate_files_end(fileEnumHandle); @@ -1008,7 +1007,7 @@ void game_autosave() { utf8 path[MAX_PATH]; utf8 backupPath[MAX_PATH]; - utf8 timeString[21]=""; + utf8 timeName[34]; // retrieve current time rct2_date currentDate; @@ -1016,18 +1015,15 @@ void game_autosave() rct2_time currentTime; platform_get_time_local(¤tTime); - sprintf(timeString, "%d-%02d-%02d_%02d-%02d-%02d", currentDate.year, currentDate.month, currentDate.day, currentTime.hour, currentTime.minute,currentTime.second); + snprintf(timeName, 34, "autosave_%d-%02d-%02d_%02d-%02d-%02d.sv6", currentDate.year, currentDate.month, currentDate.day, currentTime.hour, currentTime.minute,currentTime.second); limit_autosave_count(NUMBER_OF_AUTOSAVES_TO_KEEP); - platform_get_user_directory(path, "save"); - safe_strcpy(backupPath, path, MAX_PATH); + platform_get_user_directory(path, "save", sizeof(path)); + safe_strcpy(backupPath, path, sizeof(backupPath)); - strcat(path, "autosave_"); - strcat(path, timeString); - strcat(path, ".sv6"); - - strcat(backupPath, "autosave.sv6.bak"); + safe_strcat_path(path, timeName, sizeof(path)); + safe_strcat_path(backupPath, "autosave.sv6.bak", sizeof(backupPath)); if (platform_file_exists(path)) { platform_file_copy(path, backupPath, true); @@ -1048,10 +1044,10 @@ void rct2_exit_reason(rct_string_id title, rct_string_id body){ // Before this would set a quit message char exit_title[255]; - format_string(exit_title, title, 0); + format_string(exit_title, 256, title, 0); char exit_body[255]; - format_string(exit_body, body, 0); + format_string(exit_body, 256, body, 0); log_error(exit_title); log_error(exit_body); diff --git a/src/interface/Theme.cpp b/src/interface/Theme.cpp index 1e91fb5540..3691dc02c3 100644 --- a/src/interface/Theme.cpp +++ b/src/interface/Theme.cpp @@ -644,7 +644,7 @@ namespace ThemeManager void GetThemePath(utf8 * buffer, size_t bufferSize) { - platform_get_user_directory(buffer, "themes"); + platform_get_user_directory(buffer, "themes", bufferSize); } } diff --git a/src/interface/chat.c b/src/interface/chat.c index c61334a76d..40a8e09b65 100644 --- a/src/interface/chat.c +++ b/src/interface/chat.c @@ -102,7 +102,7 @@ void chat_draw(rct_drawpixelinfo * dpi) continue; } - safe_strcpy(lineBuffer, chat_history_get(i), CHAT_INPUT_SIZE + 10); + safe_strcpy(lineBuffer, chat_history_get(i), sizeof(lineBuffer)); int lineHeight = chat_string_wrapped_get_height((void*)&lineCh, _chatWidth - 10); _chatTop -= (lineHeight + 5); @@ -134,7 +134,7 @@ void chat_draw(rct_drawpixelinfo * dpi) break; } - safe_strcpy(lineBuffer, chat_history_get(i), CHAT_INPUT_SIZE + 10); + safe_strcpy(lineBuffer, chat_history_get(i), sizeof(lineBuffer)); stringHeight = chat_history_draw_string(dpi, (void*) &lineCh, x, y, _chatWidth - 10) + 5; gfx_set_dirty_blocks(x, y - stringHeight, x + _chatWidth, y + 20); @@ -220,7 +220,7 @@ int chat_history_draw_string(rct_drawpixelinfo *dpi, void *args, int x, int y, i gfx_draw_string(dpi, "", 255, dpi->x, dpi->y); char *buffer = gCommonStringFormatBuffer; - format_string(buffer, STR_STRING, args); + format_string(buffer, 256, STR_STRING, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase); @@ -251,7 +251,7 @@ int chat_string_wrapped_get_height(void *args, int width) gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; char *buffer = gCommonStringFormatBuffer; - format_string(buffer, STR_STRING, args); + format_string(buffer, 256, STR_STRING, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase); diff --git a/src/interface/console.c b/src/interface/console.c index 1f0ea731b2..a7bfb42124 100644 --- a/src/interface/console.c +++ b/src/interface/console.c @@ -205,7 +205,7 @@ void console_draw(rct_drawpixelinfo *dpi) size_t lineLength = min(sizeof(lineBuffer) - (size_t)utf8_get_codepoint_length(FORMAT_WHITE), (size_t)(nextLine - ch)); lineCh = lineBuffer; lineCh = utf8_write_codepoint(lineCh, FORMAT_WHITE); - strncpy(lineCh, ch, lineLength); + memcpy(lineCh, ch, lineLength); lineCh[lineLength] = 0; gfx_draw_string(dpi, lineBuffer, 100, x, y); //Value 100 outlines the letters @@ -226,7 +226,7 @@ void console_draw(rct_drawpixelinfo *dpi) // Draw current line lineCh = lineBuffer; lineCh = utf8_write_codepoint(lineCh, FORMAT_WHITE); - strcpy(lineCh, _consoleCurrentLine); + safe_strcpy(lineCh, _consoleCurrentLine, sizeof(lineBuffer) - (lineCh - lineBuffer)); gfx_draw_string(dpi, lineBuffer, 255, x, y); // Draw caret @@ -301,8 +301,9 @@ void console_write(const utf8 *src) if (charactersToWrite > charactersRemainingInBuffer) { memmove(_consoleBuffer, _consoleBuffer + bufferShift, CONSOLE_BUFFER_SIZE - bufferShift); _consoleBufferPointer -= bufferShift; + charactersRemainingInBuffer = CONSOLE_BUFFER_SIZE - (_consoleBufferPointer - _consoleBuffer) - 1; } - strcpy(_consoleBufferPointer, src); + safe_strcpy(_consoleBufferPointer, src, charactersRemainingInBuffer); _consoleBufferPointer += charactersToWrite; console_update_scroll(); } @@ -315,14 +316,14 @@ void console_writeline(const utf8 *src) void console_writeline_error(const utf8 *src) { - strcpy(_consoleErrorBuffer + 1, src); + safe_strcpy(_consoleErrorBuffer + 1, src, CONSOLE_BUFFER_2_SIZE - 1); _consoleErrorBuffer[0] = FORMAT_RED; console_writeline(_consoleErrorBuffer); } void console_writeline_warning(const utf8 *src) { - strcpy(_consoleErrorBuffer + 1, src); + safe_strcpy(_consoleErrorBuffer + 1, src, CONSOLE_BUFFER_2_SIZE - 1); _consoleErrorBuffer[0] = FORMAT_YELLOW; console_writeline(_consoleErrorBuffer); } @@ -331,7 +332,7 @@ void console_printf(const utf8 *format, ...) { va_list list; va_start(list, format); - vsprintf(_consolePrintfBuffer, format, list); + vsnprintf(_consolePrintfBuffer, sizeof(_consolePrintfBuffer), format, list); va_end(list); console_writeline(_consolePrintfBuffer); } @@ -449,7 +450,7 @@ static int cc_rides(const utf8 **argv, int argc) int i; FOR_ALL_RIDES(i, ride) { char name[128]; - format_string(name, ride->name, &ride->name_arguments); + format_string(name, 128, ride->name, &ride->name_arguments); console_printf("rides %03d type: %02u subtype %03u name %s", i, ride->type, ride->subtype, name); } } else if (strcmp(argv[0], "set") == 0) { @@ -515,7 +516,7 @@ static int cc_staff(const utf8 **argv, int argc) int i; FOR_ALL_STAFF(i, peep) { char name[128]; - format_string(name, peep->name_string_idx, &peep->id); + format_string(name, 128, peep->name_string_idx, &peep->id); console_printf("staff id %03d type: %02u energy %03u name %s", i, peep->staff_type, peep->energy, name); } } else if (strcmp(argv[0], "set") == 0) { @@ -1178,7 +1179,7 @@ void console_execute_silent(const utf8 *src) utf8 output[128]; utf8 *dst = output; dst = utf8_write_codepoint(dst, FORMAT_TOPAZ); - strcpy(dst, "Unknown command. Type help to list available commands."); + safe_strcpy(dst, "Unknown command. Type help to list available commands.", sizeof(output) - (dst - output)); console_writeline(output); } } diff --git a/src/interface/keyboard_shortcut.c b/src/interface/keyboard_shortcut.c index 28b992f9c6..c7a9e6353b 100644 --- a/src/interface/keyboard_shortcut.c +++ b/src/interface/keyboard_shortcut.c @@ -26,6 +26,7 @@ #include "../platform/platform.h" #include "../ride/track_paint.h" #include "../title.h" +#include "../util/util.h" #include "keyboard_shortcut.h" #include "viewport.h" #include "widget.h" @@ -92,33 +93,34 @@ void keyboard_shortcut_handle_command(int shortcutIndex) } } -void keyboard_shortcut_format_string(char *buffer, uint16 shortcutKey) +void keyboard_shortcut_format_string(char *buffer, size_t size, uint16 shortcutKey) { char formatBuffer[256]; + if (size == 0) return; *buffer = 0; if (shortcutKey == SHORTCUT_UNDEFINED) return; if (shortcutKey & 0x100) { - format_string(formatBuffer, STR_SHIFT_PLUS, NULL); - strcat(buffer, formatBuffer); + format_string(formatBuffer, 256, STR_SHIFT_PLUS, NULL); + safe_strcat(buffer, formatBuffer, size); } if (shortcutKey & 0x200) { - format_string(formatBuffer, STR_CTRL_PLUS, NULL); - strcat(buffer, formatBuffer); + format_string(formatBuffer, 256, STR_CTRL_PLUS, NULL); + safe_strcat(buffer, formatBuffer, size); } if (shortcutKey & 0x400) { #ifdef __MACOSX__ - format_string(formatBuffer, STR_OPTION_PLUS, NULL); + format_string(formatBuffer, 256, STR_OPTION_PLUS, NULL); #else - format_string(formatBuffer, STR_ALT_PLUS, NULL); + format_string(formatBuffer, 256, STR_ALT_PLUS, NULL); #endif - strcat(buffer, formatBuffer); + safe_strcat(buffer, formatBuffer, size); } if (shortcutKey & 0x800) { - format_string(formatBuffer, STR_CMD_PLUS, NULL); - strcat(buffer, formatBuffer); + format_string(formatBuffer, 256, STR_CMD_PLUS, NULL); + safe_strcat(buffer, formatBuffer, size); } - strcat(buffer, SDL_GetScancodeName(shortcutKey & 0xFF)); + safe_strcat(buffer, SDL_GetScancodeName(shortcutKey & 0xFF), size); } #pragma region Shortcut Commands diff --git a/src/interface/keyboard_shortcut.h b/src/interface/keyboard_shortcut.h index 67dbfefddf..a956c00da2 100644 --- a/src/interface/keyboard_shortcut.h +++ b/src/interface/keyboard_shortcut.h @@ -25,6 +25,6 @@ extern uint8 gKeyboardShortcutChangeId; void keyboard_shortcut_set(int key); void keyboard_shortcut_handle(int key); void keyboard_shortcut_handle_command(int shortcutIndex); -void keyboard_shortcut_format_string(char *buffer, uint16 shortcutKey); +void keyboard_shortcut_format_string(char *buffer, size_t size, uint16 shortcutKey); #endif diff --git a/src/interface/screenshot.c b/src/interface/screenshot.c index 55f2dd844e..7520da4404 100644 --- a/src/interface/screenshot.c +++ b/src/interface/screenshot.c @@ -67,18 +67,18 @@ static void screenshot_get_rendered_palette(rct_palette* palette) { } } -static int screenshot_get_next_path(char *path) +static int screenshot_get_next_path(char *path, size_t size) { char screenshotPath[MAX_PATH]; - platform_get_user_directory(screenshotPath, "screenshot"); + platform_get_user_directory(screenshotPath, "screenshot", sizeof(screenshotPath)); if (!platform_ensure_directory_exists(screenshotPath)) { log_error("Unable to save screenshots in OpenRCT2 screenshot directory.\n"); return -1; } - char park_name[128] = { 0 }; - format_string(park_name, gParkName, &gParkNameArgs); + char park_name[128]; + format_string(park_name, 128, gParkName, &gParkNameArgs); // retrieve current time rct2_date currentDate; @@ -87,7 +87,7 @@ static int screenshot_get_next_path(char *path) platform_get_time_local(¤tTime); // Glue together path and filename - sprintf(path, "%s%s %d-%02d-%02d %02d-%02d-%02d.png", screenshotPath, park_name, currentDate.year, currentDate.month, currentDate.day, currentTime.hour, currentTime.minute, currentTime.second); + snprintf(path, size, "%s%s %d-%02d-%02d %02d-%02d-%02d.png", screenshotPath, park_name, currentDate.year, currentDate.month, currentDate.day, currentTime.hour, currentTime.minute, currentTime.second); if (!platform_file_exists(path)) { return 0; // path ok @@ -102,7 +102,7 @@ static int screenshot_get_next_path(char *path) int i; for (i = 1; i < 1000; i++) { // Glue together path and filename - sprintf(path, "%s%s %d-%02d-%02d %02d-%02d-%02d (%d).png", screenshotPath, park_name, currentDate.year, currentDate.month, currentDate.day, currentTime.hour, currentTime.minute, currentTime.second, i); + snprintf(path, size, "%s%s %d-%02d-%02d %02d-%02d-%02d (%d).png", screenshotPath, park_name, currentDate.year, currentDate.month, currentDate.day, currentTime.hour, currentTime.minute, currentTime.second, i); if (!platform_file_exists(path)) { return i; @@ -118,7 +118,7 @@ int screenshot_dump_png(rct_drawpixelinfo *dpi) // Get a free screenshot path int index; char path[MAX_PATH] = ""; - if ((index = screenshot_get_next_path(path)) == -1) { + if ((index = screenshot_get_next_path(path, MAX_PATH)) == -1) { return -1; } @@ -137,7 +137,7 @@ int screenshot_dump_png_32bpp(sint32 width, sint32 height, const void *pixels) // Get a free screenshot path int index; char path[MAX_PATH] = ""; - if ((index = screenshot_get_next_path(path)) == -1) { + if ((index = screenshot_get_next_path(path, MAX_PATH)) == -1) { return -1; } @@ -222,7 +222,7 @@ void screenshot_giant() // Get a free screenshot path char path[MAX_PATH]; int index; - if ((index = screenshot_get_next_path(path)) == -1) { + if ((index = screenshot_get_next_path(path, MAX_PATH)) == -1) { log_error("Giant screenshot failed, unable to find a suitable destination path."); window_error_open(STR_SCREENSHOT_FAILED, STR_NONE); return; @@ -236,9 +236,8 @@ void screenshot_giant() free(dpi.bits); // Show user that screenshot saved successfully - rct_string_id stringId = STR_PLACEHOLDER; - strcpy((char*)language_get_string(stringId), path_get_filename(path)); - set_format_arg(0, rct_string_id, stringId); + set_format_arg(0, rct_string_id, STR_STRING); + set_format_arg(2, char *, path_get_filename(path)); window_error_open(STR_SCREENSHOT_SAVED_AS, STR_NONE); } diff --git a/src/interface/title_sequences.c b/src/interface/title_sequences.c index 970afe59ce..adf8e5cd12 100644 --- a/src/interface/title_sequences.c +++ b/src/interface/title_sequences.c @@ -42,10 +42,10 @@ bool title_sequence_name_exists(const char *name) bool title_sequence_save_exists(int preset, const char *name) { utf8 newName[MAX_PATH]; - char *extension = (char*)path_get_extension(name); + const char *extension = path_get_extension(name); safe_strcpy(newName, name, MAX_PATH); if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) - strcat(newName, ".sv6"); + path_append_extension(newName, ".sv6", MAX_PATH); for (int i = 0; i < gConfigTitleSequences.presets[preset].num_saves; i++) { if (_stricmp(gConfigTitleSequences.presets[preset].saves[i], newName) == 0) return true; @@ -102,8 +102,8 @@ void title_sequence_create_preset(const char *name) // Create the folder utf8 path[MAX_PATH]; - platform_get_user_directory(path, "title sequences"); - strcat(path, gConfigTitleSequences.presets[preset].name); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[preset].name, MAX_PATH); platform_file_delete(path); platform_ensure_directory_exists(path); @@ -141,28 +141,25 @@ void title_sequence_duplicate_preset(int duplicate, const char *name) // Create the folder utf8 path[MAX_PATH], srcPath[MAX_PATH]; - platform_get_user_directory(path, "title sequences"); - strcat(path, gConfigTitleSequences.presets[preset].name); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[preset].name, MAX_PATH); platform_file_delete(path); platform_ensure_directory_exists(path); // Copy the saves - char separator = platform_get_path_separator(); for (int i = 0; i < gConfigTitleSequences.presets[preset].num_saves; i++) { if (gConfigTitleSequences.presets[duplicate].path[0]) { safe_strcpy(srcPath, gConfigTitleSequences.presets[duplicate].path, MAX_PATH); - strcat(srcPath, gConfigTitleSequences.presets[duplicate].saves[i]); + safe_strcat_path(srcPath, gConfigTitleSequences.presets[duplicate].saves[i], MAX_PATH); } else { - platform_get_user_directory(srcPath, "title sequences"); - strcat(srcPath, gConfigTitleSequences.presets[duplicate].name); - strncat(srcPath, &separator, 1); - strcat(srcPath, gConfigTitleSequences.presets[duplicate].saves[i]); + platform_get_user_directory(srcPath, "title sequences", sizeof(srcPath)); + safe_strcat_path(srcPath, gConfigTitleSequences.presets[duplicate].name, MAX_PATH); + safe_strcat_path(srcPath, gConfigTitleSequences.presets[duplicate].saves[i], MAX_PATH); } - platform_get_user_directory(path, "title sequences"); - strcat(path, gConfigTitleSequences.presets[preset].name); - strncat(path, &separator, 1); - strcat(path, gConfigTitleSequences.presets[preset].saves[i]); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[preset].name, MAX_PATH); + safe_strcat_path(path, gConfigTitleSequences.presets[preset].saves[i], MAX_PATH); platform_file_copy(srcPath, path, false); } @@ -181,8 +178,8 @@ void title_sequence_delete_preset(int preset) if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets) { // Delete the folder utf8 path[MAX_PATH]; - platform_get_user_directory(path, "title sequences"); - strcat(path, gConfigTitleSequences.presets[preset].name); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[preset].name, MAX_PATH); if (!platform_directory_delete(path)) { log_error("Failed to delete directory: \"%s\"", path); } @@ -209,10 +206,10 @@ void title_sequence_rename_preset(int preset, const char *newName) if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && filename_valid_characters(newName) && !title_sequence_name_exists(newName)) { // Rename the folder utf8 src[MAX_PATH], dest[MAX_PATH]; - platform_get_user_directory(src, "title sequences"); - platform_get_user_directory(dest, "title sequences"); - strcat(src, gConfigTitleSequences.presets[preset].name); - strcat(dest, newName); + platform_get_user_directory(src, "title sequences", sizeof(src)); + platform_get_user_directory(dest, "title sequences", sizeof(dest)); + safe_strcat_path(src, gConfigTitleSequences.presets[preset].name, sizeof(src)); + safe_strcat_path(dest, newName, sizeof(dest)); platform_file_move(src, dest); safe_strcpy(gConfigTitleSequences.presets[preset].name, newName, TITLE_SEQUENCE_NAME_SIZE); @@ -228,20 +225,18 @@ void title_sequence_rename_preset(int preset, const char *newName) void title_sequence_add_save(int preset, const char *path, const char *newName) { utf8 newPath[MAX_PATH]; - char *extension = (char*)path_get_extension(newName); + const char *extension = path_get_extension(newName); safe_strcpy(newPath, newName, MAX_PATH); if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) - strcat(newPath, ".sv6"); + path_append_extension(newPath, ".sv6", MAX_PATH); if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && filename_valid_characters(newPath) && !title_sequence_save_exists(preset, newPath) && platform_file_exists(path)) { // Copy the save file - char separator = platform_get_path_separator(); - platform_get_user_directory(newPath, "title sequences"); - strcat(newPath, gConfigTitleSequences.presets[preset].name); - strncat(newPath, &separator, 1); - strcat(newPath, newName); + platform_get_user_directory(newPath, "title sequences", sizeof(newPath)); + safe_strcat_path(newPath, gConfigTitleSequences.presets[preset].name, sizeof(newPath)); + safe_strcat_path(newPath, newName, sizeof(newPath)); // Add the appropriate extension if needed if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) - strcat(newPath, ".sv6"); + path_append_extension(newPath, ".sv6", sizeof(newPath)); platform_file_copy(path, newPath, false); gConfigTitleSequences.presets[preset].num_saves++; @@ -250,7 +245,7 @@ void title_sequence_add_save(int preset, const char *path, const char *newName) safe_strcpy(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], newName, TITLE_SEQUENCE_MAX_SAVE_LENGTH); // Add the appropriate extension if needed if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) - strcat(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], ".sv6"); + path_append_extension(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], ".sv6", TITLE_SEQUENCE_MAX_SAVE_LENGTH); } } @@ -258,12 +253,10 @@ void title_sequence_remove_save(int preset, int index) { if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index < gConfigTitleSequences.presets[preset].num_saves) { // Delete the save file - char separator = platform_get_path_separator(); utf8 path[MAX_PATH]; - platform_get_user_directory(path, "title sequences"); - strcat(path, gConfigTitleSequences.presets[preset].name); - strncat(path, &separator, 1); - strcat(path, gConfigTitleSequences.presets[preset].saves[index]); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[preset].name, sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[preset].saves[index], sizeof(path)); platform_file_delete(path); // Remove all references to this save in the commands and decrement save indices @@ -291,26 +284,23 @@ void title_sequence_rename_save(int preset, int index, const char *newName) filename_valid_characters(newName) && !title_sequence_save_exists(preset, newName)) { // Rename the save file - char separator = platform_get_path_separator(); utf8 src[MAX_PATH], dest[MAX_PATH]; - platform_get_user_directory(src, "title sequences"); - platform_get_user_directory(dest, "title sequences"); - strcat(src, gConfigTitleSequences.presets[preset].name); - strcat(dest, gConfigTitleSequences.presets[preset].name); - strncat(src, &separator, 1); - strncat(dest, &separator, 1); - strcat(src, gConfigTitleSequences.presets[preset].saves[index]); - strcat(dest, newName); + platform_get_user_directory(src, "title sequences", sizeof(src)); + platform_get_user_directory(dest, "title sequences", sizeof(dest)); + safe_strcat_path(src, gConfigTitleSequences.presets[preset].name, sizeof(src)); + safe_strcat_path(dest, gConfigTitleSequences.presets[preset].name, sizeof(dest)); + safe_strcat_path(src, gConfigTitleSequences.presets[preset].saves[index], sizeof(src)); + safe_strcat_path(dest, newName, sizeof(dest)); // Add the appropriate extension if needed - char *extension = (char*)path_get_extension(newName); + const char *extension = path_get_extension(newName); if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) - strcat(dest, ".sv6"); + path_append_extension(dest, ".sv6", sizeof(dest)); platform_file_move(src, dest); safe_strcpy(gConfigTitleSequences.presets[preset].saves[index], newName, TITLE_SEQUENCE_MAX_SAVE_LENGTH); // Add the appropriate extension if needed if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) - strcat(gConfigTitleSequences.presets[preset].saves[index], ".sv6"); + path_append_extension(gConfigTitleSequences.presets[preset].saves[index], ".sv6", TITLE_SEQUENCE_MAX_SAVE_LENGTH); title_sequence_save_preset_script(preset); } } diff --git a/src/interface/window.c b/src/interface/window.c index 8edf75f0a7..7af172dfb3 100644 --- a/src/interface/window.c +++ b/src/interface/window.c @@ -2470,7 +2470,7 @@ void window_start_textbox(rct_window *call_w, int call_widget, rct_string_id exi // Enter in the the text input buffer any existing // text. if (existing_text != STR_NONE) - format_string(gTextBoxInput, existing_text, &existing_args); + format_string(gTextBoxInput, 512, existing_text, &existing_args); // In order to prevent strings that exceed the maxLength // from crashing the game. diff --git a/src/localisation/currency.c b/src/localisation/currency.c index 20476a35bc..aa570ebc23 100644 --- a/src/localisation/currency.c +++ b/src/localisation/currency.c @@ -15,6 +15,7 @@ #pragma endregion #include "../config.h" +#include "../util/util.h" #include "currency.h" #include "string_ids.h" @@ -42,5 +43,5 @@ void currency_load_custom_currency_config() { CurrencyDescriptors[CURRENCY_CUSTOM].rate = gConfigGeneral.custom_currency_rate; CurrencyDescriptors[CURRENCY_CUSTOM].affix_unicode = gConfigGeneral.custom_currency_affix; - strncpy(CurrencyDescriptors[CURRENCY_CUSTOM].symbol_unicode, gConfigGeneral.custom_currency_symbol, CURRENCY_SYMBOL_MAX_SIZE); + safe_strcpy(CurrencyDescriptors[CURRENCY_CUSTOM].symbol_unicode, gConfigGeneral.custom_currency_symbol, CURRENCY_SYMBOL_MAX_SIZE); } diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index 3cecccb3e3..44036a0f14 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -148,7 +148,6 @@ const char *language_get_string(rct_string_id id) bool language_open(int id) { - static const char *languagePath = "%s/language/%s.txt"; char filename[MAX_PATH]; char dataPath[MAX_PATH]; @@ -156,13 +155,19 @@ bool language_open(int id) if (id == LANGUAGE_UNDEFINED) return false; - platform_get_openrct_data_path(dataPath); + platform_get_openrct_data_path(dataPath, sizeof(dataPath)); if (id != LANGUAGE_ENGLISH_UK) { - sprintf(filename, languagePath, dataPath, LanguagesDescriptors[LANGUAGE_ENGLISH_UK].locale); + safe_strcpy(filename, dataPath, MAX_PATH); + safe_strcat_path(filename, "language", MAX_PATH); + safe_strcat_path(filename, LanguagesDescriptors[LANGUAGE_ENGLISH_UK].locale, MAX_PATH); + path_append_extension(filename, ".txt", MAX_PATH); _languageFallback = LanguagePackFactory::FromFile(LANGUAGE_ENGLISH_UK, filename); } - sprintf(filename, languagePath, dataPath, LanguagesDescriptors[id].locale); + safe_strcpy(filename, dataPath, MAX_PATH); + safe_strcat_path(filename, "language", MAX_PATH); + safe_strcat_path(filename, LanguagesDescriptors[id].locale, MAX_PATH); + path_append_extension(filename, ".txt", MAX_PATH); _languageCurrent = LanguagePackFactory::FromFile(id, filename); if (_languageCurrent != nullptr) { gCurrentLanguage = id; diff --git a/src/localisation/localisation.c b/src/localisation/localisation.c index 3a108db266..c89308c605 100644 --- a/src/localisation/localisation.c +++ b/src/localisation/localisation.c @@ -488,254 +488,391 @@ void utf8_remove_formatting(utf8* string, bool allowColours) { #pragma endregion -void format_string_part_from_raw(char **dest, const char *src, char **args); -void format_string_part(char **dest, rct_string_id format, char **args); +#define format_push_char_safe(C) { *(*dest)++ = (C); --(*size); } +#define format_handle_overflow(X) if ((*size) <= (X)) { *(*dest) = '\0'; (*size) = 0; return; } +#define format_push_char(C) { format_handle_overflow(1); format_push_char_safe(C); } -static void format_integer(char **dest, long long value) +#define format_push_wrap(C) { *ncur = (C); if (ncur == (*dest)) ncur = nbegin; } +#define reverse_string() while (nbegin < nend) { tmp = *nbegin; *nbegin++ = *nend; *nend-- = tmp; } + +static void format_string_part_from_raw(char **dest, size_t *size, const char *src, char **args); +static void format_string_part(char **dest, size_t *size, rct_string_id format, char **args); + +static void format_append_string(char **dest, size_t *size, const utf8 *string) { + if ((*size) == 0) return; + size_t length = strlen(string); + if (length < (*size)) { + memcpy((*dest), string, length); + (*dest) += length; + } else { + memcpy((*dest), string, (*size) - 1); + (*dest) += (*size) - 1; + *(*dest)++ = '\0'; + (*size) = 0; + } +} + +static void format_append_string_n(char **dest, size_t *size, const utf8 *string, size_t maxlen) { + if ((*size) == 0) return; + size_t length = min(maxlen, strlen(string)); + if (length < (*size)) { + memcpy((*dest), string, length); + (*dest) += length; + } else { + memcpy((*dest), string, (*size) - 1); + (*dest) += (*size) - 1; + *(*dest)++ = '\0'; + (*size) = 0; + } +} + +static void format_integer(char **dest, size_t *size, long long value) { int digit; - char *dst = *dest; - char *finish; + char *nbegin, *nend, *ncur; char tmp; - + + if ((*size) == 0) return; + // Negative sign if (value < 0) { - *dst++ = '-'; + format_push_char('-'); value = -value; } - - *dest = dst; - + if (value == 0) { - *dst++ = '0'; - } else { - // Right to left + format_push_char('0'); + return; + } + + nbegin = (*dest); + + // Right to left + while (value > 0 && (*size) > 1) { + digit = value % 10; + value /= 10; + + format_push_char_safe('0' + digit); + } + + if (value > 0) { + ncur = nbegin; + while (value > 0) { digit = value % 10; value /= 10; - - *dst++ = '0' + digit; + + format_push_wrap('0' + digit); } + + // Reverse first half of string + nend = ncur - 1; + reverse_string(); + + // Reverse second half of string + nbegin = ncur; + nend = (*dest) - 1; + reverse_string(); + + format_push_char_safe('\0'); // truncate overflowed string + } else { + // Reverse string + nend = (*dest) - 1; + reverse_string(); } - finish = dst; - - // Reverse string - dst--; - while (*dest < dst) { - tmp = **dest; - **dest = *dst; - *dst = tmp; - (*dest)++; - dst--; - } - *dest = finish; } -static void format_comma_separated_integer(char **dest, long long value) +static void format_comma_separated_integer(char **dest, size_t *size, long long value) { int digit, groupIndex; - char *dst = *dest; - char *finish; + char *nbegin, *nend, *ncur; char tmp; const char *commaMark = language_get_string(STR_LOCALE_THOUSANDS_SEPARATOR); - const char *ch; + const char *ch = NULL; + + if ((*size) == 0) return; // Negative sign if (value < 0) { - *dst++ = '-'; + format_push_char('-'); value = -value; } - - *dest = dst; - + if (value == 0) { - *dst++ = '0'; - } else { - // Groups of three digits, right to left - groupIndex = 0; + format_push_char('0'); + return; + } + + nbegin = *dest; + + // Groups of three digits, right to left + groupIndex = 0; + while (value > 0 && (*size) > 1) { + // Append group separator + if (groupIndex == 3) { + groupIndex = 0; + ch = commaMark; + } + + if (ch != NULL ) { + format_push_char_safe(*ch++); + if (*ch == '\0') ch = NULL; + } else { + digit = value % 10; + value /= 10; + + format_push_char_safe('0' + digit); + groupIndex++; + } + } + + if (value > 0) { + ncur = nbegin; + while (value > 0) { // Append group separator if (groupIndex == 3) { groupIndex = 0; - ch = commaMark; - while (*ch != 0) { - *dst++ = *ch++; - } } - - digit = value % 10; - value /= 10; - - *dst++ = '0' + digit; - groupIndex++; + + if (ch != NULL ) { + format_push_wrap(*ch++); + if (*ch == '\0') ch = NULL; + } else { + digit = value % 10; + value /= 10; + + format_push_wrap('0' + digit); + groupIndex++; + } } + + // Reverse first half of string + nend = ncur - 1; + reverse_string(); + + // Reverse second half of string + nbegin = ncur; + nend = (*dest) - 1; + reverse_string(); + + format_push_char_safe('\0'); // truncate overflowed string + } else { + // Reverse string + nend = *dest - 1; + reverse_string(); } - finish = dst; - - // Reverse string - dst--; - while (*dest < dst) { - tmp = **dest; - **dest = *dst; - *dst = tmp; - (*dest)++; - dst--; - } - *dest = finish; } -static void format_comma_separated_fixed_1dp(char **dest, long long value) +static void format_comma_separated_fixed_1dp(char **dest, size_t *size, long long value) { int digit, groupIndex; - char *dst = *dest; - char *finish; + char *nbegin, *nend, *ncur; char tmp; const char *commaMark = language_get_string(STR_LOCALE_THOUSANDS_SEPARATOR); const char *decimalMark = language_get_string(STR_LOCALE_DECIMAL_POINT); const char *ch; + int zeroNeeded = 1; + + if ((*size) == 0) return; // Negative sign if (value < 0) { - *dst++ = '-'; + format_push_char('-'); value = -value; } + + nbegin = (*dest); - *dest = dst; - - // One decimal place - digit = value % 10; - value /= 10; - *dst++ = '0' + digit; - - ch = decimalMark; - while (*ch != 0) { - *dst++ = *ch++; + // In the case of buffers this small, + // all of this would be truncated anyways. + format_handle_overflow(1); + if ((*size) > 2) { + // One decimal place + digit = value % 10; + format_push_char_safe('0' + digit); + + ch = decimalMark; } + value /= 10; - if (value == 0) { - *dst++ = '0'; - } else { - // Groups of three digits, right to left - groupIndex = 0; - while (value > 0) { - // Append group separator - if (groupIndex == 3) { - groupIndex = 0; - - ch = commaMark; - while (*ch != 0) { - *dst++ = *ch++; - } - } - + groupIndex = 0; + while ((zeroNeeded || value > 0) && (*size) > 1) { + // Append group separator + if (groupIndex == 3) { + groupIndex = 0; + ch = commaMark; + } + + if (ch != NULL ) { + format_push_char_safe(*ch++); + if (*ch == '\0') ch = NULL; + } else { + zeroNeeded = 0; digit = value % 10; value /= 10; - - *dst++ = '0' + digit; + + format_push_char_safe('0' + digit); groupIndex++; } } - finish = dst; - // Reverse string - dst--; - while (*dest < dst) { - tmp = **dest; - **dest = *dst; - *dst = tmp; - (*dest)++; - dst--; + if (zeroNeeded || value > 0) { + ncur = nbegin; + + while (zeroNeeded || value > 0) { + // Append group separator + if (groupIndex == 3) { + groupIndex = 0; + ch = commaMark; + } + + if (ch != NULL ) { + format_push_wrap(*ch++); + if (*ch == '\0') ch = NULL; + } else { + zeroNeeded = 0; + digit = value % 10; + value /= 10; + + format_push_wrap('0' + digit); + groupIndex++; + } + } + + // Reverse first half of string + nend = ncur - 1; + reverse_string(); + + // Reverse second half of string + nbegin = ncur; + nend = (*dest) - 1; + reverse_string(); + + format_push_char_safe('\0'); // truncate overflowed string + } else { + // Reverse string + nend = *dest - 1; + reverse_string(); } - *dest = finish; } -static void format_comma_separated_fixed_2dp(char **dest, long long value) +static void format_comma_separated_fixed_2dp(char **dest, size_t *size, long long value) { int digit, groupIndex; - char *dst = *dest; - char *finish; + char *nbegin, *nend, *ncur; char tmp; const char *commaMark = language_get_string(STR_LOCALE_THOUSANDS_SEPARATOR); const char *decimalMark = language_get_string(STR_LOCALE_DECIMAL_POINT); - const char *ch; + const char *ch = NULL; + int zeroNeeded = 1; + + if ((*size) == 0) return; // Negative sign if (value < 0) { - *dst++ = '-'; + format_push_char('-'); value = -value; } - *dest = dst; + nbegin = (*dest); - // Two decimal places - digit = value % 10; - value /= 10; - *dst++ = '0' + digit; - digit = value % 10; - value /= 10; - *dst++ = '0' + digit; - - ch = decimalMark; - while (*ch != 0) { - *dst++ = *ch++; + // In the case of buffers this small, + // all of this would be truncated anyways. + format_handle_overflow(1); + if ((*size) < 3) { + value /= 100; + } else { + // Two decimal places + digit = value % 10; + value /= 10; + format_push_char_safe('0' + digit); + + digit = value % 10; + value /= 10; + format_push_char_safe('0' + digit); + + ch = decimalMark; } - if (value == 0) { - *dst++ = '0'; - } else { - // Groups of three digits, right to left - groupIndex = 0; - while (value > 0) { - // Append group separator - if (groupIndex == 3) { - groupIndex = 0; - - ch = commaMark; - while (*ch != 0) { - *dst++ = *ch++; - } - } - + groupIndex = 0; + while ((zeroNeeded || value > 0) && (*size) > 1) { + // Append group separator + if (groupIndex == 3) { + groupIndex = 0; + ch = commaMark; + } + + if (ch != NULL ) { + format_push_char_safe(*ch++); + if (*ch == '\0') ch = NULL; + } else { + zeroNeeded = 0; digit = value % 10; value /= 10; - - *dst++ = '0' + digit; + + format_push_char_safe('0' + digit); groupIndex++; } } - finish = dst; - - // Reverse string - dst--; - while (*dest < dst) { - tmp = **dest; - **dest = *dst; - *dst = tmp; - (*dest)++; - dst--; + + if (zeroNeeded || value > 0) { + ncur = nbegin; + + while (zeroNeeded || value > 0) { + // Append group separator + if (groupIndex == 3) { + groupIndex = 0; + ch = commaMark; + } + + if (ch != NULL ) { + format_push_wrap(*ch++); + if (*ch == '\0') ch = NULL; + } else { + zeroNeeded = 0; + digit = value % 10; + value /= 10; + + format_push_wrap('0' + digit); + groupIndex++; + } + } + + // Reverse first half of string + nend = ncur - 1; + reverse_string(); + + // Reverse second half of string + nbegin = ncur; + nend = (*dest) - 1; + reverse_string(); + + format_push_char_safe('\0'); // truncate overflowed string + } else { + // Reverse string + nend = *dest - 1; + reverse_string(); } - *dest = finish; } -static void format_currency(char **dest, long long value) +static void format_currency(char **dest, size_t *size, long long value) { + if ((*size) == 0) return; + const currency_descriptor *currencyDesc = &CurrencyDescriptors[gConfigGeneral.currency_format]; - - int rate = currencyDesc->rate; - value *= rate; + + value *= currencyDesc->rate; // Negative sign if (value < 0) { - // Round the value away from zero - value = (value - 99) / 100; - *(*dest)++ = '-'; + format_push_char('-'); value = -value; } - else{ - //Round the value away from zero - value = (value + 99) / 100; - } + + //Round the value away from zero + value = (value + 99) / 100; // Currency symbol const utf8 *symbol = currencyDesc->symbol_unicode; @@ -746,22 +883,22 @@ static void format_currency(char **dest, long long value) } // Prefix - if (affix == CURRENCY_PREFIX) { - safe_strcpy(*dest, symbol, CURRENCY_SYMBOL_MAX_SIZE); - *dest += strlen(*dest); - } + if (affix == CURRENCY_PREFIX) + format_append_string(dest, size, symbol); + if ((*size) == 0) return; - format_comma_separated_integer(dest, value); + format_comma_separated_integer(dest, size, value); + if ((*size) == 0) return; // Currency symbol suffix - if (affix == CURRENCY_SUFFIX) { - safe_strcpy(*dest, symbol, CURRENCY_SYMBOL_MAX_SIZE); - *dest += strlen(*dest); - } + if (affix == CURRENCY_SUFFIX) + format_append_string(dest, size, symbol); } -static void format_currency_2dp(char **dest, long long value) +static void format_currency_2dp(char **dest, size_t *size, long long value) { + if ((*size) == 0) return; + const currency_descriptor *currencyDesc = &CurrencyDescriptors[gConfigGeneral.currency_format]; int rate = currencyDesc->rate; @@ -769,7 +906,7 @@ static void format_currency_2dp(char **dest, long long value) // Negative sign if (value < 0) { - *(*dest)++ = '-'; + format_push_char('-'); value = -value; } @@ -782,34 +919,31 @@ static void format_currency_2dp(char **dest, long long value) } // Prefix - if (affix == CURRENCY_PREFIX) { - safe_strcpy(*dest, symbol, CURRENCY_SYMBOL_MAX_SIZE); - *dest += strlen(*dest); - } + if (affix == CURRENCY_PREFIX) + format_append_string(dest, size, symbol); + if ((*size) == 0) return; // Drop the pennies for "large" currencies if (rate >= 100) { - format_comma_separated_integer(dest, value / 100); + format_comma_separated_integer(dest, size, value / 100); } else { - format_comma_separated_fixed_2dp(dest, value); + format_comma_separated_fixed_2dp(dest, size, value); } + if ((*size) == 0) return; // Currency symbol suffix - if (affix == CURRENCY_SUFFIX) { - safe_strcpy(*dest, symbol, CURRENCY_SYMBOL_MAX_SIZE); - *dest += strlen(*dest); - } + if (affix == CURRENCY_SUFFIX) + format_append_string(dest, size, symbol); } -static void format_date(char **dest, uint16 value) +static void format_date(char **dest, size_t *size, uint16 value) { uint16 args[] = { date_get_month(value), date_get_year(value) + 1 }; uint16 *argsRef = args; - format_string_part(dest, STR_DATE_FORMAT_MY, (char**)&argsRef); - (*dest)--; + format_string_part(dest, size, STR_DATE_FORMAT_MY, (char**)&argsRef); } -static void format_length(char **dest, sint16 value) +static void format_length(char **dest, size_t *size, sint16 value) { rct_string_id stringId = STR_UNIT_SUFFIX_METRES; @@ -819,11 +953,10 @@ static void format_length(char **dest, sint16 value) } sint16 *argRef = &value; - format_string_part(dest, stringId, (char**)&argRef); - (*dest)--; + format_string_part(dest, size, stringId, (char**)&argRef); } -static void format_velocity(char **dest, uint16 value) +static void format_velocity(char **dest, size_t *size, uint16 value) { rct_string_id stringId; @@ -842,8 +975,7 @@ static void format_velocity(char **dest, uint16 value) } uint16 *argRef = &value; - format_string_part(dest, stringId, (char**)&argRef); - (*dest)--; + format_string_part(dest, size, stringId, (char**)&argRef); } static const rct_string_id DurationFormats[][2] = { @@ -852,7 +984,7 @@ static const rct_string_id DurationFormats[][2] = { {STR_DURATION_MINS_SEC, STR_DURATION_MINS_SECS}, }; -static void format_duration(char **dest, uint16 value) +static void format_duration(char **dest, size_t *size, uint16 value) { uint16 minutes = value / 60; uint16 seconds = value % 60; @@ -876,8 +1008,7 @@ static void format_duration(char **dest, uint16 value) rct_string_id stringId = DurationFormats[minuteIndex][secondsIndex]; - format_string_part(dest, stringId, (char**)&argsRef); - (*dest)--; + format_string_part(dest, size, stringId, (char**)&argsRef); } static const rct_string_id RealtimeFormats[][2] = { @@ -886,7 +1017,7 @@ static const rct_string_id RealtimeFormats[][2] = { {STR_REALTIME_HOURS_MIN, STR_REALTIME_HOURS_MINS}, }; -static void format_realtime(char ** dest, uint16 value) +static void format_realtime(char **dest, size_t *size, uint16 value) { uint16 hours = value / 60; uint16 minutes = value % 60; @@ -910,13 +1041,14 @@ static void format_realtime(char ** dest, uint16 value) rct_string_id stringId = RealtimeFormats[hourIndex][minuteIndex]; - format_string_part(dest, stringId, (char**)&argsRef); - (*dest)--; + format_string_part(dest, size, stringId, (char**)&argsRef); } -static void format_string_code(unsigned int format_code, char **dest, char **args) +static void format_string_code(unsigned int format_code, char **dest, size_t *size, char **args) { intptr_t value; + + if ((*size) == 0) return; switch (format_code) { case FORMAT_COMMA32: @@ -924,56 +1056,56 @@ static void format_string_code(unsigned int format_code, char **dest, char **arg value = *((sint32*)*args); *args += 4; - format_comma_separated_integer(dest, value); + format_comma_separated_integer(dest, size, value); break; case FORMAT_INT32: // Pop argument value = *((sint32*)*args); *args += 4; - format_integer(dest, value); + format_integer(dest, size, value); break; case FORMAT_COMMA2DP32: // Pop argument value = *((sint32*)*args); *args += 4; - format_comma_separated_fixed_2dp(dest, value); + format_comma_separated_fixed_2dp(dest, size, value); break; - case FORMAT_COMMA1DP16: + case FORMAT_COMMA1DP16: // Pop argument value = *((sint16*)*args); *args += 2; - format_comma_separated_fixed_1dp(dest, value); + format_comma_separated_fixed_1dp(dest, size, value); break; case FORMAT_COMMA16: // Pop argument value = *((sint16*)*args); *args += 2; - format_comma_separated_integer(dest, value); + format_comma_separated_integer(dest, size, value); break; case FORMAT_UINT16: // Pop argument value = *((uint16*)*args); *args += 2; - format_integer(dest, value); + format_integer(dest, size, value); break; case FORMAT_CURRENCY2DP: // Pop argument value = *((sint32*)*args); *args += 4; - format_currency_2dp(dest, value); + format_currency_2dp(dest, size, value); break; case FORMAT_CURRENCY: // Pop argument value = *((sint32*)*args); *args += 4; - format_currency(dest, value); + format_currency(dest, size, value); break; case FORMAT_STRINGID: case FORMAT_STRINGID2: @@ -981,40 +1113,36 @@ static void format_string_code(unsigned int format_code, char **dest, char **arg value = *((uint16*)*args); *args += 2; - format_string_part(dest, (rct_string_id)value, args); - (*dest)--; + format_string_part(dest, size, (rct_string_id)value, args); break; case FORMAT_STRING: // Pop argument value = *((uintptr_t*)*args); *args += sizeof(uintptr_t); - if (value != 0) { - strcpy(*dest, (char*)value); - *dest += strlen(*dest); - } + if (value != 0) + format_append_string(dest, size, (char*)value); break; case FORMAT_MONTHYEAR: // Pop argument value = *((uint16*)*args); *args += 2; - format_date(dest, (uint16)value); + format_date(dest, size, (uint16)value); break; case FORMAT_MONTH: // Pop argument value = *((uint16*)*args); *args += 2; - strcpy(*dest, language_get_string(DateGameMonthNames[date_get_month((int)value)])); - *dest += strlen(*dest); + format_append_string(dest, size, language_get_string(DateGameMonthNames[date_get_month((int)value)])); break; case FORMAT_VELOCITY: // Pop argument value = *((sint16*)*args); *args += 2; - format_velocity(dest, (uint16)value); + format_velocity(dest, size, (uint16)value); break; case FORMAT_POP16: *args += 2; @@ -1027,76 +1155,84 @@ static void format_string_code(unsigned int format_code, char **dest, char **arg value = *((uint16*)*args); *args += 2; - format_duration(dest, (uint16)value); + format_duration(dest, size, (uint16)value); break; case FORMAT_REALTIME: // Pop argument value = *((uint16*)*args); *args += 2; - format_realtime(dest, (uint16)value); + format_realtime(dest, size, (uint16)value); break; case FORMAT_LENGTH: // Pop argument value = *((sint16*)*args); *args += 2; - format_length(dest, (sint16)value); + format_length(dest, size, (sint16)value); break; case FORMAT_SPRITE: // Pop argument value = *((uint32*)*args); *args += 4; - *(*dest)++ = 23; + format_handle_overflow(1 + sizeof(intptr_t)); + + format_push_char_safe('\x17'); *((intptr_t*)(*dest)) = value; - *dest += 4; + (*dest) += sizeof(intptr_t); + (*size) -= sizeof(intptr_t); break; } } -void format_string_part_from_raw(utf8 **dest, const utf8 *src, char **args) +static void format_string_part_from_raw(utf8 **dest, size_t *size, const utf8 *src, char **args) { unsigned int code; - while (1) { + while (*size > 1) { code = utf8_get_next(src, &src); if (code < ' ') { if (code == 0) { - *(*dest)++ = code; break; } else if (code <= 4) { - *(*dest)++ = code; - *(*dest)++ = *src++; + format_handle_overflow(2); + format_push_char_safe(code); + format_push_char_safe(*src++); } else if (code <= 16) { - *(*dest)++ = code; + format_handle_overflow(1); + format_push_char_safe(code); } else if (code <= 22) { - *(*dest)++ = code; - *(*dest)++ = *src++; - *(*dest)++ = *src++; + format_handle_overflow(3); + format_push_char_safe(code); + format_push_char_safe(*src++); + format_push_char_safe(*src++); } else { - *(*dest)++ = code; - *(*dest)++ = *src++; - *(*dest)++ = *src++; - *(*dest)++ = *src++; - *(*dest)++ = *src++; + format_handle_overflow(5); + format_push_char_safe(code); + format_push_char_safe(*src++); + format_push_char_safe(*src++); + format_push_char_safe(*src++); + format_push_char_safe(*src++); } } else if (code <= 'z') { - *(*dest)++ = code; + format_push_char(code); } else if (code < FORMAT_COLOUR_CODE_START || code == FORMAT_COMMA1DP16) { - format_string_code(code, dest, args); + format_string_code(code, dest, size, args); } else { + format_handle_overflow((size_t) utf8_get_codepoint_length(code)); *dest = utf8_write_codepoint(*dest, code); } } + *(*dest) = '\0'; } -void format_string_part(utf8 **dest, rct_string_id format, char **args) +static void format_string_part(utf8 **dest, size_t *size, rct_string_id format, char **args) { if (format == STR_NONE) { - **dest = 0; + *(*dest) = '\0'; } else if (format < 0x8000) { // Language string - format_string_part_from_raw(dest, language_get_string(format), args); + format_string_part_from_raw(dest, size, language_get_string(format), args); } else if (format < 0x9000) { // Custom string format -= 0x8000; @@ -1105,16 +1241,18 @@ void format_string_part(utf8 **dest, rct_string_id format, char **args) *args += (format & 0xC00) >> 9; format &= ~0xC00; - safe_strcpy(*dest, &gUserStrings[format * 32], 32); - *dest = strchr(*dest, 0) + 1; + format_append_string_n(dest, size, &gUserStrings[format * 32], 32); + if ((*size) > 0) *(*dest) = '\0'; } else if (format < 0xE000) { // Real name format -= -0xA000; - sprintf(*dest, "%s %c.", - real_names[format % countof(real_names)], - real_name_initials[(format >> 10) % countof(real_name_initials)] - ); - *dest = strchr(*dest, 0) + 1; + + format_append_string(dest, size, real_names[format % countof(real_names)]); + if ((*size) == 0) return; + format_push_char(' '); + format_push_char(real_name_initials[(format >> 10) % countof(real_name_initials)]); + format_push_char('.'); + *(*dest) = '\0'; *args += 4; } else { @@ -1131,14 +1269,22 @@ void format_string_part(utf8 **dest, rct_string_id format, char **args) * format (ax) * args (ecx) */ -void format_string(utf8 *dest, rct_string_id format, void *args) +void format_string(utf8 *dest, size_t size, rct_string_id format, void *args) { - format_string_part(&dest, format, (char**)&args); + utf8 *end = dest; + size_t left = size; + format_string_part(&end, &left, format, (char**)&args); + if (left == 0) + log_warning("Truncating formatted string \"%s\" to %d bytes.", dest, size); } -void format_string_raw(utf8 *dest, utf8 *src, void *args) +void format_string_raw(utf8 *dest, size_t size, utf8 *src, void *args) { - format_string_part_from_raw(&dest, src, (char**)&args); + utf8 *end = dest; + size_t left = size; + format_string_part_from_raw(&end, &left, src, (char**)&args); + if (left == 0) + log_warning("Truncating formatted string \"%s\" to %d bytes.", dest, size); } /** @@ -1148,12 +1294,16 @@ void format_string_raw(utf8 *dest, utf8 *src, void *args) * format (ax) * args (ecx) */ -void format_string_to_upper(utf8 *dest, rct_string_id format, void *args) +void format_string_to_upper(utf8 *dest, size_t size, rct_string_id format, void *args) { - format_string(dest, format, args); + utf8 *end; + size_t left; + format_string_part(&end, &left, format, args); + if (left == 0) + log_warning("Truncating formatted string \"%s\" to %d bytes.", dest, size); char *ch = dest; - while (*ch != 0) { + while (ch < end) { *ch = toupper(*ch); ch++; } diff --git a/src/localisation/localisation.h b/src/localisation/localisation.h index cf4ac6ad06..b701026923 100644 --- a/src/localisation/localisation.h +++ b/src/localisation/localisation.h @@ -31,9 +31,9 @@ int font_sprite_get_codepoint_offset(int codepoint); int utf8_get_format_code_arg_length(int codepoint); void utf8_remove_formatting(utf8* string, bool allowColours); -void format_string(char *dest, rct_string_id format, void *args); -void format_string_raw(char *dest, char *src, void *args); -void format_string_to_upper(char *dest, rct_string_id format, void *args); +void format_string(char *dest, size_t size, rct_string_id format, void *args); +void format_string_raw(char *dest, size_t size, char *src, void *args); +void format_string_to_upper(char *dest, size_t size, rct_string_id format, void *args); void generate_string_file(); utf8 *get_string_end(const utf8 *text); size_t get_string_size(const utf8 *text); diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index 00fde651fa..b264647400 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -2563,7 +2563,7 @@ enum { STR_ERR_REASON_NOT_ENOUGH_MEMORY = 3162, // STR_3163 :Installing new data: STR_OBJECT_SELECTION_SELECTION_SIZE = 3164, - STR_PLACEHOLDER = 3165, +// STR_PLACEHOLDER = 3165, // STR_3166 :{BLACK}(ID: // STR_3167 :{WINDOW_COLOUR_2}Includes: {BLACK}{COMMA16} objects STR_OBJECT_SELECTION_DESCRIPTION_SCENARIO_TEXT = 3168, diff --git a/src/management/finance.c b/src/management/finance.c index 78fcf3675c..6e7bcde7cd 100644 --- a/src/management/finance.c +++ b/src/management/finance.c @@ -20,6 +20,7 @@ #include "../localisation/localisation.h" #include "../peep/peep.h" #include "../ride/ride.h" +#include "../util/util.h" #include "../world/park.h" #include "../world/sprite.h" #include "finance.h" @@ -202,7 +203,7 @@ void finance_init() { gScenarioCompletedCompanyValue = MONEY32_UNDEFINED; gTotalAdmissions = 0; gTotalIncomeFromAdmissions = 0; - strcpy(gScenarioCompletedBy, "?"); + safe_strcpy(gScenarioCompletedBy, "?", sizeof(gScenarioCompletedBy)); } /** diff --git a/src/management/news_item.c b/src/management/news_item.c index 91b3fcbf9d..de55f9a4e4 100644 --- a/src/management/news_item.c +++ b/src/management/news_item.c @@ -282,7 +282,7 @@ void news_item_add_to_queue(uint8 type, rct_string_id string_id, uint32 assoc) utf8 buffer[256]; void *args = gCommonFormatArgs; - format_string(buffer, string_id, args); // overflows possible? + format_string(buffer, 256, string_id, args); // overflows possible? news_item_add_to_queue_raw(type, buffer, assoc); } diff --git a/src/network/NetworkConnection.cpp b/src/network/NetworkConnection.cpp index 4263361ce1..9ff767b3be 100644 --- a/src/network/NetworkConnection.cpp +++ b/src/network/NetworkConnection.cpp @@ -191,7 +191,7 @@ void NetworkConnection::SetLastDisconnectReason(const utf8 * src) void NetworkConnection::SetLastDisconnectReason(const rct_string_id string_id, void *args) { char buffer[NETWORK_DISCONNECT_REASON_BUFFER_SIZE]; - format_string(buffer, string_id, args); + format_string(buffer, NETWORK_DISCONNECT_REASON_BUFFER_SIZE, string_id, args); SetLastDisconnectReason(buffer); } diff --git a/src/network/NetworkKey.cpp b/src/network/NetworkKey.cpp index 189bcd7563..1c730b3f4a 100644 --- a/src/network/NetworkKey.cpp +++ b/src/network/NetworkKey.cpp @@ -337,7 +337,7 @@ std::string NetworkKey::PublicKeyHash() for (unsigned int i = 0; i < digest_size; i++) { char buf[3]; - sprintf(buf, "%02x", digest[i]); + snprintf(buf, 3, "%02x", digest[i]); digest_out.append(buf); } return digest_out; diff --git a/src/network/NetworkUser.cpp b/src/network/NetworkUser.cpp index 7f07eea019..71107fbc26 100644 --- a/src/network/NetworkUser.cpp +++ b/src/network/NetworkUser.cpp @@ -248,7 +248,7 @@ NetworkUser * NetworkUserManager::GetOrAddUser(const std::string &hash) void NetworkUserManager::GetStorePath(utf8 * buffer, size_t bufferSize) { - platform_get_user_directory(buffer, nullptr); + platform_get_user_directory(buffer, nullptr, bufferSize); Path::Append(buffer, bufferSize, USER_STORE_FILENAME); } diff --git a/src/network/http.cpp b/src/network/http.cpp index b54ab01f5f..dbb589a6af 100644 --- a/src/network/http.cpp +++ b/src/network/http.cpp @@ -62,7 +62,7 @@ void http_init() #ifdef __WINDOWS__ // Find SSL certificate bundle - platform_get_exe_path(_caBundlePath); + platform_get_exe_path(_caBundlePath, sizeof(_caBundlePath)); Path::Append(_caBundlePath, sizeof(_caBundlePath), DEFAULT_CA_BUNDLE_PATH); if (!platform_file_exists(_caBundlePath)) { String::Set(_caBundlePath, sizeof(_caBundlePath), DEFAULT_CA_BUNDLE_PATH); diff --git a/src/network/network.cpp b/src/network/network.cpp index 819563441d..26a80e51a1 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -405,7 +405,7 @@ void Network::UpdateClient() { _lastConnectStatus = SOCKET_STATUS_RESOLVING; char str_resolving[256]; - format_string(str_resolving, STR_MULTIPLAYER_RESOLVING, NULL); + format_string(str_resolving, 256, STR_MULTIPLAYER_RESOLVING, NULL); window_network_status_open(str_resolving, []() -> void { gNetwork.Close(); }); @@ -418,7 +418,7 @@ void Network::UpdateClient() { _lastConnectStatus = SOCKET_STATUS_CONNECTING; char str_connecting[256]; - format_string(str_connecting, STR_MULTIPLAYER_CONNECTING, NULL); + format_string(str_connecting, 256, STR_MULTIPLAYER_CONNECTING, NULL); window_network_status_open(str_connecting, []() -> void { gNetwork.Close(); }); @@ -432,7 +432,7 @@ void Network::UpdateClient() server_connection.ResetLastPacketTime(); Client_Send_TOKEN(); char str_authenticating[256]; - format_string(str_authenticating, STR_MULTIPLAYER_AUTHENTICATING, NULL); + format_string(str_authenticating, 256, STR_MULTIPLAYER_AUTHENTICATING, NULL); window_network_status_open(str_authenticating, []() -> void { gNetwork.Close(); }); @@ -464,9 +464,9 @@ void Network::UpdateClient() if (server_connection.GetLastDisconnectReason()) { const char * disconnect_reason = server_connection.GetLastDisconnectReason(); - format_string(str_disconnected, STR_MULTIPLAYER_DISCONNECTED_WITH_REASON, &disconnect_reason); + format_string(str_disconnected, 256, STR_MULTIPLAYER_DISCONNECTED_WITH_REASON, &disconnect_reason); } else { - format_string(str_disconnected, STR_MULTIPLAYER_DISCONNECTED_NO_REASON, NULL); + format_string(str_disconnected, 256, STR_MULTIPLAYER_DISCONNECTED_NO_REASON, NULL); } window_network_status_open(str_disconnected, NULL); @@ -479,7 +479,7 @@ void Network::UpdateClient() if (!_desynchronised && !CheckSRAND(gCurrentTicks, gScenarioSrand0)) { _desynchronised = true; char str_desync[256]; - format_string(str_desync, STR_MULTIPLAYER_DESYNC, NULL); + format_string(str_desync, 256, STR_MULTIPLAYER_DESYNC, NULL); window_network_status_open(str_desync, NULL); if (!gConfigNetwork.stay_connected) { Close(); @@ -534,8 +534,8 @@ const char* Network::FormatChat(NetworkPlayer* fromplayer, const char* text) if (fromplayer) { lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE); lineCh = utf8_write_codepoint(lineCh, FORMAT_BABYBLUE); - safe_strcpy(lineCh, (const char*)fromplayer->name.c_str(), fromplayer->name.size() + 1); - strcat(lineCh, ": "); + safe_strcpy(lineCh, (const char *) fromplayer->name.c_str(), sizeof(formatted) - (lineCh - formatted)); + safe_strcat(lineCh, ": ", sizeof(formatted) - (lineCh - formatted)); lineCh = strchr(lineCh, '\0'); } lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE); @@ -582,7 +582,7 @@ void Network::KickPlayer(int playerId) // Disconnect the client gracefully (*it)->SetLastDisconnectReason(STR_MULTIPLAYER_KICKED); char str_disconnect_msg[256]; - format_string(str_disconnect_msg, STR_MULTIPLAYER_KICKED_REASON, NULL); + format_string(str_disconnect_msg, 256, STR_MULTIPLAYER_KICKED_REASON, NULL); Server_Send_SETDISCONNECTMSG(*(*it), str_disconnect_msg); (*it)->Socket->Disconnect(); break; @@ -695,8 +695,8 @@ void Network::SaveGroups() if (GetMode() == NETWORK_MODE_SERVER) { utf8 path[MAX_PATH]; - platform_get_user_directory(path, NULL); - strcat(path, "groups.json"); + platform_get_user_directory(path, NULL, sizeof(path)); + safe_strcat_path(path, "groups.json", sizeof(path)); json_t * jsonGroupsCfg = json_object(); json_t * jsonGroups = json_array(); @@ -748,8 +748,8 @@ void Network::LoadGroups() utf8 path[MAX_PATH]; - platform_get_user_directory(path, NULL); - strcat(path, "groups.json"); + platform_get_user_directory(path, NULL, sizeof(path)); + safe_strcat_path(path, "groups.json", sizeof(path)); json_t * json = nullptr; if (platform_file_exists(path)) { @@ -790,7 +790,7 @@ void Network::BeginChatLog() strftime(filename, sizeof(filename), "%Y%m%d-%H%M%S.txt", tmInfo); utf8 path[MAX_PATH]; - platform_get_user_directory(path, "chatlogs"); + platform_get_user_directory(path, "chatlogs", sizeof(path)); Path::Append(path, sizeof(path), filename); _chatLogPath = std::string(path); @@ -819,7 +819,7 @@ void Network::AppendChatLog(const utf8 *text) String::Append(buffer, sizeof(buffer), text); utf8_remove_formatting(buffer, false); - String::Append(buffer, sizeof(buffer), platform_get_new_line()); + String::Append(buffer, sizeof(buffer), PLATFORM_NEWLINE); SDL_RWwrite(_chatLogStream, buffer, strlen(buffer), 1); SDL_RWclose(_chatLogStream); @@ -1216,9 +1216,9 @@ void Network::RemoveClient(std::unique_ptr& connection) connection->GetLastDisconnectReason() }; if (has_disconnected_args[1]) { - format_string(text, STR_MULTIPLAYER_PLAYER_HAS_DISCONNECTED_WITH_REASON, has_disconnected_args); + format_string(text, 256, STR_MULTIPLAYER_PLAYER_HAS_DISCONNECTED_WITH_REASON, has_disconnected_args); } else { - format_string(text, STR_MULTIPLAYER_PLAYER_HAS_DISCONNECTED_NO_REASON, &(has_disconnected_args[0])); + format_string(text, 256, STR_MULTIPLAYER_PLAYER_HAS_DISCONNECTED_NO_REASON, &(has_disconnected_args[0])); } chat_history_add(text); @@ -1408,7 +1408,7 @@ void Network::Server_Client_Joined(const char* name, const std::string &keyhash, if (player) { char text[256]; const char * player_name = (const char *) player->name.c_str(); - format_string(text, STR_MULTIPLAYER_PLAYER_HAS_JOINED_THE_GAME, &player_name); + format_string(text, 256, STR_MULTIPLAYER_PLAYER_HAS_JOINED_THE_GAME, &player_name); chat_history_add(text); Server_Send_MAP(&connection); gNetwork.Server_Send_EVENT_PLAYER_JOINED(player_name); @@ -1511,7 +1511,7 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa } char str_downloading_map[256]; unsigned int downloading_map_args[2] = {(offset + chunksize) / 1024, size / 1024}; - format_string(str_downloading_map, STR_MULTIPLAYER_DOWNLOADING_MAP, downloading_map_args); + format_string(str_downloading_map, 256, STR_MULTIPLAYER_DOWNLOADING_MAP, downloading_map_args); window_network_status_open(str_downloading_map, []() -> void { gNetwork.Close(); }); @@ -1779,27 +1779,26 @@ void Network::Client_Handle_GROUPLIST(NetworkConnection& connection, NetworkPack void Network::Client_Handle_EVENT(NetworkConnection& connection, NetworkPacket& packet) { + char text[256]; uint16 eventType; packet >> eventType; switch (eventType) { case SERVER_EVENT_PLAYER_JOINED: { - char text[256]; const char *playerName = packet.ReadString(); - format_string(text, STR_MULTIPLAYER_PLAYER_HAS_JOINED_THE_GAME, &playerName); + format_string(text, 256, STR_MULTIPLAYER_PLAYER_HAS_JOINED_THE_GAME, &playerName); chat_history_add(text); break; } case SERVER_EVENT_PLAYER_DISCONNECTED: { - char text[256]; const char *playerName = packet.ReadString(); const char *reason = packet.ReadString(); const char *args[] = { playerName, reason }; if (str_is_null_or_empty(reason)) { - format_string(text, STR_MULTIPLAYER_PLAYER_HAS_DISCONNECTED_NO_REASON, args); + format_string(text, 256, STR_MULTIPLAYER_PLAYER_HAS_DISCONNECTED_NO_REASON, args); } else { - format_string(text, STR_MULTIPLAYER_PLAYER_HAS_DISCONNECTED_WITH_REASON, args); + format_string(text, 256, STR_MULTIPLAYER_PLAYER_HAS_DISCONNECTED_WITH_REASON, args); } chat_history_add(text); break; @@ -2022,13 +2021,13 @@ const char* network_get_group_name(unsigned int index) void network_chat_show_connected_message() { - // TODO: How does this work? 2525 is '???' - char *templateString = (char*)language_get_string(STR_SHORTCUT_KEY_UNKNOWN); - keyboard_shortcut_format_string(templateString, gShortcutKeys[SHORTCUT_OPEN_CHAT_WINDOW]); + char templateBuffer[128]; + char *templateString = templateBuffer; + keyboard_shortcut_format_string(templateBuffer, 128, gShortcutKeys[SHORTCUT_OPEN_CHAT_WINDOW]); utf8 buffer[256]; NetworkPlayer server; server.name = "Server"; - format_string(buffer, STR_MULTIPLAYER_CONNECTED_CHAT_HINT, &templateString); + format_string(buffer, 256, STR_MULTIPLAYER_CONNECTED_CHAT_HINT, &templateString); const char *formatted = Network::FormatChat(&server, buffer); chat_history_add(formatted); } @@ -2349,7 +2348,7 @@ void network_append_chat_log(const utf8 *text) static void network_get_keys_directory(utf8 *buffer, size_t bufferSize) { - platform_get_user_directory(buffer, "keys"); + platform_get_user_directory(buffer, "keys", bufferSize); } static void network_get_private_key_path(utf8 *buffer, size_t bufferSize, const utf8 * playerName) @@ -2370,7 +2369,7 @@ static void network_get_public_key_path(utf8 *buffer, size_t bufferSize, const u static void network_get_keymap_path(utf8 *buffer, size_t bufferSize) { - platform_get_user_directory(buffer, NULL); + platform_get_user_directory(buffer, NULL, bufferSize); Path::Append(buffer, bufferSize, "keymappings.json"); } diff --git a/src/network/twitch.cpp b/src/network/twitch.cpp index 6de95de67f..e4d487ec6f 100644 --- a/src/network/twitch.cpp +++ b/src/network/twitch.cpp @@ -415,7 +415,7 @@ namespace Twitch if (is_user_string_id(peep->name_string_idx)) { utf8 buffer[256]; - format_string(buffer, peep->name_string_idx, NULL); + format_string(buffer, 256, peep->name_string_idx, NULL); AudienceMember * member = nullptr; for (AudienceMember &m : members) @@ -505,27 +505,6 @@ namespace Twitch } } - /** - * Like strchr but allows searching for one of many characters. - */ - static char * strchrm(const char * str, const char * find) - { - do - { - const char * fch = find; - while (*fch != '\0') - { - if (*str == *fch) - { - return (char *)str; - } - fch++; - } - } - while (*str++ != '\0'); - return nullptr; - } - static char * strskipwhitespace(const char * str) { while (*str == ' ' || *str == '\t') @@ -546,17 +525,16 @@ namespace Twitch // Skip '!' message++; - // Set buffer to the next word / token and skip - char buffer[32]; - const char * ch = strchrm(message, " \t"); - safe_strcpy(buffer, message, Math::Min(sizeof(buffer), (size_t)(ch - message + 1))); - ch = strskipwhitespace(ch); - - // Check what the word / token is - if (String::Equals(buffer, "news", true)) - { - DoChatMessageNews(ch); + // Check that command is "news" + const char *ch, *cmd; + for (ch = message, cmd = "news"; *cmd != '\0'; ++ch, ++cmd) { + if (*ch != *cmd) return; } + + if (!isspace(*ch)) return; + + ch = strskipwhitespace(ch); + DoChatMessageNews(ch); } static void DoChatMessageNews(const char * message) diff --git a/src/object.h b/src/object.h index f00ec217c5..28a886162a 100644 --- a/src/object.h +++ b/src/object.h @@ -116,7 +116,7 @@ bool object_entry_is_empty(const rct_object_entry *entry); bool object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); int object_calculate_checksum(const rct_object_entry * entry, const void * data, size_t dataLength); int find_object_in_entry_group(const rct_object_entry* entry, uint8* entry_type, uint8* entry_index); -void object_create_identifier_name(char* string_buffer, const rct_object_entry* object); +void object_create_identifier_name(char* string_buffer, size_t size, const rct_object_entry* object); rct_object_entry *object_list_find_by_name(const char *name); rct_object_entry *object_list_find(rct_object_entry *entry); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 3450f891a0..63b7055f46 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -46,6 +46,7 @@ extern "C" #include "../platform/platform.h" #include "../scenario.h" #include "../util/sawyercoding.h" + #include "../util/util.h" } constexpr uint16 OBJECT_REPOSITORY_VERSION = 10; @@ -634,8 +635,8 @@ private: static void GetRepositoryPath(utf8 * buffer, size_t bufferSize) { - platform_get_user_directory(buffer, nullptr); - strcat(buffer, "objects.idx"); + platform_get_user_directory(buffer, nullptr, bufferSize); + safe_strcat_path(buffer, "objects.idx", bufferSize); } static void GetRCT2ObjectPath(utf8 * buffer, size_t bufferSize) @@ -645,7 +646,7 @@ private: static void GetUserObjectPath(utf8 * buffer, size_t bufferSize) { - platform_get_user_directory(buffer, "object"); + platform_get_user_directory(buffer, "object", bufferSize); } static uint32 GetPathChecksum(const utf8 * path) diff --git a/src/object_list.c b/src/object_list.c index e6478da587..b465464cd3 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -122,9 +122,9 @@ bool object_entry_is_empty(const rct_object_entry *entry) * * rct2: 0x006AB344 */ -void object_create_identifier_name(char* string_buffer, const rct_object_entry* object) +void object_create_identifier_name(char* string_buffer, size_t size, const rct_object_entry* object) { - sprintf(string_buffer, "%.8s/%4X%4X", object->name, object->flags, object->checksum); + snprintf(string_buffer, size, "%.8s/%4X%4X", object->name, object->flags, object->checksum); } /** diff --git a/src/openrct2.c b/src/openrct2.c index 7bc058ee36..d3871b59d9 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -90,23 +90,25 @@ void openrct2_write_full_version_info(utf8 *buffer, size_t bufferSize) utf8 *ch = buffer; // Name and version - strcpy(ch, OPENRCT2_NAME); - strcat(buffer, ", v"); - strcat(buffer, OPENRCT2_VERSION); + safe_strcpy(ch, OPENRCT2_NAME ", v" OPENRCT2_VERSION, bufferSize - (ch - buffer)); + ch = strchr(ch, '\0'); // Build information if (!str_is_null_or_empty(gGitBranch)) { - sprintf(strchr(buffer, 0), "-%s", gGitBranch); + snprintf(ch, bufferSize - (ch - buffer), "-%s", gGitBranch); + ch = strchr(ch, '\0'); } if (!str_is_null_or_empty(gCommitSha1Short)) { - sprintf(strchr(buffer, 0), " build %s", gCommitSha1Short); + snprintf(ch, bufferSize - (ch - buffer), " build %s", gCommitSha1Short); + ch = strchr(ch, '\0'); } if (!str_is_null_or_empty(gBuildServer)) { - sprintf(strchr(buffer, 0), " provided by %s", gBuildServer); + snprintf(ch, bufferSize - (ch - buffer), " provided by %s", gBuildServer); + ch = strchr(ch, '\0'); } #if DEBUG - sprintf(strchr(buffer, 0), " (DEBUG)"); + snprintf(ch, bufferSize - (ch - buffer), " (DEBUG)"); #endif } @@ -122,23 +124,23 @@ static void openrct2_copy_files_over(const utf8 *originalDirectory, const utf8 * } // Create filter path - safe_strcpy(filter, originalDirectory, MAX_PATH); + safe_strcpy(filter, originalDirectory, sizeof(filter)); ch = strchr(filter, '*'); if (ch != NULL) *ch = 0; - strcat(filter, "*"); - strcat(filter, extension); + safe_strcat_path(filter, "*", sizeof(filter)); + path_append_extension(filter, extension, sizeof(filter)); fileEnumHandle = platform_enumerate_files_begin(filter); while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { - safe_strcpy(newPath, newDirectory, MAX_PATH); - strcat(newPath, fileInfo.path); + safe_strcpy(newPath, newDirectory, sizeof(newPath)); + safe_strcat_path(newPath, fileInfo.path, sizeof(newPath)); - safe_strcpy(oldPath, originalDirectory, MAX_PATH); + safe_strcpy(oldPath, originalDirectory, sizeof(oldPath)); ch = strchr(oldPath, '*'); if (ch != NULL) *ch = 0; - strcat(oldPath, fileInfo.path); + safe_strcat_path(oldPath, fileInfo.path, sizeof(oldPath)); if (!platform_file_exists(newPath)) platform_file_copy(oldPath, newPath, false); @@ -147,14 +149,14 @@ static void openrct2_copy_files_over(const utf8 *originalDirectory, const utf8 * fileEnumHandle = platform_enumerate_directories_begin(originalDirectory); while (platform_enumerate_directories_next(fileEnumHandle, filter)) { - safe_strcpy(newPath, newDirectory, MAX_PATH); - strcat(newPath, filter); + safe_strcpy(newPath, newDirectory, sizeof(newPath)); + safe_strcat_path(newPath, filter, sizeof(newPath)); safe_strcpy(oldPath, originalDirectory, MAX_PATH); ch = strchr(oldPath, '*'); if (ch != NULL) *ch = 0; - strcat(oldPath, filter); + safe_strcat_path(oldPath, filter, sizeof(oldPath)); if (!platform_ensure_directory_exists(newPath)) { log_error("Could not create directory %s.", newPath); @@ -167,7 +169,7 @@ static void openrct2_copy_files_over(const utf8 *originalDirectory, const utf8 * static void openrct2_set_exe_path() { - platform_get_exe_path(gExePath); + platform_get_exe_path(gExePath, sizeof(gExePath)); log_verbose("Setting exe path to %s", gExePath); } @@ -178,10 +180,10 @@ static void openrct2_copy_original_user_files_over() { utf8 path[MAX_PATH]; - platform_get_user_directory(path, "save"); + platform_get_user_directory(path, "save", sizeof(path)); openrct2_copy_files_over((utf8*)gRCT2AddressSavedGamesPath, path, ".sv6"); - platform_get_user_directory(path, "landscape"); + platform_get_user_directory(path, "landscape", sizeof(path)); openrct2_copy_files_over((utf8*)gRCT2AddressLandscapesPath, path, ".sc6"); } @@ -196,7 +198,7 @@ bool openrct2_initialise() platform_resolve_openrct_data_path(); platform_resolve_user_data_path(); - platform_get_user_directory(userPath, NULL); + platform_get_user_directory(userPath, NULL, sizeof(userPath)); if (!platform_ensure_directory_exists(userPath)) { log_fatal("Could not create user directory (do you have write access to your documents folder?)"); return false; @@ -217,7 +219,7 @@ bool openrct2_initialise() gConfigGeneral.last_run_version = strndup(OPENRCT2_VERSION, strlen(OPENRCT2_VERSION)); config_save_default(); utf8 path[MAX_PATH]; - config_get_default_path(path); + config_get_default_path(path, sizeof(path)); log_fatal("An RCT2 install directory must be specified! Please edit \"game_path\" in %s.", path); return false; } @@ -493,7 +495,7 @@ void openrct2_reset_object_tween_locations() static void openrct2_get_segment_data_path(char * buffer, size_t bufferSize) { - platform_get_exe_path(buffer); + platform_get_exe_path(buffer, bufferSize); safe_strcat_path(buffer, "openrct2_data", bufferSize); } diff --git a/src/paint/map_element/banner.c b/src/paint/map_element/banner.c index 81c7df4744..a721f1d131 100644 --- a/src/paint/map_element/banner.c +++ b/src/paint/map_element/banner.c @@ -99,9 +99,9 @@ void banner_paint(uint8 direction, int height, rct_map_element* map_element) string_id = STR_BANNER_TEXT_FORMAT; } if (gConfigGeneral.upper_case_banners) { - format_string_to_upper(gCommonStringFormatBuffer, string_id, gCommonFormatArgs); + format_string_to_upper(gCommonStringFormatBuffer, 256, string_id, gCommonFormatArgs); } else { - format_string(gCommonStringFormatBuffer, string_id, gCommonFormatArgs); + format_string(gCommonStringFormatBuffer, 256, string_id, gCommonFormatArgs); } gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY; diff --git a/src/paint/map_element/entrance.c b/src/paint/map_element/entrance.c index eda3d7144f..1c4da0d91c 100644 --- a/src/paint/map_element/entrance.c +++ b/src/paint/map_element/entrance.c @@ -131,9 +131,9 @@ static void ride_entrance_exit_paint(uint8 direction, int height, rct_map_elemen utf8 entrance_string[MAX_PATH]; if (gConfigGeneral.upper_case_banners) { - format_string_to_upper(entrance_string, string_id, gCommonFormatArgs); + format_string_to_upper(entrance_string, MAX_PATH, string_id, gCommonFormatArgs); } else { - format_string(entrance_string, string_id, gCommonFormatArgs); + format_string(entrance_string, MAX_PATH, string_id, gCommonFormatArgs); } gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY; @@ -208,9 +208,9 @@ static void park_entrance_paint(uint8 direction, int height, rct_map_element* ma utf8 park_name[MAX_PATH]; if (gConfigGeneral.upper_case_banners) { - format_string_to_upper(park_name, park_text_id, gCommonFormatArgs); + format_string_to_upper(park_name, MAX_PATH, park_text_id, gCommonFormatArgs); } else { - format_string(park_name, park_text_id, gCommonFormatArgs); + format_string(park_name, MAX_PATH, park_text_id, gCommonFormatArgs); } gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY; diff --git a/src/paint/map_element/fence.c b/src/paint/map_element/fence.c index 3adc1c36dd..6304b24686 100644 --- a/src/paint/map_element/fence.c +++ b/src/paint/map_element/fence.c @@ -367,9 +367,9 @@ void fence_paint(uint8 direction, int height, rct_map_element * map_element) utf8 signString[MAX_PATH]; rct_string_id stringId = STR_SCROLLING_SIGN_TEXT; if (gConfigGeneral.upper_case_banners) { - format_string_to_upper(signString, stringId, gCommonFormatArgs); + format_string_to_upper(signString, MAX_PATH, stringId, gCommonFormatArgs); } else { - format_string(signString, stringId, gCommonFormatArgs); + format_string(signString, MAX_PATH, stringId, gCommonFormatArgs); } gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY; diff --git a/src/paint/map_element/path.c b/src/paint/map_element/path.c index 83143b3ca5..8a5f1741a1 100644 --- a/src/paint/map_element/path.c +++ b/src/paint/map_element/path.c @@ -396,9 +396,9 @@ static void sub_6A4101(rct_map_element * map_element, uint16 height, uint32 ebp, string_id = STR_RIDE_ENTRANCE_NAME; } if (gConfigGeneral.upper_case_banners) { - format_string_to_upper(gCommonStringFormatBuffer, string_id, gCommonFormatArgs); + format_string_to_upper(gCommonStringFormatBuffer, 256, string_id, gCommonFormatArgs); } else { - format_string(gCommonStringFormatBuffer, string_id, gCommonFormatArgs); + format_string(gCommonStringFormatBuffer, 256, string_id, gCommonFormatArgs); } gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY; diff --git a/src/paint/map_element/scenery_multiple.c b/src/paint/map_element/scenery_multiple.c index 1ef3576456..0504f8f9a3 100644 --- a/src/paint/map_element/scenery_multiple.c +++ b/src/paint/map_element/scenery_multiple.c @@ -21,6 +21,7 @@ #include "../../game.h" #include "../../interface/viewport.h" #include "../../localisation/localisation.h" +#include "../../util/util.h" #include "../../world/map.h" #include "../../world/scenery.h" @@ -88,9 +89,9 @@ static int scenery_multiple_sign_text_height(const utf8 *str, rct_large_scenery_ static const utf8 *scenery_multiple_sign_fit_text(const utf8 *str, rct_large_scenery_text *text, bool height) { - static utf8 fitStr[32] = {0}; + static utf8 fitStr[32]; utf8 *fitStrEnd = fitStr; - strncpy(fitStr, str, sizeof(fitStr) - 1); + safe_strcpy(fitStr, str, sizeof(fitStr)); int w = 0; uint32 codepoint; while (w <= text->max_width && (codepoint = utf8_get_next(fitStrEnd, (const utf8**)&fitStrEnd)) != 0) { @@ -262,16 +263,16 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map stringId = ride->name; set_format_arg(0, uint32, ride->name_arguments); } - utf8 signString[MAX_PATH] = {0}; - format_string(signString, stringId, gCommonFormatArgs); + utf8 signString[MAX_PATH]; + format_string(signString, MAX_PATH, stringId, gCommonFormatArgs); rct_large_scenery_text *text = entry->large_scenery.text; int y_offset = (text->offset[(direction & 1)].y * 2); if (text->var_C & 0x1) { // Draw vertical sign: y_offset += 1; - utf8 fitStr[32] = {0}; + utf8 fitStr[32]; const utf8 *fitStrPtr = fitStr; - strncpy(fitStr, scenery_multiple_sign_fit_text(signString, text, true), sizeof(fitStr) - 1); + safe_strcpy(fitStr, scenery_multiple_sign_fit_text(signString, text, true), sizeof(fitStr)); int height = scenery_multiple_sign_text_height(fitStr, text); uint32 codepoint; while ((codepoint = utf8_get_next(fitStrPtr, &fitStrPtr)) != 0) { @@ -355,9 +356,9 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map utf8 signString[MAX_PATH]; rct_string_id stringId = STR_SCROLLING_SIGN_TEXT; if (gConfigGeneral.upper_case_banners) { - format_string_to_upper(signString, stringId, gCommonFormatArgs); + format_string_to_upper(signString, MAX_PATH, stringId, gCommonFormatArgs); } else { - format_string(signString, stringId, gCommonFormatArgs); + format_string(signString, MAX_PATH, stringId, gCommonFormatArgs); } gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY; diff --git a/src/paint/paint.c b/src/paint/paint.c index b81f47b15a..c44f6efa27 100644 --- a/src/paint/paint.c +++ b/src/paint/paint.c @@ -1094,7 +1094,7 @@ void viewport_draw_money_effects() draw_pixel_info_crop_by_zoom(&dpi); do { - format_string(buffer, ps->string_id, &ps->args); + format_string(buffer, 256, ps->string_id, &ps->args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; bool forceSpriteFont = false; diff --git a/src/peep/peep.c b/src/peep/peep.c index 8f19adc948..d5c572ce36 100644 --- a/src/peep/peep.c +++ b/src/peep/peep.c @@ -7364,7 +7364,7 @@ int peep_check_easteregg_name(int index, rct_peep *peep) { char buffer[256]; - format_string(buffer, peep->name_string_idx, &peep->id); + format_string(buffer, 256, peep->name_string_idx, &peep->id); return _stricmp(buffer, gPeepEasterEggNames[index]) == 0; } @@ -7373,7 +7373,7 @@ int peep_get_easteregg_name_id(rct_peep *peep) char buffer[256]; int i; - format_string(buffer, peep->name_string_idx, &peep->id); + format_string(buffer, 256, peep->name_string_idx, &peep->id); for (i = 0; i < countof(gPeepEasterEggNames); i++) if (_stricmp(buffer, gPeepEasterEggNames[i]) == 0) @@ -9889,7 +9889,7 @@ static int guest_path_finding(rct_peep* peep) /* For guests, use the existing PEEP_FLAGS_TRACKING flag to * determine for which guest(s) the pathfinding debugging will * be output for. */ - format_string(gPathFindDebugPeepName, peep->name_string_idx, &(peep->id)); + format_string(gPathFindDebugPeepName, sizeof(gPathFindDebugPeepName), peep->name_string_idx, &(peep->id)); gPathFindDebug = peep->peep_flags & PEEP_FLAGS_TRACKING; #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -11888,9 +11888,9 @@ static int peep_compare(const void *sprite_index_a, const void *sprite_index_b) utf8 name_a[256]; utf8 name_b[256]; uint32 peepIndex = peep_a->id; - format_string(name_a, peep_a->name_string_idx, &peepIndex); + format_string(name_a, 256, peep_a->name_string_idx, &peepIndex); peepIndex = peep_b->id; - format_string(name_b, peep_b->name_string_idx, &peepIndex); + format_string(name_b, 256, peep_b->name_string_idx, &peepIndex); return strlogicalcmp(name_a, name_b); } @@ -12059,7 +12059,7 @@ money32 set_peep_name(int flags, int state, uint16 sprite_index, uint8* text_1, set_format_arg(0, uint32, peep->id); utf8* curName = gCommonStringFormatBuffer; rct_string_id curId = peep->name_string_idx; - format_string(curName, curId, gCommonFormatArgs); + format_string(curName, 256, curId, gCommonFormatArgs); if (strcmp(curName, newName) == 0) return 0; diff --git a/src/peep/staff.c b/src/peep/staff.c index 8c35068ab5..72b73a99b1 100644 --- a/src/peep/staff.c +++ b/src/peep/staff.c @@ -1100,7 +1100,7 @@ static uint8 staff_mechanic_direction_path(rct_peep* peep, uint8 validDirections /* For staff, there is no tracking button (any other similar * suitable existing mechanism?), so fall back to a crude * string comparison with a compile time hardcoded name. */ - format_string(gPathFindDebugPeepName, peep->name_string_idx, &(peep->id)); + format_string(gPathFindDebugPeepName, sizeof(gPathFindDebugPeepName), peep->name_string_idx, &(peep->id)); gPathFindDebug = strcmp(gPathFindDebugPeepName, "Mechanic Debug") == 0; #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 diff --git a/src/platform/crash.cpp b/src/platform/crash.cpp index 378cd20908..d518a2717f 100644 --- a/src/platform/crash.cpp +++ b/src/platform/crash.cpp @@ -24,9 +24,6 @@ #include #include #include -#elif defined(__LINUX__) - #include - #define BREAKPAD_PATH "/tmp" #else #error Breakpad support not implemented yet for this platform #endif @@ -68,12 +65,12 @@ static bool OnCrash(const wchar_t * dumpPath, // Get filenames wchar_t dumpFilePath[MAX_PATH]; wchar_t saveFilePath[MAX_PATH]; - wsprintfW(dumpFilePath, L"%s%s.dmp", dumpPath, miniDumpId); - wsprintfW(saveFilePath, L"%s%s.sv6", dumpPath, miniDumpId); + swprintf_s(dumpFilePath, sizeof(dumpFilePath), L"%s%s.dmp", dumpPath, miniDumpId); + swprintf_s(saveFilePath, sizeof(saveFilePath), L"%s%s.sv6", dumpPath, miniDumpId); // Try to rename the files wchar_t dumpFilePathNew[MAX_PATH]; - wsprintfW(dumpFilePathNew, L"%s%s(%s).dmp", dumpPath, miniDumpId, _wszCommitSha1Short); + swprintf_s(dumpFilePathNew, sizeof(dumpFilePathNew), L"%s%s(%s).dmp", dumpPath, miniDumpId, _wszCommitSha1Short); if (_wrename(dumpFilePath, dumpFilePathNew) == 0) { std::wcscpy(dumpFilePath, dumpFilePathNew); @@ -141,7 +138,7 @@ static bool OnCrash(const wchar_t * dumpPath, static std::wstring GetDumpDirectory() { char userDirectory[MAX_PATH]; - platform_get_user_directory(userDirectory, NULL); + platform_get_user_directory(userDirectory, NULL, sizeof(userDirectory)); wchar_t * userDirectoryW = utf8_to_widechar(userDirectory); auto result = std::wstring(userDirectoryW); diff --git a/src/platform/linux.c b/src/platform/linux.c index 783da34f4a..5894cba234 100644 --- a/src/platform/linux.c +++ b/src/platform/linux.c @@ -46,7 +46,7 @@ struct dummy { typedef enum { DT_NONE, DT_KDIALOG, DT_ZENITY } dialog_type; -void platform_get_exe_path(utf8 *outPath) +void platform_get_exe_path(utf8 *outPath, size_t outSize) { char exePath[MAX_PATH]; ssize_t bytesRead; @@ -55,17 +55,16 @@ void platform_get_exe_path(utf8 *outPath) log_fatal("failed to read /proc/self/exe"); } exePath[bytesRead - 1] = '\0'; - char *exeDelimiter = strrchr(exePath, platform_get_path_separator()); + char *exeDelimiter = strrchr(exePath, *PATH_SEPARATOR); if (exeDelimiter == NULL) { log_error("should never happen here"); outPath[0] = '\0'; return; } - int exeDelimiterIndex = (int)(exeDelimiter - exePath); + *exeDelimiter = '\0'; - exePath[exeDelimiterIndex] = '\0'; - safe_strcpy(outPath, exePath, exeDelimiterIndex + 1); + safe_strcpy(outPath, exePath, outSize); } bool platform_check_steam_overlay_attached() { @@ -94,7 +93,7 @@ bool platform_check_steam_overlay_attached() { * - $XDG_CONFIG_HOME/OpenRCT2 * - /home/[uid]/.config/OpenRCT2 */ -void platform_posix_sub_user_data_path(char *buffer, const char *homedir, const char *separator) { +void platform_posix_sub_user_data_path(char *buffer, size_t size, const char *homedir) { const char *configdir = getenv("XDG_CONFIG_HOME"); log_verbose("configdir = '%s'", configdir); if (configdir == NULL) @@ -107,17 +106,15 @@ void platform_posix_sub_user_data_path(char *buffer, const char *homedir, const return; } - strncat(buffer, homedir, MAX_PATH - 1); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, ".config", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + safe_strcpy(buffer, homedir, size); + safe_strcat_path(buffer, ".config", size); } else { - strncat(buffer, configdir, MAX_PATH - 1); + safe_strcpy(buffer, configdir, size); } - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, "OpenRCT2", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + safe_strcat_path(buffer, "OpenRCT2", size); + path_end_with_separator(buffer, size); } /** @@ -128,7 +125,7 @@ void platform_posix_sub_user_data_path(char *buffer, const char *homedir, const * - /var/lib/openrct2 * - /usr/share/openrct2 */ -void platform_posix_sub_resolve_openrct_data_path(utf8 *out) { +void platform_posix_sub_resolve_openrct_data_path(utf8 *out, size_t size) { static const utf8 *searchLocations[] = { "../share/openrct2", #ifdef ORCT2_RESOURCE_DIR @@ -144,8 +141,7 @@ void platform_posix_sub_resolve_openrct_data_path(utf8 *out) { log_verbose("Looking for OpenRCT2 data in %s", searchLocations[i]); if (platform_directory_exists(searchLocations[i])) { - out[0] = '\0'; - safe_strcpy(out, searchLocations[i], MAX_PATH); + safe_strcpy(out, searchLocations[i], size); return; } } @@ -169,7 +165,7 @@ uint16 platform_get_locale_language(){ } } } //end strip - strncpy(pattern,langString, length); //copy all until first '.' or '@' + memcpy(pattern, langString, length); //copy all until first '.' or '@' pattern[length] = '\0'; //find _ if present const char *strip = strchr(pattern, '_'); @@ -304,7 +300,7 @@ static dialog_type get_dialog_app(char *cmd, size_t *cmd_size) { return dtype; } -bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) { +bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc, size_t outSize) { int exit_value; char executable[MAX_PATH]; char cmd[MAX_PATH]; @@ -428,7 +424,7 @@ bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) snprintf(msg, MAX_PATH, "\"%s\" not found: %s, please choose another file\n", result, strerror(errno)); platform_show_messagebox(msg); - return platform_open_common_file_dialog(outFilename, desc); + return platform_open_common_file_dialog(outFilename, desc, outSize); } else if (desc->type == FD_SAVE && access(result, F_OK) != -1 && dtype == DT_KDIALOG) { snprintf(cmd, MAX_PATH, "%s --yesno \"Overwrite %s?\"", executable, result); @@ -441,7 +437,7 @@ bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) } } - strncpy(outFilename, result, MAX_PATH); + safe_strcpy(outFilename, result, outSize); return 1; } @@ -477,8 +473,7 @@ utf8 *platform_open_directory_browser(utf8 *title) { result[size-1] = '\0'; - return_value = (char*) malloc(strlen(result)+1); - strcpy(return_value, result); + return_value = _strdup(result); return return_value; } @@ -510,7 +505,7 @@ void platform_show_messagebox(char *message) { execute_cmd(cmd, 0, 0, 0); } -bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) +bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer, size_t size) { assert(buffer != NULL); assert(font != NULL); @@ -538,7 +533,7 @@ bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) if (FcPatternGetString(match, FC_FILE, 0, &filename) == FcResultMatch) { found = true; - safe_strcpy(buffer, (utf8*) filename, MAX_PATH); + safe_strcpy(buffer, (utf8*) filename, size); log_verbose("FontConfig provided font %s", filename); } FcPatternDestroy(match); diff --git a/src/platform/macos.m b/src/platform/macos.m index 12bc0b1219..24aff3a1b4 100644 --- a/src/platform/macos.m +++ b/src/platform/macos.m @@ -29,8 +29,9 @@ bool platform_check_steam_overlay_attached() { return false; } -void platform_get_exe_path(utf8 *outPath) +void platform_get_exe_path(utf8 *outPath, size_t outSize) { + if (outSize == 0) return; char exePath[MAX_PATH]; uint32_t size = MAX_PATH; int result = _NSGetExecutablePath(exePath, &size); @@ -38,17 +39,16 @@ void platform_get_exe_path(utf8 *outPath) log_fatal("failed to get path"); } exePath[MAX_PATH - 1] = '\0'; - char *exeDelimiter = strrchr(exePath, platform_get_path_separator()); + char *exeDelimiter = strrchr(exePath, *PATH_SEPARATOR); if (exeDelimiter == NULL) { log_error("should never happen here"); outPath[0] = '\0'; return; } - int exeDelimiterIndex = (int)(exeDelimiter - exePath); + *exeDelimiter = '\0'; - safe_strcpy(outPath, exePath, exeDelimiterIndex + 1); - outPath[exeDelimiterIndex] = '\0'; + safe_strcpy(outPath, exePath, outSize); } /** @@ -56,7 +56,7 @@ void platform_get_exe_path(utf8 *outPath) * - (command line argument) * - ~/Library/Application Support/OpenRCT2 */ -void platform_posix_sub_user_data_path(char *buffer, const char *homedir, const char *separator) { +void platform_posix_sub_user_data_path(char *buffer, size_t size, const char *homedir) { if (homedir == NULL) { log_fatal("Couldn't find user data directory"); @@ -64,14 +64,11 @@ void platform_posix_sub_user_data_path(char *buffer, const char *homedir, const return; } - strncat(buffer, homedir, MAX_PATH - 1); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, "Library", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, "Application Support", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, "OpenRCT2", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + safe_strcpy(buffer, homedir, size); + safe_strcat_path(buffer, "Library", size); + safe_strcat_path(buffer, "Application Support", size); + safe_strcat_path(buffer, "OpenRCT2", size); + path_end_with_separator(buffer, size); } /** @@ -80,7 +77,7 @@ void platform_posix_sub_user_data_path(char *buffer, const char *homedir, const * - /data * - */ -void platform_posix_sub_resolve_openrct_data_path(utf8 *out) { +void platform_posix_sub_resolve_openrct_data_path(utf8 *out, size_t size) { @autoreleasepool { NSBundle *bundle = [NSBundle mainBundle]; @@ -90,7 +87,7 @@ void platform_posix_sub_resolve_openrct_data_path(utf8 *out) { if (platform_directory_exists(resources)) { out[0] = '\0'; - safe_strcpy(out, resources, MAX_PATH); + safe_strcpy(out, resources, size); return; } } @@ -121,14 +118,13 @@ utf8 *platform_open_directory_browser(utf8 *title) { NSString *selectedPath = panel.URL.path; const char *path = selectedPath.UTF8String; - url = (utf8*)malloc(strlen(path) + 1); - strcpy(url,path); + url = _strdup(path); } return url; } } -bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) { +bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc, size_t outSize) { @autoreleasepool { NSMutableArray *extensions = [NSMutableArray new]; @@ -169,14 +165,14 @@ bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) SDL_RaiseWindow(gWindow); return false; } else { - strcpy(outFilename, panel.URL.path.UTF8String); + safe_strcpy(outFilename, panel.URL.path.UTF8String, outSize); SDL_RaiseWindow(gWindow); return true; } } } -bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) +bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer, size_t size) { @autoreleasepool { @@ -184,7 +180,7 @@ bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fontRef, kCTFontURLAttribute); if (url) { NSString *fontPath = [NSString stringWithString:[(NSURL *)CFBridgingRelease(url) path]]; - strcpy(buffer, fontPath.UTF8String); + safe_strcpy(buffer, fontPath.UTF8String, size); return true; } else { return false; diff --git a/src/platform/platform.h b/src/platform/platform.h index ac813b561c..23cde3c2b6 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -46,8 +46,10 @@ #ifdef __WINDOWS__ #define PATH_SEPARATOR "\\" +#define PLATFORM_NEWLINE "\r\n" #else #define PATH_SEPARATOR "/" +#define PLATFORM_NEWLINE "\n" #endif typedef struct resolution { @@ -145,9 +147,7 @@ void platform_get_date_local(rct2_date *out_date); void platform_get_time_local(rct2_time *out_time); // Platform specific definitions -void platform_get_exe_path(utf8 *outPath); -const char *platform_get_new_line(); -char platform_get_path_separator(); +void platform_get_exe_path(utf8 *outPath, size_t outSize); bool platform_file_exists(const utf8 *path); bool platform_directory_exists(const utf8 *path); bool platform_original_game_data_exists(const utf8 *path); @@ -177,18 +177,18 @@ void platform_set_cursor_position(int x, int y); unsigned int platform_get_ticks(); void platform_resolve_user_data_path(); void platform_resolve_openrct_data_path(); -void platform_get_openrct_data_path(utf8 *outPath); -void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory); +void platform_get_openrct_data_path(utf8 *outPath, size_t outSize); +void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory, size_t outSize); utf8* platform_get_username(); void platform_show_messagebox(utf8 *message); -bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc); +bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc, size_t outSize); utf8 *platform_open_directory_browser(utf8 *title); uint8 platform_get_locale_currency(); uint8 platform_get_currency_value(const char *currencyCode); uint16 platform_get_locale_language(); uint8 platform_get_locale_measurement_format(); uint8 platform_get_locale_temperature_format(); -bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer); +bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer, size_t size); bool platform_check_steam_overlay_attached(); @@ -212,8 +212,8 @@ datetime64 platform_get_datetime_now_utc(); #endif // __WINDOWS__ #if defined(__LINUX__) || defined(__MACOSX__) - void platform_posix_sub_user_data_path(char *buffer, const char *homedir, const char *separator); - void platform_posix_sub_resolve_openrct_data_path(utf8 *out); + void platform_posix_sub_user_data_path(char *buffer, size_t size, const char *homedir); + void platform_posix_sub_resolve_openrct_data_path(utf8 *out, size_t size); #endif #endif diff --git a/src/platform/posix.c b/src/platform/posix.c index 48dac48ce2..3cd135cd2e 100644 --- a/src/platform/posix.c +++ b/src/platform/posix.c @@ -111,16 +111,6 @@ void platform_get_time_local(rct2_time *out_time) out_time->hour = timeinfo->tm_hour; } -char platform_get_path_separator() -{ - return '/'; -} - -const char *platform_get_new_line() -{ - return "\n"; -} - bool platform_file_exists(const utf8 *path) { wchar_t *wPath = utf8_to_widechar(path); @@ -160,9 +150,10 @@ bool platform_original_game_data_exists(const utf8 *path) wcstombs(buffer, wPath, len); buffer[len] = '\0'; free(wPath); - char separator = platform_get_path_separator(); char checkPath[MAX_PATH]; - sprintf(checkPath, "%s%c%s%c%s", buffer, separator, "Data", separator, "g1.dat"); + safe_strcpy(checkPath, buffer, MAX_PATH); + safe_strcat_path(checkPath, "Data", MAX_PATH); + safe_strcat_path(checkPath, "g1.dat", MAX_PATH); return platform_file_exists(checkPath); } @@ -198,8 +189,7 @@ bool platform_directory_delete(const utf8 *path) FTSENT *p, *chp; // fts_open only accepts non const paths, so we have to take a copy - char* ourPath = (char*)malloc(strlen(path) + 1); - strcpy(ourPath, path); + char* ourPath = _strdup(path); utf8* const patharray[2] = {ourPath, NULL}; if ((ftsp = fts_open(patharray, FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR, NULL)) == NULL) { @@ -321,7 +311,7 @@ int platform_enumerate_files_begin(const utf8 *pattern) } log_verbose("begin file search, pattern: %s", npattern); - char *file_name = strrchr(npattern, platform_get_path_separator()); + char *file_name = strrchr(npattern, *PATH_SEPARATOR); char *dir_name; if (file_name != NULL) { @@ -356,7 +346,6 @@ int platform_enumerate_files_begin(const utf8 *pattern) char **paths = enumFileInfo->paths; // 256 is size of dirent.d_name const int dir_name_len = strnlen(dir_name, MAX_PATH); - char separator[] = {platform_get_path_separator(), 0}; for (int idx = 0; idx < cnt; idx++) { struct dirent *d = enumFileInfo->fileListTemp[idx]; @@ -364,11 +353,9 @@ int platform_enumerate_files_begin(const utf8 *pattern) // 1 for separator, 1 for trailing null size_t path_len = sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2); paths[idx] = malloc(path_len); - paths[idx][0] = '\0'; log_verbose("dir_name: %s", dir_name); - strncat(paths[idx], dir_name, path_len - 2); - strncat(paths[idx], separator, path_len - strnlen(paths[idx], path_len) - 1); - strncat(paths[idx], d->d_name, path_len - strnlen(paths[idx], path_len) - 1); + safe_strcpy(paths[idx], dir_name, path_len); + safe_strcat_path(paths[idx], d->d_name, path_len); log_verbose("paths[%d] = %s", idx, paths[idx]); } enumFileInfo->handle = 0; @@ -495,7 +482,6 @@ int platform_enumerate_directories_begin(const utf8 *directory) char **paths = enumFileInfo->paths; // 256 is size of dirent.d_name const int dir_name_len = strnlen(npattern, MAX_PATH); - char separator[] = {platform_get_path_separator(), 0}; for (int idx = 0; idx < cnt; idx++) { struct dirent *d = enumFileInfo->fileListTemp[idx]; @@ -503,11 +489,9 @@ int platform_enumerate_directories_begin(const utf8 *directory) // 1 for separator, 1 for trailing null size_t path_len = sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2); paths[idx] = malloc(path_len); - paths[idx][0] = '\0'; log_verbose("dir_name: %s", npattern); - strncat(paths[idx], npattern, path_len - 2); - strncat(paths[idx], separator, path_len - strnlen(paths[idx], path_len) - 1); - strncat(paths[idx], d->d_name, path_len - strnlen(paths[idx], path_len) - 1); + safe_strcpy(paths[idx], npattern, path_len); + safe_strcat_path(paths[idx], d->d_name, path_len); log_verbose("paths[%d] = %s", idx, paths[idx]); } enumFileInfo->handle = 0; @@ -552,7 +536,7 @@ bool platform_enumerate_directories_next(int handle, utf8 *path) } // so very, very wrong safe_strcpy(path, basename(fileName), MAX_PATH); - strncat(path, "/", MAX_PATH - strlen(path) - 1); + path_end_with_separator(path, MAX_PATH); return true; } else { return false; @@ -679,7 +663,6 @@ static wchar_t *regular_to_wchar(const char* src) */ void platform_resolve_user_data_path() { - const char separator[2] = { platform_get_path_separator(), 0 }; if (gCustomUserDataPath[0] != 0) { if (!platform_ensure_directory_exists(gCustomUserDataPath)) { @@ -696,10 +679,7 @@ void platform_resolve_user_data_path() free(path); // Ensure path ends with separator - int len = strlen(_userDataDirectoryPath); - if (_userDataDirectoryPath[len - 1] != separator[0]) { - strncat(_userDataDirectoryPath, separator, MAX_PATH - 1); - } + path_end_with_separator(_userDataDirectoryPath, MAX_PATH); log_verbose("User data path resolved to: %s", _userDataDirectoryPath); if (!platform_directory_exists(_userDataDirectoryPath)) { log_error("Custom user data directory %s does not exist", _userDataDirectoryPath); @@ -708,11 +688,10 @@ void platform_resolve_user_data_path() } char buffer[MAX_PATH]; - buffer[0] = '\0'; log_verbose("buffer = '%s'", buffer); const char *homedir = getpwuid(getuid())->pw_dir; - platform_posix_sub_user_data_path(buffer, homedir, separator); + platform_posix_sub_user_data_path(buffer, MAX_PATH, homedir); log_verbose("OpenRCT2 user data directory = '%s'", buffer); int len = strnlen(buffer, MAX_PATH); @@ -725,9 +704,9 @@ void platform_resolve_user_data_path() log_verbose("User data path resolved to: %s", _userDataDirectoryPath); } -void platform_get_openrct_data_path(utf8 *outPath) +void platform_get_openrct_data_path(utf8 *outPath, size_t outSize) { - safe_strcpy(outPath, _openrctDataDirectoryPath, sizeof(_openrctDataDirectoryPath)); + safe_strcpy(outPath, _openrctDataDirectoryPath, outSize); } /** @@ -738,27 +717,20 @@ void platform_get_openrct_data_path(utf8 *outPath) */ void platform_resolve_openrct_data_path() { - const char separator[2] = { platform_get_path_separator(), 0 }; - if (gCustomOpenrctDataPath[0] != 0) { if (realpath(gCustomOpenrctDataPath, _openrctDataDirectoryPath)) { log_error("Could not resolve path \"%s\"", gCustomOpenrctDataPath); return; } - // Ensure path ends with separator - int len = strlen(_openrctDataDirectoryPath); - if (_openrctDataDirectoryPath[len - 1] != separator[0]) { - strncat(_openrctDataDirectoryPath, separator, MAX_PATH - 1); - } + path_end_with_separator(_openrctDataDirectoryPath, MAX_PATH); return; } - char buffer[MAX_PATH] = { 0 }; - platform_get_exe_path(buffer); + char buffer[MAX_PATH]; + platform_get_exe_path(buffer, sizeof(buffer)); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, "data", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + safe_strcat_path(buffer, "data", MAX_PATH); log_verbose("Looking for OpenRCT2 data in %s", buffer); if (platform_directory_exists(buffer)) { @@ -768,26 +740,25 @@ void platform_resolve_openrct_data_path() return; } - platform_posix_sub_resolve_openrct_data_path(_openrctDataDirectoryPath); + platform_posix_sub_resolve_openrct_data_path(_openrctDataDirectoryPath, sizeof(_openrctDataDirectoryPath)); log_verbose("Trying to use OpenRCT2 data in %s", _openrctDataDirectoryPath); } -void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory) +void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory, size_t outSize) { - const char separator[2] = { platform_get_path_separator(), 0 }; char buffer[MAX_PATH]; safe_strcpy(buffer, _userDataDirectoryPath, sizeof(buffer)); if (subDirectory != NULL && subDirectory[0] != 0) { log_verbose("adding subDirectory '%s'", subDirectory); - strncat(buffer, subDirectory, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + safe_strcat_path(buffer, subDirectory, sizeof(buffer)); + path_end_with_separator(buffer, sizeof(buffer)); } int len = strnlen(buffer, MAX_PATH); wchar_t *w_buffer = regular_to_wchar(buffer); w_buffer[len] = '\0'; utf8 *path = widechar_to_utf8(w_buffer); free(w_buffer); - safe_strcpy(outPath, path, MAX_PATH); + safe_strcpy(outPath, path, outSize); free(path); log_verbose("outPath + subDirectory = '%s'", buffer); } diff --git a/src/platform/shared.c b/src/platform/shared.c index f9428ef96c..b2c14f00c5 100644 --- a/src/platform/shared.c +++ b/src/platform/shared.c @@ -517,7 +517,7 @@ void platform_process_messages() break; case SDL_TEXTEDITING: // When inputting Korean characters, `e.edit.length` is always Zero. - safe_strcpy(gTextInputComposition, e.edit.text, min((e.edit.length == 0) ? (strlen(e.edit.text)+1) : e.edit.length, 32)); + safe_strcpy(gTextInputComposition, e.edit.text, sizeof(gTextInputComposition)); gTextInputCompositionStart = e.edit.start; gTextInputCompositionLength = e.edit.length; gTextInputCompositionActive = ((e.edit.length != 0 || strlen(e.edit.text) != 0) && gTextInputComposition[0] != 0); diff --git a/src/platform/windows.c b/src/platform/windows.c index c4a339e28a..29a83d451a 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -178,16 +178,6 @@ void platform_get_time_local(rct2_time *out_time) out_time->second = systime.wSecond; } -char platform_get_path_separator() -{ - return '\\'; -} - -const char *platform_get_new_line() -{ - return "\r\n"; -} - bool platform_file_exists(const utf8 *path) { wchar_t *wPath = utf8_to_widechar(path); @@ -208,7 +198,9 @@ bool platform_directory_exists(const utf8 *path) bool platform_original_game_data_exists(const utf8 *path) { utf8 checkPath[MAX_PATH]; - sprintf(checkPath, "%s%c%s%c%s", path, platform_get_path_separator(), "Data", platform_get_path_separator(), "g1.dat"); + safe_strcpy(checkPath, path, MAX_PATH); + safe_strcat_path(checkPath, "Data", MAX_PATH); + safe_strcat_path(checkPath, "g1.dat", MAX_PATH); return platform_file_exists(checkPath); } @@ -465,8 +457,8 @@ bool platform_enumerate_directories_next(int handle, utf8 *path) } utf8 *filename = widechar_to_utf8(enumFileInfo->data.cFileName); - strncpy(path, filename, MAX_PATH); - strncat(path, "\\", MAX_PATH); + safe_strcpy(path, filename, MAX_PATH); + path_end_with_separator(path, MAX_PATH); free(filename); return true; } @@ -519,7 +511,6 @@ bool platform_file_delete(const utf8 *path) void platform_resolve_openrct_data_path() { wchar_t wOutPath[MAX_PATH]; - const char separator[2] = { platform_get_path_separator(), 0 }; if (gCustomOpenrctDataPath[0] != 0) { wchar_t *customUserDataPathW = utf8_to_widechar(gCustomOpenrctDataPath); @@ -532,18 +523,13 @@ void platform_resolve_openrct_data_path() free(outPathTemp); free(customUserDataPathW); - // Ensure path ends with separator - size_t len = strlen(_userDataDirectoryPath); - if (_userDataDirectoryPath[len - 1] != separator[0]) { - strcat(_userDataDirectoryPath, separator); - } + path_end_with_separator(_userDataDirectoryPath, sizeof(_userDataDirectoryPath)); return; } - char buffer[MAX_PATH] = { 0 }; - platform_get_exe_path(buffer); + char buffer[MAX_PATH]; + platform_get_exe_path(buffer, sizeof(buffer)); - strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); - strncat(buffer, "data", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + safe_strcat_path(buffer, "data", MAX_PATH); if (platform_directory_exists(buffer)) { @@ -556,9 +542,9 @@ void platform_resolve_openrct_data_path() } } -void platform_get_openrct_data_path(utf8 *outPath) +void platform_get_openrct_data_path(utf8 *outPath, size_t outSize) { - safe_strcpy(outPath, _openrctDataDirectoryPath, sizeof(_openrctDataDirectoryPath)); + safe_strcpy(outPath, _openrctDataDirectoryPath, outSize); } /** @@ -569,7 +555,6 @@ void platform_get_openrct_data_path(utf8 *outPath) void platform_resolve_user_data_path() { wchar_t wOutPath[MAX_PATH]; - const char separator[2] = { platform_get_path_separator(), 0 }; if (gCustomUserDataPath[0] != 0) { wchar_t *customUserDataPathW = utf8_to_widechar(gCustomUserDataPath); @@ -582,11 +567,7 @@ void platform_resolve_user_data_path() free(outPathTemp); free(customUserDataPathW); - // Ensure path ends with separator - size_t len = strlen(_userDataDirectoryPath); - if (_userDataDirectoryPath[len - 1] != separator[0]) { - strcat(_userDataDirectoryPath, separator); - } + path_end_with_separator(_userDataDirectoryPath, sizeof(_userDataDirectoryPath)); return; } @@ -595,23 +576,20 @@ void platform_resolve_user_data_path() safe_strcpy(_userDataDirectoryPath, outPathTemp, sizeof(_userDataDirectoryPath)); free(outPathTemp); - strcat(_userDataDirectoryPath, separator); - strcat(_userDataDirectoryPath, "OpenRCT2"); - strcat(_userDataDirectoryPath, separator); + safe_strcat_path(_userDataDirectoryPath, "OpenRCT2", sizeof(_userDataDirectoryPath)); + path_end_with_separator(_userDataDirectoryPath, sizeof(_userDataDirectoryPath)); } else { log_fatal("Unable to resolve user data path."); exit(-1); } } -void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory) +void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory, size_t outSize) { - const char separator[2] = { platform_get_path_separator(), 0 }; - - strcpy(outPath, _userDataDirectoryPath); + safe_strcpy(outPath, _userDataDirectoryPath, outSize); if (subDirectory != NULL && subDirectory[0] != 0) { - strcat(outPath, subDirectory); - strcat(outPath, separator); + safe_strcat_path(outPath, subDirectory, outSize); + path_end_with_separator(outPath, outSize); } } @@ -624,7 +602,7 @@ void platform_show_messagebox(utf8 *message) * * rct2: 0x004080EA */ -bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) +bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc, size_t outSize) { OPENFILENAMEW openFileName; wchar_t wcFilename[MAX_PATH]; @@ -651,9 +629,9 @@ bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) utf8 *ch = filters; for (int i = 0; i < countof(desc->filters); i++) { if (desc->filters[i].name != NULL) { - strcpy(ch, desc->filters[i].name); + safe_strcpy(ch, desc->filters[i].name, sizeof(filters) - (ch - filters)); ch = strchr(ch, 0) + 1; - strcpy(ch, desc->filters[i].pattern); + safe_strcpy(ch, desc->filters[i].pattern, sizeof(filters) - (ch - filters)); ch = strchr(ch, 0) + 1; } } @@ -695,7 +673,7 @@ bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) if (result) { utf8 *resultFilename = widechar_to_utf8(openFileName.lpstrFile); - strcpy(outFilename, resultFilename); + safe_strcpy(outFilename, resultFilename, outSize); free(resultFilename); // If there is no extension, append the pattern @@ -709,7 +687,7 @@ bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) const utf8 *pattern = desc->filters[filterIndex].pattern; const utf8 *patternExtension = path_get_extension(pattern); if (!str_is_null_or_empty(patternExtension)) { - strcat(outFilename, patternExtension); + safe_strcat_path(outFilename, patternExtension, outSize); } } } @@ -775,10 +753,10 @@ int windows_get_registry_install_info(rct2_install_info *installInfo, char *sour HKEY hKey; DWORD type, size; - strcpy(subkeyInfogrames, "Software\\Infogrames\\"); - strcat(subkeyInfogrames, source); - strcpy(subkeyFishTechGroup, "Software\\Fish Technology Group\\"); - strcat(subkeyFishTechGroup, source); + safe_strcpy(subkeyInfogrames, "Software\\Infogrames\\", sizeof(subkeyInfogrames)); + safe_strcat(subkeyInfogrames, source, sizeof(subkeyInfogrames)); + safe_strcpy(subkeyFishTechGroup, "Software\\Fish Technology Group\\", sizeof(subkeyFishTechGroup)); + safe_strcat(subkeyFishTechGroup, source, sizeof(subkeyFishTechGroup)); if (RegOpenKeyA(HKEY_LOCAL_MACHINE, subkeyInfogrames, &hKey) != ERROR_SUCCESS) return 0; @@ -798,7 +776,7 @@ int windows_get_registry_install_info(rct2_install_info *installInfo, char *sour size = 4; RegQueryValueExA(hKey, "InstallLevel", 0, &type, (LPBYTE)&installInfo->installLevel, &size); for (int i = 0; i <= 15; i++) { - sprintf(keyName, "AddonPack%d", i); + snprintf(keyName, 100, "AddonPack%d", i); size = sizeof(installInfo->expansionPackNames[i]); if (RegQueryValueExA(hKey, keyName, 0, &type, installInfo->expansionPackNames[i], &size) == ERROR_SUCCESS) installInfo->activeExpansionPacks |= (1 << i); @@ -992,23 +970,21 @@ char *strndup(const char *src, size_t size) return (char *)dst; } -void platform_get_exe_path(utf8 *outPath) +void platform_get_exe_path(utf8 *outPath, size_t outSize) { wchar_t exePath[MAX_PATH]; wchar_t tempPath[MAX_PATH]; wchar_t *exeDelimiter; - int exeDelimiterIndex; GetModuleFileNameW(NULL, exePath, MAX_PATH); - exeDelimiter = wcsrchr(exePath, platform_get_path_separator()); - exeDelimiterIndex = (int)(exeDelimiter - exePath); - lstrcpynW(tempPath, exePath, exeDelimiterIndex + 1); - tempPath[exeDelimiterIndex] = L'\0'; + exeDelimiter = wcsrchr(exePath, *PATH_SEPARATOR); + *exeDelimiter = L'\0'; + wcscpy_s(tempPath, MAX_PATH, exePath); _wfullpath(exePath, tempPath, MAX_PATH); - WideCharToMultiByte(CP_UTF8, 0, exePath, countof(exePath), outPath, MAX_PATH, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, exePath, MAX_PATH, outPath, (int) outSize, NULL, NULL); } -bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) +bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer, size_t size) { #if !defined(__MINGW32__) && ((NTDDI_VERSION >= NTDDI_VISTA) && !defined(_USING_V110_SDK71_) && !defined(_ATL_XP_TARGETING)) wchar_t *fontFolder; @@ -1016,15 +992,13 @@ bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) { // Convert wchar to utf8, then copy the font folder path to the buffer. utf8 *outPathTemp = widechar_to_utf8(fontFolder); - strcpy(buffer, outPathTemp); + safe_strcpy(buffer, outPathTemp, size); free(outPathTemp); CoTaskMemFree(fontFolder); // Append the requested font's file name. - const char separator[2] = { platform_get_path_separator(), 0 }; - strcat(buffer, separator); - strcat(buffer, font->filename); + safe_strcat_path(buffer, font->filename, size); return true; } else @@ -1033,8 +1007,8 @@ bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) } #else log_warning("Compatibility hack: falling back to C:\\Windows\\Fonts"); - strcpy(buffer, "C:\\Windows\\Fonts\\"); - strcat(buffer, font->filename); + safe_strcpy(buffer, "C:\\Windows\\Fonts\\", size); + safe_strcat_path(buffer, font->filename, size); return true; #endif } @@ -1090,6 +1064,8 @@ static bool windows_setup_file_association( ) { wchar_t exePathW[MAX_PATH]; wchar_t dllPathW[MAX_PATH]; + + int printResult; GetModuleFileNameW(NULL, exePathW, sizeof(exePathW)); GetModuleFileNameW(_dllModule, dllPathW, sizeof(dllPathW)); @@ -1126,7 +1102,8 @@ static bool windows_setup_file_association( } // [hRootKey\OpenRCT2.ext\DefaultIcon] wchar_t szIconW[MAX_PATH]; - wsprintfW(szIconW, L"\"%s\",%d", dllPathW, iconIndex); + printResult = swprintf_s(szIconW, MAX_PATH, L"\"%s\",%d", dllPathW, iconIndex); + assert(printResult >= 0); if (RegSetValueW(hKey, L"DefaultIcon", REG_SZ, szIconW, 0) != ERROR_SUCCESS) { goto fail; } @@ -1143,7 +1120,8 @@ static bool windows_setup_file_association( // [hRootKey\OpenRCT2.sv6\shell\open\command] wchar_t szCommandW[MAX_PATH]; - wsprintfW(szCommandW, L"\"%s\" %s", exePathW, commandArgsW); + printResult = swprintf_s(szCommandW, MAX_PATH, L"\"%s\" %s", exePathW, commandArgsW); + assert(printResult >= 0); if (RegSetValueW(hKey, L"shell\\open\\command", REG_SZ, szCommandW, 0) != ERROR_SUCCESS) { goto fail; } diff --git a/src/rct2.c b/src/rct2.c index 87b8ef3e61..fa3c1cfbff 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -204,59 +204,55 @@ int rct2_init_directories() { // windows_get_registry_install_info((rct2_install_info*)0x009AA10C, "RollerCoaster Tycoon 2 Setup", "MS Sans Serif", 0); - char separator[] = {platform_get_path_separator(), 0}; - if (str_is_null_or_empty(gCustomRCT2DataPath)) { // check install directory if (!platform_original_game_data_exists(gConfigGeneral.game_path)) { log_verbose("install directory does not exist or invalid directory selected, %s", gConfigGeneral.game_path); if (!config_find_or_browse_install_directory()) { utf8 path[MAX_PATH]; - config_get_default_path(path); + config_get_default_path(path, sizeof(path)); log_fatal("Invalid RCT2 installation path. Please correct \"game_path\" in %s.", path); return 0; } } - strcpy(gRCT2AddressAppPath, gConfigGeneral.game_path); + safe_strcpy(gRCT2AddressAppPath, gConfigGeneral.game_path, sizeof(gRCT2AddressAppPath)); } else { - strcpy(gRCT2AddressAppPath, gCustomRCT2DataPath); + safe_strcpy(gRCT2AddressAppPath, gCustomRCT2DataPath, sizeof(gRCT2AddressAppPath)); } - strcat(gRCT2AddressAppPath, separator); + path_end_with_separator(gRCT2AddressAppPath, sizeof(gRCT2AddressAppPath)); - strcpy(gRCT2AddressSavedGamesPath, gRCT2AddressAppPath); - strcat(gRCT2AddressSavedGamesPath, "Saved Games"); - strcat(gRCT2AddressSavedGamesPath, separator); + safe_strcpy(gRCT2AddressSavedGamesPath, gRCT2AddressAppPath, sizeof(gRCT2AddressSavedGamesPath)); + safe_strcat_path(gRCT2AddressSavedGamesPath, "Saved Games", sizeof(gRCT2AddressSavedGamesPath)); + path_end_with_separator(gRCT2AddressSavedGamesPath, sizeof(gRCT2AddressSavedGamesPath)); - strcpy(gRCT2AddressScenariosPath, gRCT2AddressAppPath); - strcat(gRCT2AddressScenariosPath, "Scenarios"); - strcat(gRCT2AddressScenariosPath, separator); - strcat(gRCT2AddressScenariosPath, "*.SC6"); + safe_strcpy(gRCT2AddressScenariosPath, gRCT2AddressAppPath, sizeof(gRCT2AddressScenariosPath)); + safe_strcat_path(gRCT2AddressScenariosPath, "Scenarios", sizeof(gRCT2AddressScenariosPath)); + safe_strcat_path(gRCT2AddressScenariosPath, "*.SC6", sizeof(gRCT2AddressScenariosPath)); - strcpy(gRCT2AddressLandscapesPath, gRCT2AddressAppPath); - strcat(gRCT2AddressLandscapesPath, "Landscapes"); - strcat(gRCT2AddressLandscapesPath, separator); - strcat(gRCT2AddressLandscapesPath, "*.SC6"); + safe_strcpy(gRCT2AddressLandscapesPath, gRCT2AddressAppPath, sizeof(gRCT2AddressLandscapesPath)); + safe_strcat_path(gRCT2AddressLandscapesPath, "Landscapes", sizeof(gRCT2AddressLandscapesPath)); + safe_strcat_path(gRCT2AddressLandscapesPath, "*.SC6", sizeof(gRCT2AddressLandscapesPath)); - strcpy(gRCT2AddressObjectDataPath, gRCT2AddressAppPath); - strcat(gRCT2AddressObjectDataPath, "ObjData"); - strcat(gRCT2AddressObjectDataPath, separator); - strcat(gRCT2AddressObjectDataPath, "*.DAT"); + safe_strcpy(gRCT2AddressObjectDataPath, gRCT2AddressAppPath, sizeof(gRCT2AddressObjectDataPath)); + safe_strcat_path(gRCT2AddressObjectDataPath, "ObjData", sizeof(gRCT2AddressObjectDataPath)); + safe_strcat_path(gRCT2AddressObjectDataPath, "*.DAT", sizeof(gRCT2AddressObjectDataPath)); - strcpy(gRCT2AddressTracksPath, gRCT2AddressAppPath); - strcat(gRCT2AddressTracksPath, "Tracks"); - strcat(gRCT2AddressTracksPath, separator); - strcat(gRCT2AddressTracksPath, "*.TD?"); + safe_strcpy(gRCT2AddressTracksPath, gRCT2AddressAppPath, sizeof(gRCT2AddressTracksPath)); + safe_strcat_path(gRCT2AddressTracksPath, "Tracks", sizeof(gRCT2AddressTracksPath)); + safe_strcat_path(gRCT2AddressTracksPath, "*.TD?", sizeof(gRCT2AddressTracksPath)); - strcpy(gRCT2AddressSavedGamesPath2, gRCT2AddressSavedGamesPath); + safe_strcpy(gRCT2AddressSavedGamesPath2, gRCT2AddressSavedGamesPath, sizeof(gRCT2AddressSavedGamesPath2)); return 1; } -void substitute_path(char *dest, const char *path, const char *filename) +void substitute_path(char *dest, size_t size, const char *path, const char *filename) { - while (*path != '*') { + size_t written = 0; + while (*path != '*' && *path != '\0' && written < size) { *dest++ = *path++; + ++written; } - strcpy(dest, filename); + safe_strcpy(dest, filename, size - written); } /** @@ -331,7 +327,7 @@ static void rct2_draw_fps(rct_drawpixelinfo *dpi) ch = utf8_write_codepoint(ch, FORMAT_OUTLINE); ch = utf8_write_codepoint(ch, FORMAT_WHITE); - sprintf(ch, "%d", _currentFPS); + snprintf(ch, 64 - (ch - buffer), "%d", _currentFPS); // Draw Text int stringWidth = gfx_get_string_width(buffer); @@ -351,7 +347,7 @@ bool rct2_open_file(const char *path) extension++; if (_stricmp(extension, "sv6") == 0) { - strcpy((char*)gRCT2AddressSavedGamesPath2, path); + safe_strcpy((char*)gRCT2AddressSavedGamesPath2, path, sizeof(gRCT2AddressSavedGamesPath2)); if (game_load_save(path)) { gFirstTimeSave = 0; return true; @@ -359,7 +355,7 @@ bool rct2_open_file(const char *path) } else if (_stricmp(extension, "sc6") == 0) { // TODO scenario install rct_scenario_basic scenarioBasic; - strcpy(scenarioBasic.path, path); + safe_strcpy(scenarioBasic.path, path, sizeof(scenarioBasic.path)); if (scenario_load_and_play_from_path(scenarioBasic.path)) { return true; } @@ -471,7 +467,7 @@ void rct2_update() const utf8 *get_file_path(int pathId) { static utf8 path[MAX_PATH]; - strcpy(path, gRCT2AddressAppPath); + safe_strcpy(path, gRCT2AddressAppPath, sizeof(path)); safe_strcat_path(path, RCT2FilePaths[pathId], sizeof(path)); return path; } diff --git a/src/rct2.h b/src/rct2.h index 6ba631454a..f9597746ba 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -292,7 +292,7 @@ int rct2_init_directories(); int rct2_startup_checks(); void rct2_dispose(); void rct2_update(); -void substitute_path(char *dest, const char *path, const char *filename); +void substitute_path(char *dest, size_t size, const char *path, const char *filename); int check_mutex(); int check_file_paths(); int check_file_path(int pathId); diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index fbea148c86..fe4fb0438d 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -38,6 +38,7 @@ extern "C" #include "../ride/ride_ratings.h" #include "../scenario.h" #include "../util/sawyercoding.h" + #include "../util/util.h" #include "../world/climate.h" #include "../world/map_animation.h" #include "../world/park.h" @@ -381,7 +382,7 @@ void S6Exporter::Export() memcpy(_s6.park_entrance_y, gParkEntranceY, sizeof(_s6.park_entrance_y)); memcpy(_s6.park_entrance_z, gParkEntranceZ, sizeof(_s6.park_entrance_z)); memcpy(_s6.park_entrance_direction, gParkEntranceDirection, sizeof(_s6.park_entrance_direction)); - strncpy(_s6.scenario_filename, _scenarioFileName, sizeof(_s6.scenario_filename) - 1); + safe_strcpy(_s6.scenario_filename, _scenarioFileName, sizeof(_s6.scenario_filename)); memcpy(_s6.saved_expansion_pack_names, gScenarioExpansionPacks, sizeof(_s6.saved_expansion_pack_names)); memcpy(_s6.banners, gBanners, sizeof(_s6.banners)); memcpy(_s6.custom_strings, gUserStrings, sizeof(_s6.custom_strings)); diff --git a/src/ride/ride.c b/src/ride/ride.c index b55ece56d2..fe7b2ad09f 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -263,7 +263,7 @@ rct_ride_entry *get_ride_entry_by_ride(rct_ride *ride) if (type == NULL) { char oldname[128]; - format_string(oldname, ride->name, &ride->name_arguments); + format_string(oldname, 128, ride->name, &ride->name_arguments); log_error("Invalid ride subtype for ride %s", oldname); } return type; @@ -5607,7 +5607,7 @@ void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi *ebx = MONEY32_UNDEFINED; return; } - format_string(oldName, ride->name, &ride->name_arguments); + format_string(oldName, 128, ride->name, &ride->name_arguments); if (strcmp(oldName, newName) == 0) { *ebx = 0; return; @@ -5811,7 +5811,7 @@ static bool ride_name_exists(char *name) int i; FOR_ALL_RIDES(i, ride) { - format_string(buffer, ride->name, &ride->name_arguments); + format_string(buffer, 256, ride->name, &ride->name_arguments); if (strcmp(buffer, name) == 0) { return true; } @@ -6015,7 +6015,7 @@ foundRideEntry: name_args.number = 0; do { name_args.number++; - format_string(rideNameBuffer, 1, &name_args); + format_string(rideNameBuffer, 256, 1, &name_args); } while (ride_name_exists(rideNameBuffer)); ride->name = 1; ride->name_arguments_type_name = name_args.type_name; @@ -6031,7 +6031,7 @@ foundRideEntry: rct_string_id rideNameStringId = 0; for (int i = 0; i < 100; i++) { ride->name_arguments_number++; - format_string(rideNameBuffer, ride->name, &ride->name_arguments); + format_string(rideNameBuffer, 256, ride->name, &ride->name_arguments); rideNameStringId = user_string_allocate(4, rideNameBuffer); if (rideNameStringId != 0) { @@ -8589,7 +8589,7 @@ void ride_reset_all_names() name_args.number = 0; do { name_args.number++; - format_string(rideNameBuffer, 1, &name_args); + format_string(rideNameBuffer, 256, 1, &name_args); } while (ride_name_exists(rideNameBuffer)); ride->name = 1; diff --git a/src/ride/track_design_index.c b/src/ride/track_design_index.c index 6d06a96092..15653345f1 100644 --- a/src/ride/track_design_index.c +++ b/src/ride/track_design_index.c @@ -180,15 +180,15 @@ bool track_design_index_rename(const utf8 *path, const utf8 *newName) } utf8 newPath[MAX_PATH]; - const char *lastPathSep = strrchr(path, platform_get_path_separator()); + const char *lastPathSep = strrchr(path, *PATH_SEPARATOR); if (lastPathSep == NULL) { gGameCommandErrorText = STR_CANT_RENAME_TRACK_DESIGN; return false; } size_t directoryLength = (size_t)(lastPathSep - path + 1); memcpy(newPath, path, directoryLength); - strcpy(newPath + directoryLength, newName); - strcat(newPath, ".td6"); + safe_strcpy(newPath + directoryLength, newName, sizeof(newPath) - directoryLength); + path_append_extension(newPath, ".td6", sizeof(newPath)); if (!platform_file_move(path, newPath)) { gGameCommandErrorText = STR_ANOTHER_FILE_EXISTS_WITH_NAME_OR_FILE_IS_WRITE_PROTECTED; @@ -271,7 +271,7 @@ static void track_design_index_scan() track_design_index_include(directory); // Get track directory from user directory - platform_get_user_directory(directory, "track"); + platform_get_user_directory(directory, "track", sizeof(directory)); track_design_index_include(directory); // Sort items by ride type then by filename @@ -360,6 +360,6 @@ static void track_design_index_dispose() static void track_design_index_get_path(utf8 * buffer, size_t bufferLength) { - platform_get_user_directory(buffer, NULL); - safe_strcat(buffer, "tracks.idx", bufferLength); + platform_get_user_directory(buffer, NULL, bufferLength); + safe_strcat_path(buffer, "tracks.idx", bufferLength); } diff --git a/src/ride/track_design_save.c b/src/ride/track_design_save.c index 0109d84590..41336526de 100644 --- a/src/ride/track_design_save.c +++ b/src/ride/track_design_save.c @@ -172,7 +172,7 @@ bool track_design_save(uint8 rideIndex) } utf8 track_name[MAX_PATH]; - format_string(track_name, ride->name, &ride->name_arguments); + format_string(track_name, MAX_PATH, ride->name, &ride->name_arguments); window_loadsave_open(LOADSAVETYPE_TRACK | LOADSAVETYPE_SAVE, track_name); gLoadSaveCallback = track_design_save_callback; diff --git a/src/scenario.c b/src/scenario.c index 7600908d48..7e50a5c9b9 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -237,15 +237,15 @@ void scenario_begin() char *buffer = gCommonStringFormatBuffer; // Set localised park name - format_string(buffer, stex->park_name, 0); + format_string(buffer, 256, stex->park_name, 0); park_set_name(buffer); // Set localised scenario name - format_string(buffer, stex->scenario_name, 0); + format_string(buffer, 256, stex->scenario_name, 0); safe_strcpy(gScenarioName, buffer, 64); // Set localised scenario details - format_string(buffer, stex->details, 0); + format_string(buffer, 256, stex->details, 0); safe_strcpy(gScenarioDetails, buffer, 256); } } @@ -253,15 +253,15 @@ void scenario_begin() // Set the last saved game path char parkName[128]; - format_string(parkName, gParkName, &gParkNameArgs); + format_string(parkName, 128, gParkName, &gParkNameArgs); - platform_get_user_directory(gScenarioSavePath, "save"); - strncat(gScenarioSavePath, parkName, sizeof(gScenarioSavePath) - strlen(gScenarioSavePath) - 1); - strncat(gScenarioSavePath, ".sv6", sizeof(gScenarioSavePath) - strlen(gScenarioSavePath) - 1); + platform_get_user_directory(gScenarioSavePath, "save", sizeof(gScenarioSavePath)); + safe_strcat_path(gScenarioSavePath, parkName, sizeof(gScenarioSavePath)); + path_append_extension(gScenarioSavePath, ".sv6", sizeof(gScenarioSavePath)); - strcpy(gRCT2AddressSavedGamesPath2, gRCT2AddressSavedGamesPath); - strcpy(gRCT2AddressSavedGamesPath2 + strlen(gRCT2AddressSavedGamesPath2), gScenarioSavePath); - strcat(gRCT2AddressSavedGamesPath2, ".SV6"); + safe_strcpy(gRCT2AddressSavedGamesPath2, gRCT2AddressSavedGamesPath, MAX_PATH); + safe_strcat_path(gRCT2AddressSavedGamesPath2, gScenarioSavePath, MAX_PATH); + path_append_extension(gRCT2AddressSavedGamesPath2, ".SV6", MAX_PATH); gCurrentExpenditure = 0; gCurrentProfit = 0; @@ -270,7 +270,7 @@ void scenario_begin() gScenarioCompletedCompanyValue = MONEY32_UNDEFINED; gTotalAdmissions = 0; gTotalIncomeFromAdmissions = 0; - strcpy(gScenarioCompletedBy, "?"); + safe_strcpy(gScenarioCompletedBy, "?", sizeof(gScenarioCompletedBy)); park_reset_history(); finance_reset_history(); award_reset(); @@ -312,7 +312,7 @@ static void scenario_end() void scenario_set_filename(const char *value) { - substitute_path(_scenarioPath, gRCT2AddressScenariosPath, value); + substitute_path(_scenarioPath, sizeof(_scenarioPath), gRCT2AddressScenariosPath, value); _scenarioFileName = path_get_filename(_scenarioPath); } @@ -679,14 +679,14 @@ int scenario_prepare_for_save() rct_stex_entry* stex = g_stexEntries[0]; if ((intptr_t)stex != -1) { char buffer[256]; - format_string(buffer, stex->scenario_name, NULL); + format_string(buffer, 256, stex->scenario_name, NULL); safe_strcpy(gS6Info.name, buffer, sizeof(gS6Info.name)); memcpy(&gS6Info.entry, &object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0], sizeof(rct_object_entry)); } if (gS6Info.name[0] == 0) - format_string(gS6Info.name, gParkName, &gParkNameArgs); + format_string(gS6Info.name, 64, gParkName, &gParkNameArgs); gS6Info.objective_type = gScenarioObjectiveType; gS6Info.objective_arg_1 = gScenarioObjectiveYear; diff --git a/src/scenario_list.c b/src/scenario_list.c index 686c82539c..bcbd8d20c3 100644 --- a/src/scenario_list.c +++ b/src/scenario_list.c @@ -38,7 +38,7 @@ static int scenario_list_sort_by_category(const void *a, const void *b); static int scenario_list_sort_by_index(const void *a, const void *b); static bool scenario_scores_load(); -static void scenario_scores_legacy_get_path(utf8 *outPath); +static void scenario_scores_legacy_get_path(utf8 *outPath, size_t size); static bool scenario_scores_legacy_load(const utf8 *path); static void scenario_highscore_remove(scenario_highscore_entry *higscore); static void scenario_highscore_list_dispose(); @@ -61,14 +61,14 @@ void scenario_load_list() scenario_list_include(directory); // Get scenario directory from user directory - platform_get_user_directory(directory, "scenario"); + platform_get_user_directory(directory, "scenario", sizeof(directory)); scenario_list_include(directory); scenario_list_sort(); scenario_scores_load(); utf8 scoresPath[MAX_PATH]; - scenario_scores_legacy_get_path(scoresPath); + scenario_scores_legacy_get_path(scoresPath, sizeof(scoresPath)); scenario_scores_legacy_load(scoresPath); scenario_scores_legacy_load(get_file_path(PATH_ID_SCORES)); } @@ -289,19 +289,19 @@ scenario_index_entry *scenario_list_find_by_path(const utf8 *path) /** * Gets the path for the scenario scores path. */ -static void scenario_scores_get_path(utf8 *outPath) +static void scenario_scores_get_path(utf8 *outPath, size_t size) { - platform_get_user_directory(outPath, NULL); - strcat(outPath, "highscores.dat"); + platform_get_user_directory(outPath, NULL, size); + safe_strcat_path(outPath, "highscores.dat", size); } /** * Gets the path for the scenario scores path. */ -static void scenario_scores_legacy_get_path(utf8 *outPath) +static void scenario_scores_legacy_get_path(utf8 *outPath, size_t size) { - platform_get_user_directory(outPath, NULL); - strcat(outPath, "scores.dat"); + platform_get_user_directory(outPath, NULL, size); + safe_strcat_path(outPath, "scores.dat", size); } /** @@ -380,7 +380,7 @@ static bool scenario_scores_legacy_load(const utf8 *path) static bool scenario_scores_load() { utf8 scoresPath[MAX_PATH]; - scenario_scores_get_path(scoresPath); + scenario_scores_get_path(scoresPath, sizeof(scoresPath)); // Load scores file SDL_RWops *file = SDL_RWFromFile(scoresPath, "rb"); @@ -431,7 +431,7 @@ static bool scenario_scores_load() bool scenario_scores_save() { utf8 scoresPath[MAX_PATH]; - scenario_scores_get_path(scoresPath); + scenario_scores_get_path(scoresPath, sizeof(scoresPath)); SDL_RWops *file = SDL_RWFromFile(scoresPath, "wb"); if (file == NULL) { diff --git a/src/title.c b/src/title.c index db5244ff1a..8cb0af6b9d 100644 --- a/src/title.c +++ b/src/title.c @@ -366,7 +366,6 @@ static void title_do_next_script_opcode() case TITLE_SCRIPT_LOAD: { char *ch, filename[32], path[MAX_PATH]; - char separator = platform_get_path_separator(); // Get filename ch = filename; @@ -379,12 +378,11 @@ static void title_do_next_script_opcode() safe_strcpy(path, gConfigTitleSequences.presets[_scriptCurrentPreset].path, MAX_PATH); } else { - platform_get_user_directory(path, "title sequences"); - strcat(path, gConfigTitleSequences.presets[_scriptCurrentPreset].name); - strncat(path, &separator, 1); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[_scriptCurrentPreset].name, sizeof(path)); } - strcat(path, filename); + safe_strcat_path(path, filename, sizeof(path)); if (title_load_park(path)) { _scriptNoLoadsSinceRestart = 0; gTitleScriptSave = gConfigTitleSequences.presets[gCurrentPreviewTitleSequence].commands[gTitleScriptCommand].saveIndex; @@ -504,7 +502,7 @@ void DrawOpenRCT2(rct_drawpixelinfo *dpi, int x, int y) gfx_draw_string(dpi, buffer, 0, x + 5, y + 5 - 13); // Write platform information - sprintf(ch, "%s (%s)", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); + snprintf(ch, 256 - (ch - buffer), "%s (%s)", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); gfx_draw_string(dpi, buffer, 0, x + 5, y + 5); } @@ -624,11 +622,10 @@ static uint8 *title_script_load() char parts[3 * 128], *token, *part1, *part2, *src; utf8 path[MAX_PATH]; - utf8 dataPath[MAX_PATH]; - utf8 filePath[] = "title/script.txt"; - platform_get_openrct_data_path(dataPath); - sprintf(path, "%s%c%s", dataPath, platform_get_path_separator(), filePath); + platform_get_openrct_data_path(path, sizeof(path)); + safe_strcat_path(path, "title", MAX_PATH); + safe_strcat_path(path, "script.txt", MAX_PATH); log_verbose("loading title script, %s", path); file = SDL_RWFromFile(path, "r"); if (file == NULL) { diff --git a/src/util/util.c b/src/util/util.c index 437176760e..2afe119704 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -65,7 +65,7 @@ bool filename_valid_characters(const utf8 *filename) utf8 *path_get_directory(const utf8 *path) { // Find the last slash or backslash in the path - char *filename = strrchr(path, platform_get_path_separator()); + char *filename = strrchr(path, *PATH_SEPARATOR); // If the path is invalid (e.g. just a file name), return NULL if (filename == NULL) @@ -80,7 +80,7 @@ utf8 *path_get_directory(const utf8 *path) const char *path_get_filename(const utf8 *path) { // Find last slash or backslash in the path - char *filename = strrchr(path, platform_get_path_separator()); + char *filename = strrchr(path, *PATH_SEPARATOR); // Checks if the path is valid (e.g. not just a file name) if (filename == NULL) @@ -112,24 +112,23 @@ const char *path_get_extension(const utf8 *path) return extension; } -void path_set_extension(utf8 *path, const utf8 *newExtension) +void path_set_extension(utf8 *path, const utf8 *newExtension, size_t size) { // Remove existing extension (check first if there is one) if (path_get_extension(path) < strrchr(path, '\0')) path_remove_extension(path); // Append new extension - path_append_extension(path, newExtension); + path_append_extension(path, newExtension, size); } -void path_append_extension(utf8 *path, const utf8 *newExtension) +void path_append_extension(utf8 *path, const utf8 *newExtension, size_t size) { // Append a dot to the filename if the new extension doesn't start with it - char *endOfString = strrchr(path, '\0'); if (newExtension[0] != '.') - *endOfString++ = '.'; + safe_strcat(path, ".", size); // Append the extension to the path - safe_strcpy(endOfString, newExtension, MAX_PATH - (endOfString - path) - 1); + safe_strcat(path, newExtension, size); } void path_remove_extension(utf8 *path) @@ -142,6 +141,14 @@ void path_remove_extension(utf8 *path) log_warning("No extension found. (path = %s)", path); } +void path_end_with_separator(utf8 *path, size_t size) { + size_t length = strnlen(path, size); + if (length >= size - 1) return; + + if (path[length - 1] != *PATH_SEPARATOR) + safe_strcat(path, PATH_SEPARATOR, size); +} + bool readentirefile(const utf8 *path, void **outBuffer, size_t *outLength) { SDL_RWops *fp; @@ -338,18 +345,7 @@ char *safe_strcat(char *destination, const char *source, size_t size) char *safe_strcat_path(char *destination, const char *source, size_t size) { - const char pathSeparator = platform_get_path_separator(); - - size_t length = strnlen(destination, size); - if (length >= size - 1) { - return destination; - } - - if (destination[length - 1] != pathSeparator) { - destination[length] = pathSeparator; - destination[length + 1] = '\0'; - } - + path_end_with_separator(destination, size); return safe_strcat(destination, source, size); } diff --git a/src/util/util.h b/src/util/util.h index ee26b9c6e2..261596ba3f 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -31,9 +31,10 @@ bool filename_valid_characters(const utf8 *filename); char *path_get_directory(const utf8 *path); const char *path_get_filename(const utf8 *path); const char *path_get_extension(const utf8 *path); -void path_set_extension(utf8 *path, const utf8 *newExtension); -void path_append_extension(utf8 *path, const utf8 *newExtension); +void path_set_extension(utf8 *path, const utf8 *newExtension, size_t size); +void path_append_extension(utf8 *path, const utf8 *newExtension, size_t size); void path_remove_extension(utf8 *path); +void path_end_with_separator(utf8 *path, size_t size); bool readentirefile(const utf8 *path, void **outBuffer, size_t *outLength); int bitscanforward(int source); diff --git a/src/windows/changelog.c b/src/windows/changelog.c index a73863847a..7d392f3e22 100644 --- a/src/windows/changelog.c +++ b/src/windows/changelog.c @@ -205,7 +205,8 @@ static bool window_changelog_read_file() { window_changelog_dispose_file(); utf8 path[MAX_PATH]; - sprintf(path, "%s%cchangelog.txt", gExePath, platform_get_path_separator()); + safe_strcpy(path, gExePath, MAX_PATH); + safe_strcat_path(path, "changelog.txt", MAX_PATH); if (!readentirefile(path, (void**)&_changelogText, &_changelogTextSize)) { log_error("Unable to read changelog.txt"); return false; diff --git a/src/windows/custom_currency.c b/src/windows/custom_currency.c index cdafbd4587..5f1ee92e0d 100644 --- a/src/windows/custom_currency.c +++ b/src/windows/custom_currency.c @@ -22,6 +22,7 @@ #include "../localisation/localisation.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../util/util.h" #include "dropdown.h" enum WINDOW_CUSTOM_CURRENCY_WIDGET_IDX { @@ -238,13 +239,13 @@ static void custom_currency_window_text_input(struct rct_window *w, int widgetIn char* end; switch(widgetIndex){ case WIDX_SYMBOL_TEXT: - strncpy( + safe_strcpy( CurrencyDescriptors[CURRENCY_CUSTOM].symbol_unicode, text, CURRENCY_SYMBOL_MAX_SIZE ); - strncpy( + safe_strcpy( gConfigGeneral.custom_currency_symbol, CurrencyDescriptors[CURRENCY_CUSTOM].symbol_unicode, CURRENCY_SYMBOL_MAX_SIZE diff --git a/src/windows/dropdown.c b/src/windows/dropdown.c index 9f378d3bd6..a0141f7be0 100644 --- a/src/windows/dropdown.c +++ b/src/windows/dropdown.c @@ -133,7 +133,7 @@ void window_dropdown_show_text(int x, int y, int extray, uint8 colour, uint8 fla // Calculate the longest string width max_string_width = 0; for (i = 0; i < num_items; i++) { - format_string(buffer, gDropdownItemsFormat[i], (void*)(&gDropdownItemsArgs[i])); + format_string(buffer, 256, gDropdownItemsFormat[i], (void*)(&gDropdownItemsArgs[i])); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; string_width = gfx_get_string_width(buffer); max_string_width = max(string_width, max_string_width); diff --git a/src/windows/editor_inventions_list.c b/src/windows/editor_inventions_list.c index e46cd467f9..87fb936c19 100644 --- a/src/windows/editor_inventions_list.c +++ b/src/windows/editor_inventions_list.c @@ -895,7 +895,7 @@ static void window_editor_inventions_list_scrollpaint(rct_window *w, rct_drawpix ptr = utf8_write_codepoint(ptr, colour & 0xFF); } - format_string(ptr, stringId, NULL); + format_string(ptr, 256, stringId, NULL); if (disableItemMovement) { gCurrentFontSpriteBase = -1; @@ -931,7 +931,7 @@ static void window_editor_inventions_list_drag_open(rct_research_item *researchI _editorInventionsListDraggedItem = researchItem; stringId = research_item_get_name(researchItem->entryIndex & 0xFFFFFF); - format_string(buffer, stringId, NULL); + format_string(buffer, 256, stringId, NULL); stringWidth = gfx_get_string_width(buffer); window_editor_inventions_list_drag_widgets[0].right = stringWidth; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 61aaaa0a04..f53375f88b 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1446,13 +1446,13 @@ static void window_editor_object_selection_scrollpaint(rct_window *w, rct_drawpi if (ridePage) { // Draw ride type rct_string_id rideTypeStringId = get_ride_type_string_id(listItem->repositoryItem); - strcpy(buffer, language_get_string(rideTypeStringId)); + safe_strcpy(buffer, language_get_string(rideTypeStringId), 256 - (buffer - bufferWithColour)); gfx_draw_string(dpi, bufferWithColour, colour, x, y); x = w->widgets[WIDX_LIST_SORT_RIDE].left - w->widgets[WIDX_LIST].left; } // Draw text - strcpy(buffer, listItem->repositoryItem->Name); + safe_strcpy(buffer, listItem->repositoryItem->Name, 256 - (buffer - bufferWithColour)); if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) { while (*buffer != 0 && *buffer != 9) buffer++; @@ -1629,7 +1629,7 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, con if (bh != 0 && !(flags & (1 << 1))) { char objectName[64]; - object_create_identifier_name(objectName, &item->ObjectEntry); + object_create_identifier_name(objectName, 64, &item->ObjectEntry); set_format_arg(0, const char *, objectName); set_object_selection_error(bh, STR_OBJECT_SELECTION_ERR_SHOULD_SELECT_X_FIRST); return 0; diff --git a/src/windows/editor_objective_options.c b/src/windows/editor_objective_options.c index b32555ec79..3a2a393ff9 100644 --- a/src/windows/editor_objective_options.c +++ b/src/windows/editor_objective_options.c @@ -794,10 +794,10 @@ static void window_editor_objective_options_main_textinput(rct_window *w, int wi park_set_name(text); if (gS6Info.name[0] == 0) - format_string(gS6Info.name, gParkName, &gParkNameArgs); + format_string(gS6Info.name, 64, gParkName, &gParkNameArgs); break; case WIDX_SCENARIO_NAME: - strncpy(gS6Info.name, text, 64); + safe_strcpy(gS6Info.name, text, 64); if (strnlen(gS6Info.name, 64) == 64) { gS6Info.name[64 - 1] = '\0'; @@ -806,7 +806,7 @@ static void window_editor_objective_options_main_textinput(rct_window *w, int wi window_invalidate(w); break; case WIDX_DETAILS: - strncpy(gS6Info.details, text, 256); + safe_strcpy(gS6Info.details, text, 256); if (strnlen(gS6Info.details, 256) == 256) { gS6Info.details[256 - 1] = '\0'; diff --git a/src/windows/error.c b/src/windows/error.c index f16ec070b6..64110972e0 100644 --- a/src/windows/error.c +++ b/src/windows/error.c @@ -87,14 +87,14 @@ void window_error_open(rct_string_id title, rct_string_id message) // Format the title dst = utf8_write_codepoint(dst, FORMAT_BLACK); if (title != STR_NONE) { - format_string(dst, title, gCommonFormatArgs); + format_string(dst, 512 - (dst - _window_error_text), title, gCommonFormatArgs); dst = get_string_end(dst); } // Format the message if (message != STR_NONE) { dst = utf8_write_codepoint(dst, FORMAT_NEWLINE); - format_string(dst, message, gCommonFormatArgs); + format_string(dst, 512 - (dst - _window_error_text), message, gCommonFormatArgs); dst = get_string_end(dst); } diff --git a/src/windows/install_track.c b/src/windows/install_track.c index 53d4db593e..6a4c86c216 100644 --- a/src/windows/install_track.c +++ b/src/windows/install_track.c @@ -378,15 +378,15 @@ static void window_install_track_design(rct_window *w) { utf8 destPath[MAX_PATH]; - platform_get_user_directory(destPath, "track"); + platform_get_user_directory(destPath, "track", sizeof(destPath)); if (!platform_ensure_directory_exists(destPath)) { log_error("Unable to create directory '%s'", destPath); window_error_open(STR_CANT_SAVE_TRACK_DESIGN, STR_NONE); return; } - strcat(destPath, _trackName); - strcat(destPath, ".td6"); + safe_strcat_path(destPath, _trackName, sizeof(destPath)); + path_append_extension(destPath, ".td6", sizeof(destPath)); if (platform_file_exists(destPath)) { log_info("%s already exists, prompting user for a different track design name", destPath); diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 5c2c371c91..85c584862e 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -139,12 +139,12 @@ static void window_loadsave_sort_list(int index, int endIndex); static rct_window *window_overwrite_prompt_open(const char *name, const char *path); -static int window_loadsave_get_dir(utf8 *last_save, char *path, const char *subdir) +static int window_loadsave_get_dir(utf8 *last_save, char *path, const char *subdir, size_t pathSize) { if (last_save && platform_ensure_directory_exists(last_save)) - safe_strcpy(path, last_save, MAX_PATH); + safe_strcpy(path, last_save, pathSize); else - platform_get_user_directory(path, subdir); + platform_get_user_directory(path, subdir, pathSize); if (!platform_ensure_directory_exists(path)) { log_error("Unable to create save directory."); @@ -183,28 +183,28 @@ rct_window *window_loadsave_open(int type, char *defaultName) switch (type & 0x0E) { case LOADSAVETYPE_GAME: w->widgets[WIDX_TITLE].text = isSave ? STR_FILE_DIALOG_TITLE_SAVE_GAME : STR_FILE_DIALOG_TITLE_LOAD_GAME; - if (window_loadsave_get_dir(gConfigGeneral.last_save_game_directory, path, "save")) { + if (window_loadsave_get_dir(gConfigGeneral.last_save_game_directory, path, "save", sizeof(path))) { window_loadsave_populate_list(w, isSave, path, ".sv6"); success = true; } break; case LOADSAVETYPE_LANDSCAPE: w->widgets[WIDX_TITLE].text = isSave ? STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE : STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE; - if (window_loadsave_get_dir(gConfigGeneral.last_save_landscape_directory, path, "landscape")) { + if (window_loadsave_get_dir(gConfigGeneral.last_save_landscape_directory, path, "landscape", sizeof(path))) { window_loadsave_populate_list(w, isSave, path, ".sc6"); success = true; } break; case LOADSAVETYPE_SCENARIO: w->widgets[WIDX_TITLE].text = STR_FILE_DIALOG_TITLE_SAVE_SCENARIO; - if (window_loadsave_get_dir(gConfigGeneral.last_save_scenario_directory, path, "scenario")) { + if (window_loadsave_get_dir(gConfigGeneral.last_save_scenario_directory, path, "scenario", sizeof(path))) { window_loadsave_populate_list(w, isSave, path, ".sc6"); success = true; } break; case LOADSAVETYPE_TRACK: w->widgets[WIDX_TITLE].text = isSave ? STR_FILE_DIALOG_TITLE_SAVE_TRACK : STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN; - if (window_loadsave_get_dir(gConfigGeneral.last_save_track_directory, path, "track")) { + if (window_loadsave_get_dir(gConfigGeneral.last_save_track_directory, path, "track", sizeof(path))) { window_loadsave_populate_list(w, isSave, path, ".td?"); success = true; } @@ -233,11 +233,11 @@ static void window_loadsave_close(rct_window *w) window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT); } -static bool browse(bool isSave, char *path) +static bool browse(bool isSave, char *path, size_t pathSize) { - safe_strcpy(path, _directory, MAX_PATH); + safe_strcpy(path, _directory, pathSize); if (isSave) - strcat(path, _defaultName); + safe_strcat_path(path, _defaultName, pathSize); file_dialog_desc desc = { 0 }; desc.initial_directory = _directory; @@ -269,7 +269,7 @@ static bool browse(bool isSave, char *path) } desc.title = language_get_string(title); - return platform_open_common_file_dialog(path, &desc); + return platform_open_common_file_dialog(path, &desc, pathSize); } static void window_loadsave_mouseup(rct_window *w, int widgetIndex) @@ -291,7 +291,7 @@ static void window_loadsave_mouseup(rct_window *w, int widgetIndex) window_text_input_open(w, WIDX_NEW, STR_NONE, STR_FILEBROWSER_NAME_PROMPT, STR_STRING, (uintptr_t)&_defaultName, 64); break; case WIDX_BROWSE: - if (browse(isSave, path)) + if (browse(isSave, path, sizeof(path))) window_loadsave_select(w, path); break; case WIDX_SORT_NAME: @@ -317,16 +317,16 @@ static void window_loadsave_mouseup(rct_window *w, int widgetIndex) case WIDX_DEFAULT: switch (_type & 0x0E) { case LOADSAVETYPE_GAME: - platform_get_user_directory(path, "save"); + platform_get_user_directory(path, "save", sizeof(path)); break; case LOADSAVETYPE_LANDSCAPE: - platform_get_user_directory(path, "landscape"); + platform_get_user_directory(path, "landscape", sizeof(path)); break; case LOADSAVETYPE_SCENARIO: - platform_get_user_directory(path, "scenario"); + platform_get_user_directory(path, "scenario", sizeof(path)); break; case LOADSAVETYPE_TRACK: - platform_get_user_directory(path, "track"); + platform_get_user_directory(path, "track", sizeof(path)); break; } @@ -411,8 +411,8 @@ static void window_loadsave_textinput(rct_window *w, int widgetIndex, char *text } safe_strcpy(path, _directory, sizeof(path)); - strncat(path, text, sizeof(path) - strnlen(path, MAX_PATH) - 1); - strncat(path, _extension, sizeof(path) - strnlen(path, MAX_PATH) - 1); + safe_strcat_path(path, text, sizeof(path)); + path_append_extension(path, _extension, sizeof(path)); overwrite = 0; for (i = 0; i < _listItemsCount; i++) { @@ -563,7 +563,7 @@ static void window_loadsave_populate_list(rct_window *w, int includeNewItem, con // If the drive exists, list it loadsave_list_item *listItem = &_listItems[_listItemsCount]; - sprintf(listItem->path, "%c:%c", 'A' + x, platform_get_path_separator()); + snprintf(listItem->path, sizeof(listItem->path), "%c:" PATH_SEPARATOR, 'A' + x); safe_strcpy(listItem->name, listItem->path, sizeof(listItem->name)); listItem->type = TYPE_DIRECTORY; @@ -572,15 +572,14 @@ static void window_loadsave_populate_list(rct_window *w, int includeNewItem, con } } else { - char separator = platform_get_path_separator(); // Remove the separator at the end of the path, if present safe_strcpy(_parentDirectory, directory, sizeof(_parentDirectory)); - if (_parentDirectory[strlen(_parentDirectory) - 1] == separator) + if (_parentDirectory[strlen(_parentDirectory) - 1] == *PATH_SEPARATOR) _parentDirectory[strlen(_parentDirectory) - 1] = '\0'; // Remove everything past the now last separator - char *ch = strrchr(_parentDirectory, separator); + char *ch = strrchr(_parentDirectory, *PATH_SEPARATOR); if (ch != NULL) { *(ch + 1) = '\0'; } else if (drives) { @@ -588,7 +587,7 @@ static void window_loadsave_populate_list(rct_window *w, int includeNewItem, con _parentDirectory[0] = '\0'; } else { // Else, go to the root directory - sprintf(_parentDirectory, "%c", separator); + snprintf(_parentDirectory, MAX_PATH, "%c", *PATH_SEPARATOR); } // Disable the Up button if the current directory is the root directory @@ -623,7 +622,7 @@ static void window_loadsave_populate_list(rct_window *w, int includeNewItem, con char filter[MAX_PATH]; safe_strcpy(filter, directory, sizeof(filter)); safe_strcat_path(filter, "*", sizeof(filter)); - safe_strcat(filter, extension, sizeof(filter)); + path_append_extension(filter, extension, sizeof(filter)); file_info fileInfo; fileEnumHandle = platform_enumerate_files_begin(filter); @@ -675,10 +674,10 @@ static void window_loadsave_select(rct_window *w, const char *path) save_path(&gConfigGeneral.last_save_game_directory, path); if (gLoadSaveTitleSequenceSave) { utf8 newName[MAX_PATH]; - char *extension = (char*)path_get_extension(path); + const char *extension = path_get_extension(path); safe_strcpy(newName, path_get_filename(path), MAX_PATH); if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) - strcat(newName, ".sv6"); + path_append_extension(newName, ".sv6", sizeof(newName)); if (title_sequence_save_exists(gCurrentTitleSequence, newName)) { set_format_arg(0, intptr_t, (intptr_t)&_listItems[w->selected_list_item].name); window_text_input_open(w, WIDX_SCROLL, STR_FILEBROWSER_RENAME_SAVE_TITLE, STR_ERROR_EXISTING_NAME, STR_STRING, (uintptr_t)_listItems[w->selected_list_item].name, TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1); @@ -789,10 +788,10 @@ static void window_loadsave_select(rct_window *w, const char *path) break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_TRACK) : { - char *p = _strdup(path); - path_set_extension(p, "td6"); + char p[MAX_PATH]; + safe_strcpy(p, path, sizeof(p)); + path_set_extension(p, "td6", sizeof(p)); int success = track_design_save_to_file(p); - free(p); if (success) { window_close_by_class(WC_LOADSAVE); @@ -913,16 +912,13 @@ static void window_overwrite_prompt_invalidate(rct_window *w) static void window_overwrite_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi) { window_draw_widgets(w, dpi); - - rct_string_id templateStringId = STR_PLACEHOLDER; - char *templateString; - - templateString = (char*)language_get_string(templateStringId); - strcpy(templateString, _window_overwrite_prompt_name); + + set_format_arg(0, rct_string_id, STR_STRING); + set_format_arg(2, char *, _window_overwrite_prompt_name); int x = w->x + w->width / 2; int y = w->y + (w->height / 2) - 3; - gfx_draw_string_centred_wrapped(dpi, &templateStringId, x, y, w->width - 4, STR_FILEBROWSER_OVERWRITE_PROMPT, 0); + gfx_draw_string_centred_wrapped(dpi, gCommonFormatArgs, x, y, w->width - 4, STR_FILEBROWSER_OVERWRITE_PROMPT, 0); } diff --git a/src/windows/multiplayer.c b/src/windows/multiplayer.c index dab4f6f82a..c776ceaa88 100644 --- a/src/windows/multiplayer.c +++ b/src/windows/multiplayer.c @@ -610,7 +610,7 @@ static void window_multiplayer_players_scrollpaint(rct_window *w, rct_drawpixeli int colour = 0; if (i == w->selected_list_item) { gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x02000031); - safe_strcpy(&buffer[0], network_get_player_name(i), sizeof(buffer)); + safe_strcpy(buffer, network_get_player_name(i), sizeof(buffer)); colour = w->colours[2]; } else { if (network_get_player_flags(i) & NETWORK_PLAYER_FLAG_ISSERVER) { @@ -652,7 +652,7 @@ static void window_multiplayer_players_scrollpaint(rct_window *w, rct_drawpixeli } else { lineCh = utf8_write_codepoint(lineCh, FORMAT_RED); } - sprintf(lineCh, "%d ms", ping); + snprintf(lineCh, sizeof(buffer) - (lineCh - buffer), "%d ms", ping); gfx_draw_string(dpi, buffer, colour, 356, y - 1); } y += 10; @@ -819,11 +819,11 @@ static void window_multiplayer_groups_paint(rct_window *w, rct_drawpixelinfo *dp rct_widget* widget = &window_multiplayer_groups_widgets[WIDX_DEFAULT_GROUP]; int group = network_get_group_index(network_get_default_group()); if (group != -1) { - char buffer[300] = {0}; + char buffer[300]; char* lineCh; lineCh = buffer; lineCh = utf8_write_codepoint(lineCh, FORMAT_WINDOW_COLOUR_2); - strcpy(lineCh, network_get_group_name(group)); + safe_strcpy(lineCh, network_get_group_name(group), sizeof(buffer) - (lineCh - buffer)); set_format_arg(0, const char *, buffer); gfx_draw_string_centred_clipped( dpi, @@ -848,11 +848,11 @@ static void window_multiplayer_groups_paint(rct_window *w, rct_drawpixelinfo *dp widget = &window_multiplayer_groups_widgets[WIDX_SELECTED_GROUP]; group = network_get_group_index(_selectedGroup); if (group != -1) { - char buffer[300] = {0}; + char buffer[300]; char* lineCh; lineCh = buffer; lineCh = utf8_write_codepoint(lineCh, FORMAT_WINDOW_COLOUR_2); - strcpy(lineCh, network_get_group_name(group)); + safe_strcpy(lineCh, network_get_group_name(group), sizeof(buffer) - (lineCh - buffer)); set_format_arg(0, const char *, buffer); gfx_draw_string_centred_clipped( dpi, diff --git a/src/windows/network_status.c b/src/windows/network_status.c index 92cf59be6b..0432e19574 100644 --- a/src/windows/network_status.c +++ b/src/windows/network_status.c @@ -145,7 +145,7 @@ static void window_network_status_update(rct_window *w) static void window_network_status_textinput(rct_window *w, int widgetIndex, char *text) { - strcpy(_password, ""); + _password[0] = '\0'; switch (widgetIndex) { case WIDX_PASSWORD: if (text != NULL) @@ -177,7 +177,7 @@ static void window_network_status_paint(rct_window *w, rct_drawpixelinfo *dpi) char buffer[sizeof(window_network_status_text) + 10]; char* lineCh = buffer; lineCh = utf8_write_codepoint(lineCh, FORMAT_BLACK); - strcpy(lineCh, window_network_status_text); + safe_strcpy(lineCh, window_network_status_text, sizeof(buffer) - (lineCh - buffer)); gfx_clip_string(buffer, w->widgets[WIDX_BACKGROUND].right - 50); int x = w->x + (w->width / 2); int y = w->y + (w->height / 2); diff --git a/src/windows/new_campaign.c b/src/windows/new_campaign.c index a7d1b6c9a6..69070599e8 100644 --- a/src/windows/new_campaign.c +++ b/src/windows/new_campaign.c @@ -114,8 +114,8 @@ static int ride_name_compare(const void *a, const void *b) rideA = get_ride(*((uint8*)a)); rideB = get_ride(*((uint8*)b)); - format_string(rideAName, rideA->name, &rideA->name_arguments); - format_string(rideBName, rideB->name, &rideB->name_arguments); + format_string(rideAName, 256, rideA->name, &rideA->name_arguments); + format_string(rideBName, 256, rideB->name, &rideB->name_arguments); return _strcmpi(rideAName, rideBName); } diff --git a/src/windows/new_ride.c b/src/windows/new_ride.c index 2968d80316..c8ffa93322 100644 --- a/src/windows/new_ride.c +++ b/src/windows/new_ride.c @@ -33,6 +33,7 @@ #include "../ride/ride_data.h" #include "../sprites.h" #include "../ride/track_data.h" +#include "../util/util.h" static uint8 _windowNewRideCurrentTab; static ride_list_item _windowNewRideHighlightedItem[6]; @@ -311,7 +312,7 @@ static void window_new_ride_populate_list() } char preferredVehicleName[9]; - strcpy(preferredVehicleName," "); + safe_strcpy(preferredVehicleName, " ", sizeof(preferredVehicleName)); if (ride_type_is_invented(rideType)) { int dh = 0; @@ -338,11 +339,11 @@ static void window_new_ride_populate_list() // Skip if the vehicle isn't the preferred vehicle for this generic track type if (gConfigInterface.select_by_track_type && (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry))) { if (strcmp(preferredVehicleName, " \0") == 0) { - strcpy(preferredVehicleName, rideEntryName); + safe_strcpy(preferredVehicleName, rideEntryName, sizeof(preferredVehicleName)); preferredVehicleName[8] = 0; } else { if (vehicle_preference_compare(rideType, preferredVehicleName, rideEntryName) == 1) { - strcpy(preferredVehicleName, rideEntryName); + safe_strcpy(preferredVehicleName, rideEntryName, sizeof(preferredVehicleName)); preferredVehicleName[8] = 0; } else { continue; diff --git a/src/windows/player.c b/src/windows/player.c index 92d06e9dc0..8681b2916d 100644 --- a/src/windows/player.c +++ b/src/windows/player.c @@ -360,11 +360,11 @@ void window_player_overview_paint(rct_window *w, rct_drawpixelinfo *dpi) int groupindex = network_get_group_index(network_get_player_group(player)); if (groupindex != -1) { rct_widget* widget = &window_player_overview_widgets[WIDX_GROUP]; - char buffer[300] = {0}; + char buffer[300]; char* lineCh; lineCh = buffer; lineCh = utf8_write_codepoint(lineCh, FORMAT_WINDOW_COLOUR_2); - strcpy(lineCh, network_get_group_name(groupindex)); + safe_strcpy(lineCh, network_get_group_name(groupindex), sizeof(buffer) - (lineCh - buffer)); set_format_arg(0, const char *, buffer); gfx_draw_string_centred_clipped( @@ -385,7 +385,7 @@ void window_player_overview_paint(rct_window *w, rct_drawpixelinfo *dpi) set_format_arg(0, rct_string_id, STR_PING); gfx_draw_string_left(dpi, STR_WINDOW_COLOUR_2_STRINGID, gCommonFormatArgs, 0, x, y); char ping[64]; - sprintf(ping, "%d ms", network_get_player_ping(player)); + snprintf(ping, 64, "%d ms", network_get_player_ping(player)); gfx_draw_string(dpi, ping, w->colours[2], x + 30, y); // Draw last action diff --git a/src/windows/ride_list.c b/src/windows/ride_list.c index ea5a2c9dc9..20cb30cd6b 100644 --- a/src/windows/ride_list.c +++ b/src/windows/ride_list.c @@ -729,10 +729,10 @@ static void window_ride_list_refresh_list(rct_window *w) int current_list_position = list_index; switch (w->list_information_type) { case INFORMATION_TYPE_STATUS: - format_string_to_upper(bufferA, ride->name, &ride->name_arguments); + format_string_to_upper(bufferA, 128, ride->name, &ride->name_arguments); while (--current_list_position >= 0) { otherRide = get_ride(w->list_item_positions[current_list_position]); - format_string_to_upper(bufferB, otherRide->name, &otherRide->name_arguments); + format_string_to_upper(bufferB, 128, otherRide->name, &otherRide->name_arguments); if (strcmp(bufferA, bufferB) >= 0) break; diff --git a/src/windows/server_list.c b/src/windows/server_list.c index 017d66a5ff..67754599f5 100644 --- a/src/windows/server_list.c +++ b/src/windows/server_list.c @@ -480,7 +480,7 @@ static void window_server_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi char players[32]; players[0] = 0; if (serverDetails->maxplayers > 0) { - sprintf(players, "%d/%d", serverDetails->players, serverDetails->maxplayers); + snprintf(players, 32, "%d/%d", serverDetails->players, serverDetails->maxplayers); } int numPlayersStringWidth = gfx_get_string_width(players); gfx_draw_string(dpi, players, w->colours[1], right - numPlayersStringWidth, y + 3); @@ -525,8 +525,8 @@ static void server_list_load_server_entries() utf8 path[MAX_PATH]; SDL_RWops *file; - platform_get_user_directory(path, NULL); - strcat(path, "servers.cfg"); + platform_get_user_directory(path, NULL, sizeof(path)); + safe_strcat_path(path, "servers.cfg", sizeof(path)); file = SDL_RWFromFile(path, "rb"); if (file == NULL) { @@ -564,8 +564,8 @@ static void server_list_save_server_entries() utf8 path[MAX_PATH]; SDL_RWops *file; - platform_get_user_directory(path, NULL); - strcat(path, "servers.cfg"); + platform_get_user_directory(path, NULL, sizeof(path)); + safe_strcat_path(path, "servers.cfg", sizeof(path)); file = SDL_RWFromFile(path, "wb"); if (file == NULL) { diff --git a/src/windows/server_start.c b/src/windows/server_start.c index 9bc9e7ccd3..ce6243d498 100644 --- a/src/windows/server_start.c +++ b/src/windows/server_start.c @@ -140,7 +140,7 @@ void window_server_start_open() window->page = 0; window->list_information_type = 0; - sprintf(_port, "%u", gConfigNetwork.default_port); + snprintf(_port, 7, "%u", gConfigNetwork.default_port); safe_strcpy(_name, gConfigNetwork.server_name, sizeof(_name)); } diff --git a/src/windows/shortcut_keys.c b/src/windows/shortcut_keys.c index ad808bdb42..0a8891aa68 100644 --- a/src/windows/shortcut_keys.c +++ b/src/windows/shortcut_keys.c @@ -256,14 +256,13 @@ static void window_shortcut_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, i gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031); } - // TODO: How does this work? 2525 is '???' - rct_string_id templateStringId = STR_SHORTCUT_KEY_UNKNOWN; - char *templateString = (char*)language_get_string(templateStringId); - keyboard_shortcut_format_string(templateString, gShortcutKeys[i]); + char templateString[128]; + keyboard_shortcut_format_string(templateString, 128, gShortcutKeys[i]); set_format_arg(0, rct_string_id, STR_SHORTCUT_ENTRY_FORMAT); set_format_arg(2, rct_string_id, ShortcutStringIds[i]); - set_format_arg(4, rct_string_id, templateStringId); + set_format_arg(4, rct_string_id, STR_STRING); + set_format_arg(6, char *, templateString); gfx_draw_string_left(dpi, format, gCommonFormatArgs, 0, 0, y - 1); } } diff --git a/src/windows/text_input.c b/src/windows/text_input.c index e1618fed54..2e45c53d78 100644 --- a/src/windows/text_input.c +++ b/src/windows/text_input.c @@ -107,11 +107,7 @@ void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id t // Enter in the the text input buffer any existing // text. if (existing_text != STR_NONE) - format_string(text_input, existing_text, &existing_args); - - // In order to prevent strings that exceed the maxLength - // from crashing the game. - text_input[maxLength - 1] = '\0'; + format_string(text_input, maxLength, existing_text, &existing_args); utf8_remove_format_codes(text_input, false); diff --git a/src/windows/tile_inspector.c b/src/windows/tile_inspector.c index c486b01358..628893d337 100644 --- a/src/windows/tile_inspector.c +++ b/src/windows/tile_inspector.c @@ -573,8 +573,8 @@ static void window_tile_inspector_paint(rct_window *w, rct_drawpixelinfo *dpi) gfx_draw_string_left(dpi, STR_TILE_INSPECTOR_CHOOSE_MSG, NULL, 12, x, y); } else { char buffer[256]; - sprintf( - buffer, + snprintf( + buffer, 256, "X: %d, Y: %d", window_tile_inspector_tile_x, window_tile_inspector_tile_y @@ -614,8 +614,8 @@ static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo * switch (type) { case MAP_ELEMENT_TYPE_SURFACE: - sprintf( - buffer, + snprintf( + buffer, 256, "Surface (%s, %s)", language_get_string(TerrainTypes[map_element_get_terrain(element)]), language_get_string(TerrainEdgeTypes[map_element_get_terrain_edge(element)]) @@ -628,16 +628,16 @@ static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo * const uint8 pathHasScenery = footpath_element_has_path_scenery(element); const uint8 pathAdditionType = footpath_element_get_path_scenery_index(element); if (footpath_element_is_queue(element)) { - sprintf( - buffer, "Queue (%s)%s%s for (%d)", + snprintf( + buffer, 256, "Queue (%s)%s%s for (%d)", language_get_string(get_footpath_entry(pathType)->string_idx), // Path name pathHasScenery ? " with " : "", // Adds " with " when there is something on the path pathHasScenery ? language_get_string(get_footpath_item_entry(pathAdditionType)->name) : "", // Path addition name element->properties.path.ride_index // Ride index for queue ); } else { - sprintf( - buffer, "Path (%s)%s%s", + snprintf( + buffer, 256, "Path (%s)%s%s", language_get_string(get_footpath_entry(pathType)->string_idx), // Path name pathHasScenery ? " with " : "", // Adds " with " when there is something on the path pathHasScenery ? language_get_string(get_footpath_item_entry(pathAdditionType)->name) : "" // Path addition name @@ -647,32 +647,32 @@ static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo * type_name = buffer; break; case MAP_ELEMENT_TYPE_TRACK: - sprintf( - buffer, + snprintf( + buffer, 256, "Track (%s)", language_get_string(RideNaming[get_ride(element->properties.track.ride_index)->type].name) ); type_name = buffer; break; case MAP_ELEMENT_TYPE_SCENERY: - sprintf( - buffer, + snprintf( + buffer, 256, "Scenery (%s)", language_get_string(get_small_scenery_entry(element->properties.scenery.type)->name) ); type_name = buffer; break; case MAP_ELEMENT_TYPE_ENTRANCE: - sprintf( - buffer, + snprintf( + buffer, 256, "Entrance (%s)", language_get_string(EntranceTypes[element->properties.entrance.type]) ); type_name = buffer; break; case MAP_ELEMENT_TYPE_FENCE: - sprintf( - buffer, + snprintf( + buffer, 256, "Fence (%s)", language_get_string(get_wall_entry(element->properties.scenery.type)->name) ); @@ -682,8 +682,8 @@ static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo * type_name = "Scenery multiple"; break; case MAP_ELEMENT_TYPE_BANNER: - sprintf( - buffer, + snprintf( + buffer, 256, "Banner (%d)", element->properties.banner.index ); @@ -692,7 +692,7 @@ static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo * case MAP_ELEMENT_TYPE_CORRUPT: // fall-through default: - sprintf(buffer, "Unknown (type %d)", type); + snprintf(buffer, 256, "Unknown (type %d)", type); type_name = buffer; } diff --git a/src/windows/title_command_editor.c b/src/windows/title_command_editor.c index b39ba9f0c0..4c0ad9a6de 100644 --- a/src/windows/title_command_editor.c +++ b/src/windows/title_command_editor.c @@ -25,6 +25,7 @@ #include "../interface/themes.h" #include "../interface/title_sequences.h" #include "../title.h" +#include "../util/util.h" #include "dropdown.h" typedef struct TITLE_COMMAND_ORDER { @@ -448,7 +449,7 @@ static void window_title_command_editor_textinput(rct_window *w, int widgetIndex window_invalidate(w); } else { - strcpy(textbox1Buffer, text); + safe_strcpy(textbox1Buffer, text, sizeof(textbox1Buffer)); } break; case WIDX_TEXTBOX_X: @@ -459,7 +460,7 @@ static void window_title_command_editor_textinput(rct_window *w, int widgetIndex window_invalidate(w); } else { - strcpy(textbox1Buffer, text); + safe_strcpy(textbox1Buffer, text, sizeof(textbox1Buffer)); } break; case WIDX_TEXTBOX_Y: @@ -470,7 +471,7 @@ static void window_title_command_editor_textinput(rct_window *w, int widgetIndex window_invalidate(w); } else { - strcpy(textbox2Buffer, text); + safe_strcpy(textbox2Buffer, text, sizeof(textbox2Buffer)); } break; } diff --git a/src/windows/title_editor.c b/src/windows/title_editor.c index 58ede26f0b..b283456b24 100644 --- a/src/windows/title_editor.c +++ b/src/windows/title_editor.c @@ -295,7 +295,6 @@ void window_title_editor_close(rct_window *w) static void window_title_editor_mouseup(rct_window *w, int widgetIndex) { char path[MAX_PATH]; - char separator = platform_get_path_separator(); int defaultPreset, playing, inTitle, i, commandEditorOpen; defaultPreset = (gCurrentTitleSequence < TITLE_SEQUENCE_DEFAULT_PRESETS); @@ -360,12 +359,11 @@ static void window_title_editor_mouseup(rct_window *w, int widgetIndex) } else { // TODO: This should probably use a constant - platform_get_user_directory(path, "title sequences"); - strcat(path, gConfigTitleSequences.presets[gCurrentTitleSequence].name); - strncat(path, &separator, 1); + platform_get_user_directory(path, "title sequences", sizeof(path)); + safe_strcat_path(path, gConfigTitleSequences.presets[gCurrentTitleSequence].name, sizeof(path)); } - strcat(path, gConfigTitleSequences.presets[gCurrentTitleSequence].saves[w->selected_list_item]); + safe_strcat_path(path, gConfigTitleSequences.presets[gCurrentTitleSequence].saves[w->selected_list_item], sizeof(path)); game_load_save(path); window_title_editor_open(1); } @@ -905,10 +903,10 @@ void window_title_editor_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int set_format_arg(0, uintptr_t, &title->saves[i]); if (selected || hover) { - format_string(buffer, STR_STRING, gCommonFormatArgs); + format_string(buffer, 256, STR_STRING, gCommonFormatArgs); } else { - format_string(buffer + 1, STR_STRING, gCommonFormatArgs); + format_string(buffer + 1, 255, STR_STRING, gCommonFormatArgs); buffer[0] = FORMAT_BLACK; } set_format_arg(0, uintptr_t, &buffer); @@ -980,10 +978,10 @@ void window_title_editor_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int } if ((selected || hover) && !error) { - format_string(buffer, commandName, gCommonFormatArgs); + format_string(buffer, 256, commandName, gCommonFormatArgs); } else { - format_string(buffer + 1, commandName, gCommonFormatArgs); + format_string(buffer + 1, 255, commandName, gCommonFormatArgs); buffer[0] = (error ? ((selected || hover) ? FORMAT_LIGHTPINK : FORMAT_RED) : FORMAT_BLACK); } set_format_arg(0, uintptr_t, &buffer); diff --git a/src/windows/title_scenarioselect.c b/src/windows/title_scenarioselect.c index ed66bb697c..b9231372b8 100644 --- a/src/windows/title_scenarioselect.c +++ b/src/windows/title_scenarioselect.c @@ -484,14 +484,16 @@ static void window_scenarioselect_scrollpaint(rct_window *w, rct_drawpixelinfo * bool isDisabled = listItem->scenario.is_locked; // Draw scenario name - rct_string_id placeholderStringId = STR_PLACEHOLDER; - safe_strcpy((char*)language_get_string(placeholderStringId), scenario->name, 64); + char buffer[64]; + safe_strcpy(buffer, scenario->name, sizeof(buffer)); rct_string_id format = isDisabled ? STR_STRINGID : (isHighlighted ? highlighted_format : unhighlighted_format); + set_format_arg(0, rct_string_id, STR_STRING); + set_format_arg(2, char *, buffer); colour = isDisabled ? w->colours[1] | 0x40 : COLOUR_BLACK; if (isDisabled) { gCurrentFontSpriteBase = -1; } - gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 1, colour, &placeholderStringId); + gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 1, colour, gCommonFormatArgs); // Check if scenario is completed if (isCompleted) { @@ -503,9 +505,10 @@ static void window_scenarioselect_scrollpaint(rct_window *w, rct_drawpixelinfo * if (!str_is_null_or_empty(scenario->highscore->name)) { completedByName = scenario->highscore->name; } - safe_strcpy((char*)language_get_string(placeholderStringId), completedByName, 64); + safe_strcpy(buffer, completedByName, 64); set_format_arg(0, rct_string_id, STR_COMPLETED_BY); - set_format_arg(2, rct_string_id, placeholderStringId); + set_format_arg(2, rct_string_id, STR_STRING); + set_format_arg(4, char *, buffer); gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 11, 0, gCommonFormatArgs); } @@ -527,7 +530,7 @@ static void draw_category_heading(rct_window *w, rct_drawpixelinfo *dpi, int lef // Get string dimensions utf8 *buffer = gCommonStringFormatBuffer; - format_string(buffer, stringId, NULL); + format_string(buffer, 256, stringId, NULL); int categoryStringHalfWidth = (gfx_get_string_width(buffer) / 2) + 4; int strLeft = centreX - categoryStringHalfWidth; int strRight = centreX + categoryStringHalfWidth; diff --git a/src/windows/tooltip.c b/src/windows/tooltip.c index 7beaaef13a..e2232a6c38 100644 --- a/src/windows/tooltip.c +++ b/src/windows/tooltip.c @@ -88,7 +88,7 @@ void window_tooltip_show(rct_string_id id, int x, int y) char* buffer = gCommonStringFormatBuffer; - format_string(buffer, id, gCommonFormatArgs); + format_string(buffer, 256, id, gCommonFormatArgs); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; int tooltip_text_width; diff --git a/src/windows/track_manage.c b/src/windows/track_manage.c index fb4467697d..5e8c8176b7 100644 --- a/src/windows/track_manage.c +++ b/src/windows/track_manage.c @@ -39,7 +39,7 @@ enum { static rct_widget window_track_manage_widgets[] = { { WWT_FRAME, 0, 0, 249, 0, 43, STR_NONE, STR_NONE }, - { WWT_CAPTION, 0, 1, 248, 1, 14, 3155, STR_WINDOW_TITLE_TIP }, + { WWT_CAPTION, 0, 1, 248, 1, 14, STR_STRING, STR_WINDOW_TITLE_TIP }, { WWT_CLOSEBOX, 0, 237, 247, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, { WWT_DROPDOWN_BUTTON, 0, 10, 119, 24, 35, STR_TRACK_MANAGE_RENAME, STR_NONE }, { WWT_DROPDOWN_BUTTON, 0, 130, 239, 24, 35, STR_TRACK_MANAGE_DELETE, STR_NONE }, @@ -166,10 +166,6 @@ void window_track_manage_open(track_design_file_ref *tdFileRef) trackDesignListWindow->track_list.var_484 |= 1; } - // TODO: 3155 appears to be empty. What is this supposed to do? - utf8 *title = (utf8*)language_get_string(3155); - format_string(title, STR_TRACK_LIST_NAME_FORMAT, &tdFileRef->name); - _trackDesignFileReference = tdFileRef; } @@ -240,6 +236,7 @@ static void window_track_manage_invalidate(rct_window *w) */ static void window_track_manage_paint(rct_window *w, rct_drawpixelinfo *dpi) { + set_format_arg(0, char *, _trackDesignFileReference->name); window_draw_widgets(w, dpi); } diff --git a/src/windows/track_place.c b/src/windows/track_place.c index e8577d57ee..6377166edd 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -45,7 +45,7 @@ enum { static rct_widget window_track_place_widgets[] = { { WWT_FRAME, 0, 0, 199, 0, 123, 0xFFFFFFFF, STR_NONE }, - { WWT_CAPTION, 0, 1, 198, 1, 14, 3155, STR_WINDOW_TITLE_TIP }, + { WWT_CAPTION, 0, 1, 198, 1, 14, STR_STRING, STR_WINDOW_TITLE_TIP }, { WWT_CLOSEBOX, 0, 187, 197, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, { WWT_FLATBTN, 0, 173, 196, 83, 106, SPR_ROTATE_ARROW, STR_ROTATE_90_TIP }, { WWT_FLATBTN, 0, 173, 196, 59, 82, SPR_MIRROR_ARROW, STR_MIRROR_IMAGE_TIP }, @@ -167,10 +167,6 @@ void window_track_place_open(const track_design_file_ref *tdFileRef) _window_track_place_last_x = 0xFFFF; _currentTrackPieceDirection = (2 - get_current_rotation()) & 3; window_track_place_draw_mini_preview(td6); - - // TODO: 3155 appears to be empty. What is this supposed to do? - char *title = (char*)language_get_string(3155); - format_string(title, STR_TRACK_LIST_NAME_FORMAT, &td6->name); _trackDesign = td6; } @@ -445,6 +441,7 @@ static void window_track_place_attempt_placement(rct_track_td6 *td6, int x, int */ static void window_track_place_paint(rct_window *w, rct_drawpixelinfo *dpi) { + set_format_arg(0, char *, _trackDesign->name); window_draw_widgets(w, dpi); // Draw mini tile preview diff --git a/src/world/map.c b/src/world/map.c index 899e12db88..912a62e348 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -30,6 +30,7 @@ #include "../ride/track.h" #include "../ride/track_data.h" #include "../scenario.h" +#include "../util/util.h" #include "banner.h" #include "climate.h" #include "footpath.h" @@ -5249,7 +5250,7 @@ void game_command_set_banner_name(int* eax, int* ebx, int* ecx, int* edx, int* e utf8 *buffer = gCommonStringFormatBuffer; utf8 *dst = buffer; dst = utf8_write_codepoint(dst, FORMAT_COLOUR_CODE_START + banner->text_colour); - strncpy(dst, newName, 32); + safe_strcpy(dst, newName, 32); rct_string_id stringId = user_string_allocate(128, buffer); if (stringId) { @@ -5388,7 +5389,7 @@ void game_command_set_banner_style(int* eax, int* ebx, int* ecx, int* edx, int* int colourCodepoint = FORMAT_COLOUR_CODE_START + banner->text_colour; utf8 buffer[256]; - format_string(buffer, banner->string_idx, 0); + format_string(buffer, 256, banner->string_idx, 0); int firstCodepoint = utf8_get_next(buffer, NULL); if (firstCodepoint >= FORMAT_COLOUR_CODE_START && firstCodepoint <= FORMAT_COLOUR_CODE_END) { utf8_write_codepoint(buffer, colourCodepoint); diff --git a/src/world/money_effect.c b/src/world/money_effect.c index 8e60a8042e..7b57216890 100644 --- a/src/world/money_effect.c +++ b/src/world/money_effect.c @@ -55,7 +55,7 @@ static void money_effect_create_at(money32 value, int x, int y, int z) value *= -1; stringId = 1399; } - format_string(buffer, stringId, &value); + format_string(buffer, 128, stringId, &value); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; moneyEffect->offset_x = -(gfx_get_string_width(buffer) / 2); moneyEffect->wiggle = 0; diff --git a/src/world/park.c b/src/world/park.c index a3d2318f28..b724ff0248 100644 --- a/src/world/park.c +++ b/src/world/park.c @@ -147,7 +147,7 @@ void park_init() award_reset(); gS6Info.name[0] = '\0'; - format_string(gS6Info.details, STR_NO_DETAILS_YET, NULL); + format_string(gS6Info.details, 256, STR_NO_DETAILS_YET, NULL); } /** @@ -915,7 +915,7 @@ void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi return; } - format_string(oldName, gParkName, &gParkNameArgs); + format_string(oldName, 128, gParkName, &gParkNameArgs); if (strcmp(oldName, newName) == 0) { *ebx = 0; return; diff --git a/src/world/sprite.c b/src/world/sprite.c index 82b97b61bd..ab596eaa9e 100644 --- a/src/world/sprite.c +++ b/src/world/sprite.c @@ -207,7 +207,7 @@ const char * sprite_checksum() char *x = (char *)_spriteChecksum; for (unsigned int i = 0; i < size; i++) { - sprintf(x, "%02x", localhash[i]); + snprintf(x, EVP_MAX_MD_SIZE + 1, "%02x", localhash[i]); x += 2; } *x = '\0';