From 9f5e6901187946c4844a3506b5abc82a13f0761b Mon Sep 17 00:00:00 2001 From: rubidium Date: Tue, 14 Apr 2009 21:07:33 +0000 Subject: [PATCH] (svn r16059) [0.7] -Backport from trunk: - Fix: Inconsistency between using NETWORK_NAME_LENGTH and NETWORK_CLIENT_NAME_LENGTH for the length of client names (r15988) - Fix: [NewGRF] Abort production callback after 0x10000 iterations and show a messagebox blaming the NewGRF [FS#2787] (r15958) - Fix: [NewGRF] Set callback_param1 (var 10) to 1 only when requested (r15957) - Fix: Tooltip of detailed ratings window button showed wrong tip (r15943) - Change: Harden string copying on places where it is possible (r16024) - Change: Use recent Czech language for plural form (r15965) --- src/ai/ai_scanner.cpp | 2 +- src/fileio.cpp | 10 +++++----- src/graph_gui.cpp | 2 +- src/lang/czech.txt | 2 +- src/lang/english.txt | 2 ++ src/misc_gui.cpp | 2 +- src/music/win32_m.cpp | 2 +- src/network/network_gui.cpp | 2 +- src/newgrf_industries.cpp | 14 ++++++++++++++ src/newgrf_station.cpp | 8 +++++--- src/newgrf_station.h | 8 ++++++++ src/screenshot.cpp | 2 +- src/settings.cpp | 6 +++--- src/settings_type.h | 2 +- src/strgen/strgen.cpp | 8 ++++---- src/strings.cpp | 8 +++++++- src/video/dedicated_v.cpp | 2 +- 17 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/ai/ai_scanner.cpp b/src/ai/ai_scanner.cpp index a35055133d..716df088dc 100644 --- a/src/ai/ai_scanner.cpp +++ b/src/ai/ai_scanner.cpp @@ -153,7 +153,7 @@ AIScanner::AIScanner() : /* Create the dummy AI */ this->engine->ResetCrashed(); - strcpy(this->main_script, "%_dummy"); + strecpy(this->main_script, "%_dummy", lastof(this->main_script)); extern void AI_CreateAIInfoDummy(HSQUIRRELVM vm); AI_CreateAIInfoDummy(this->engine->GetVM()); } diff --git a/src/fileio.cpp b/src/fileio.cpp index 79d2283f64..8252f5b905 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -363,7 +363,7 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, char resolved_name[MAX_RESOLVED_LENGTH]; /* Filenames in tars are always forced to be lowercase */ - strcpy(resolved_name, filename); + strecpy(resolved_name, filename, lastof(resolved_name)); strtolower(resolved_name); size_t resolved_len = strlen(resolved_name); @@ -376,9 +376,9 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, /* Apply link */ char resolved_name2[MAX_RESOLVED_LENGTH]; const std::string &dest = link->second; - strcpy(resolved_name2, &(resolved_name[len])); - strcpy(resolved_name, dest.c_str()); - strcpy(&(resolved_name[dest.length()]), resolved_name2); + strecpy(resolved_name2, &(resolved_name[len]), lastof(resolved_name2)); + strecpy(resolved_name, dest.c_str(), lastof(resolved_name)); + strecpy(&(resolved_name[dest.length()]), resolved_name2, lastof(resolved_name)); break; // Only resolve one level } } @@ -640,7 +640,7 @@ bool TarListAddFile(const char *filename) /* Process relative path. * Note: The destination of links must not contain any directory-links. */ - strcpy(dest, name); + strecpy(dest, name, lastof(dest)); char *destpos = strrchr(dest, PATHSEPCHAR); if (destpos == NULL) destpos = dest; *destpos = '\0'; diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 44cfe75ecf..7db4320b4f 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -554,7 +554,7 @@ static const Widget _performance_history_widgets[] = { { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_SHOW_DETAILED_PERFORMANCE_RATINGS}, { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 237, 0x0, STR_NULL}, { WIDGETS_END}, }; diff --git a/src/lang/czech.txt b/src/lang/czech.txt index ae8666ef9f..7d12d8b16b 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -3,7 +3,7 @@ ##isocode cs_CZ ##winlangid 0x0405 ##grflangid 0x15 -##plural 6 +##plural 10 ##case nom gen dat acc voc loc ins big small ##gender m f n diff --git a/src/lang/english.txt b/src/lang/english.txt index 9651e0c0e5..e063b1d27b 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2241,6 +2241,7 @@ STR_704A_SELECT_FEMALE_FACES :{BLACK}Select f STR_704B_GENERATE_RANDOM_NEW_FACE :{BLACK}Generate random new face STR_704C_KEY :{BLACK}Key STR_704D_SHOW_KEY_TO_GRAPHS :{BLACK}Show key to graphs +STR_SHOW_DETAILED_PERFORMANCE_RATINGS :{BLACK}Show detailed performance ratings STR_704E_KEY_TO_COMPANY_GRAPHS :{WHITE}Key to company graphs STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY :{BLACK}Click here to toggle company's entry on graph on/off STR_7050_UNITS_OF_CARGO_DELIVERED :{WHITE}Units of cargo delivered @@ -3172,6 +3173,7 @@ STR_BROKEN_VEHICLE_LENGTH :{WHITE}Train '{ STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:RAW_STRING}' provides incorrect information. STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Cargo/refit information for '{1:ENGINE}' differs from purchase list after construction. This might cause autorenew/-replace to fail refitting correctly. +STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' caused an endless loop in the production callback. STR_LOADGAME_REMOVED_TRAMS :{WHITE}Game was saved in version without tram support. All trams have been removed. diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index df474d5985..8741a3d2e0 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -1490,7 +1490,7 @@ public: this->vscroll.cap--; case SLD_SAVE_GAME: this->GenerateFileName(); break; - case SLD_SAVE_SCENARIO: strcpy(this->edit_str_buf, "UNNAMED"); break; + case SLD_SAVE_SCENARIO: strecpy(this->edit_str_buf, "UNNAMED", &this->edit_str_buf[edit_str_size - 1]); break; default: break; } diff --git a/src/music/win32_m.cpp b/src/music/win32_m.cpp index abcbffd27d..54ea6e74f7 100644 --- a/src/music/win32_m.cpp +++ b/src/music/win32_m.cpp @@ -23,7 +23,7 @@ static FMusicDriver_Win32 iFMusicDriver_Win32; void MusicDriver_Win32::PlaySong(const char *filename) { assert(filename != NULL); - strcpy(_midi.start_song, filename); + strecpy(_midi.start_song, filename, lastof(_midi.start_song)); _midi.playing = true; _midi.stop_song = false; SetEvent(_midi.wait_obj); diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 783806e330..398cf3b0f2 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -305,7 +305,7 @@ protected: } public: - NetworkGameWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_NAME_LENGTH, desc) + NetworkGameWindow(const WindowDesc *desc) : QueryStringBaseWindow(NETWORK_CLIENT_NAME_LENGTH, desc) { ttd_strlcpy(this->edit_str_buf, _settings_client.network.client_name, this->edit_str_size); this->afilter = CS_ALPHANUMERAL; diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index 88d5958938..73397eb7c5 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -17,6 +17,8 @@ #include "town.h" #include "company_base.h" #include "command_func.h" +#include "gui.h" +#include "strings_func.h" #include "table/strings.h" @@ -570,6 +572,18 @@ void IndustryProductionCallback(Industry *ind, int reason) object.callback_param2 = reason; for (uint loop = 0;; loop++) { + /* limit the number of calls to break infinite loops. + * 'loop' is provided as 16 bits to the newgrf, so abort when those are exceeded. */ + if (loop >= 0x10000) { + /* display error message */ + SetDParamStr(0, spec->grf_prop.grffile->filename); + SetDParam(1, spec->name); + ShowErrorMessage(STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK, STR_NEWGRF_BUGGY, 0, 0); + + /* abort the function early, this error isn't critical and will allow the game to continue to run */ + break; + } + SB(object.callback_param2, 8, 16, loop); const SpriteGroup *group = Resolve(spec->grf_prop.spritegroup, &object); if (group == NULL || group->type != SGT_INDUSTRY_PRODUCTION) break; diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index 26b49cc877..57384b102b 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -558,7 +558,7 @@ static const SpriteGroup *StationResolveReal(const ResolverObject *object, const break; } - if (HasBit(statspec->flags, 1)) cargo /= (st->trainst_w + st->trainst_h); + if (HasBit(statspec->flags, SSF_DIV_BY_STATION_SIZE)) cargo /= (st->trainst_w + st->trainst_h); cargo = min(0xfff, cargo); if (cargo > statspec->cargo_threshold) { @@ -655,7 +655,9 @@ SpriteID GetCustomStationGroundRelocation(const StationSpec *statspec, const Sta ResolverObject object; NewStationResolver(&object, statspec, st, tile); - object.callback_param1 = 1; // Indicate we are resolving the ground sprite + if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) { + object.callback_param1 = 1; // Indicate we are resolving the ground sprite + } group = ResolveStation(&object); if (group == NULL || group->type != SGT_RESULT) return 0; @@ -904,7 +906,7 @@ void AnimateStationTile(TileIndex tile) bool frame_set_by_callback = false; if (HasBit(ss->callbackmask, CBM_STATION_ANIMATION_NEXT_FRAME)) { - uint32 param = HasBit(ss->flags, 2) ? Random() : 0; + uint32 param = HasBit(ss->flags, SSF_CB141_RANDOM_BITS) ? Random() : 0; uint16 callback = GetStationCallback(CBID_STATION_ANIM_NEXT_FRAME, param, 0, ss, st, tile); if (callback != CALLBACK_FAILED) { diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 9af801f05d..5bd52891b2 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -29,6 +29,14 @@ typedef TinyEnumT StationClassIDByte; /** Allow incrementing of StationClassID variables */ DECLARE_POSTFIX_INCREMENT(StationClassID); +enum StationSpecFlags { + SSF_SEPARATE_GROUND, ///< Use different sprite set for ground sprites. + SSF_DIV_BY_STATION_SIZE, ///< Divide cargo amount by station size. + SSF_CB141_RANDOM_BITS, ///< Callback 141 needs random bits. + SSF_CUSTOM_FOUNDATIONS, ///< Draw custom foundations. + SSF_EXTENDED_FOUNDATIONS, ///< Extended foundation block instead of simple. +}; + /* Station layout for given dimensions - it is a two-dimensional array * where index is computed as (x * platforms) + platform. */ typedef byte *StationLayout; diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 01dac79a01..17b18993ea 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -456,7 +456,7 @@ const char *GetScreenshotFormatDesc(int i) void SetScreenshotFormat(int i) { _cur_screenshot_format = i; - strcpy(_screenshot_format_name, _screenshot_formats[i].extension); + strecpy(_screenshot_format_name, _screenshot_formats[i].extension, lastof(_screenshot_format_name)); } /* screenshot generator that dumps the current video buffer */ diff --git a/src/settings.cpp b/src/settings.cpp index 4f3eda5473..e79248b76a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -556,7 +556,7 @@ static void ini_save_settings(IniFile *ini, const SettingDesc *sd, const char *g uint32 i = (uint32)ReadValue(ptr, sld->conv); switch (sdb->cmd) { - case SDT_BOOLX: strcpy(buf, (i != 0) ? "true" : "false"); break; + case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break; case SDT_NUMX: seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break; case SDT_ONEOFMANY: make_oneofmany(buf, lastof(buf), sdb->many, i); break; case SDT_MANYOFMANY: make_manyofmany(buf, lastof(buf), sdb->many, i); break; @@ -566,9 +566,9 @@ static void ini_save_settings(IniFile *ini, const SettingDesc *sd, const char *g case SDT_STRING: switch (GetVarMemType(sld->conv)) { - case SLE_VAR_STRB: strcpy(buf, (char*)ptr); break; + case SLE_VAR_STRB: strecpy(buf, (char*)ptr, lastof(buf)); break; case SLE_VAR_STRBQ:seprintf(buf, lastof(buf), "\"%s\"", (char*)ptr); break; - case SLE_VAR_STR: strcpy(buf, *(char**)ptr); break; + case SLE_VAR_STR: strecpy(buf, *(char**)ptr, lastof(buf)); break; case SLE_VAR_STRQ: if (*(char**)ptr == NULL) { buf[0] = '\0'; diff --git a/src/settings_type.h b/src/settings_type.h index e3f52600db..56015dc083 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -119,7 +119,7 @@ struct NetworkSettings { char rcon_password[NETWORK_PASSWORD_LENGTH]; ///< passowrd for rconsole (server side) bool server_advertise; ///< advertise the server to the masterserver uint8 lan_internet; ///< search on the LAN or internet for servers - char client_name[NETWORK_NAME_LENGTH]; ///< name of the player (as client) + char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< name of the player (as client) char default_company_pass[NETWORK_PASSWORD_LENGTH]; ///< default password for new companies in encrypted form char connect_to_ip[NETWORK_HOSTNAME_LENGTH]; ///< default for the "Add server" query char network_id[NETWORK_UNIQUE_ID_LENGTH]; ///< semi-unique ID of the client diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index 04a59b3876..b769d55fef 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -99,7 +99,7 @@ static char _cases[MAX_NUM_CASES][16]; static uint _numcases; /* for each plural value, this is the number of plural forms. */ -static const byte _plural_form_counts[] = { 2, 1, 2, 3, 3, 3, 3, 3, 4, 2 }; +static const byte _plural_form_counts[] = { 2, 1, 2, 3, 3, 3, 3, 3, 4, 2, 3 }; static const char *_cur_ident; @@ -1193,9 +1193,9 @@ static void WriteLangfile(const char *filename) hdr.text_dir = _lang_textdir; hdr.winlangid = TO_LE16(_lang_winlangid); hdr.newgrflangid = _lang_newgrflangid; - strcpy(hdr.name, _lang_name); - strcpy(hdr.own_name, _lang_ownname); - strcpy(hdr.isocode, _lang_isocode); + strecpy(hdr.name, _lang_name, lastof(hdr.name)); + strecpy(hdr.own_name, _lang_ownname, lastof(hdr.own_name)); + strecpy(hdr.isocode, _lang_isocode, lastof(hdr.isocode)); fwrite(&hdr, sizeof(hdr), 1, f); diff --git a/src/strings.cpp b/src/strings.cpp index 07bd67c1bd..7da8bdf807 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -439,7 +439,7 @@ static int DeterminePluralForm(int64 count) /* Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4] * Used in: - * Croatian, Czech, Russian, Slovak, Ukrainian */ + * Croatian, Russian, Slovak, Ukrainian */ case 6: return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; @@ -460,6 +460,12 @@ static int DeterminePluralForm(int64 count) * Icelandic */ case 9: return n % 10 == 1 && n % 100 != 11 ? 0 : 1; + + /* Three forms, special cases for one and 2, 3, or 4 + * Used in: + * Czech */ + case 10: + return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2; } } diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index 93ea1c7e26..486ea547e0 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -222,7 +222,7 @@ static void DedicatedHandleKeyInput() #else /* Handle console input, and singal console thread, it can accept input again */ assert_compile(lengthof(_win_console_thread_buffer) <= lengthof(input_line)); - strcpy(input_line, _win_console_thread_buffer); + strecpy(input_line, _win_console_thread_buffer, lastof(input_line)); SetEvent(_hWaitForInputHandling); #endif