From a51ba3465028e8b8707c2b350ce0217d0d0c58aa Mon Sep 17 00:00:00 2001 From: ALONSO Laurent Date: Fri, 22 Oct 2021 13:39:28 +0200 Subject: [PATCH] add methods get_special_string to check access bounds of spec_strs... --- src/fileio/fileio_scen.cpp | 32 +++++++++++++------------ src/game/boe.actions.cpp | 2 +- src/game/boe.dlgutil.cpp | 8 +++---- src/game/boe.infodlg.cpp | 6 ++--- src/game/boe.items.cpp | 6 ++--- src/game/boe.specials.cpp | 14 +++++------ src/scenario/outdoors.cpp | 21 ++++++++++++++++ src/scenario/outdoors.hpp | 3 +++ src/scenario/scenario.cpp | 22 +++++++++++++++++ src/scenario/scenario.hpp | 2 ++ src/scenario/town.cpp | 21 ++++++++++++++++ src/scenario/town.hpp | 2 ++ src/scenedit/scen.actions.cpp | 18 +++++++------- src/scenedit/scen.fileio.cpp | 2 +- src/scenedit/scen.keydlgs.cpp | 6 ++--- src/universe/party.cpp | 45 +++++++++++++++++++---------------- 16 files changed, 143 insertions(+), 67 deletions(-) diff --git a/src/fileio/fileio_scen.cpp b/src/fileio/fileio_scen.cpp index 09d07f6c..97de8889 100644 --- a/src/fileio/fileio_scen.cpp +++ b/src/fileio/fileio_scen.cpp @@ -273,7 +273,8 @@ bool load_scenario_v1(fs::path file_to_load, cScenario& scenario, bool only_head if(i % 2 == 0) scenario.special_items[(i-60)/2].name = tmp; else scenario.special_items[(i-60)/2].descr = tmp; } else if(i >= 260) continue; // These were never ever used, for some reason. - else scenario.spec_strs[i-160] = tmp; + else + scenario.get_special_string(i-160) = tmp; } fclose(file_id); @@ -888,9 +889,9 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) { timers++; } else if(type == "string") { game->GetAttribute("id", &strnum); - if(strnum >= scenario.spec_strs.size()) // changeme: add a maximum and discard data if not in a range + if(strnum >= scenario.spec_strs.size() && strnum<10000) scenario.spec_strs.resize(strnum + 1); - game->GetText(&scenario.spec_strs[strnum], false); + game->GetText(&scenario.get_special_string(strnum), false); } else if(type == "journal") { game->GetAttribute("id", &strnum); if(strnum >= scenario.journal_strs.size()) // changeme: add a maximum and discard data if not in a range @@ -1133,7 +1134,7 @@ void readItemsFromXml(ticpp::Document&& data, cScenario& scenario) { throw xBadNode(type, elem->Row(), elem->Column(), fname); int which_item; elem->GetAttribute("id", &which_item); - if(which_item >= scenario.scen_items.size() && which_item<5000) // checkme: what is a reasonnable maximum for the item + if(which_item >= scenario.scen_items.size() && which_item<5000) // checkme: what is a reasonable maximum for the item scenario.scen_items.resize(which_item + 1); cItem& the_item = scenario.get_item(which_item); the_item = cItem(); @@ -1654,9 +1655,9 @@ void readOutdoorsFromXml(ticpp::Document&& data, cOutdoors& out) { } else if(type == "string") { int str; elem->GetAttribute("id", &str); - if(str >= out.spec_strs.size()) + if(str >= out.spec_strs.size() && str<10000) // CHECKME: 10000 is probably too big? out.spec_strs.resize(str + 1); - elem->GetText(&out.spec_strs[str], false); + elem->GetText(&out.get_special_string(str), false); } else throw xBadNode(type, elem->Row(), elem->Column(), fname); } if(!found_name) @@ -1781,9 +1782,9 @@ void readTownFromXml(ticpp::Document&& data, cTown*& town, cScenario& scen) { } else if(type == "string") { int str; elem->GetAttribute("id", &str); - if(str >= town->spec_strs.size()) + if(str >= town->spec_strs.size() && str<10000) town->spec_strs.resize(str + 1); - elem->GetText(&town->spec_strs[str], false); + elem->GetText(&town->get_special_string(str), false); } else if(type == "item") { int which_item; elem->GetAttribute("id", &which_item); @@ -1888,19 +1889,20 @@ void readDialogueFromXml(ticpp::Document&& data, cSpeech& talk, int town_num) { id %= 10; std::set reqs = {"title", "look", "name", "job"}; Iterator who; + cPersonality &people=talk.people[id]; for(who = who.begin(elem.Get()); who != who.end(); who++) { who->GetValue(&type); reqs.erase(type); if(type == "title") { - who->GetText(&talk.people[id].title, false); + who->GetText(&people.title, false); } else if(type == "look") { - who->GetText(&talk.people[id].look, false); + who->GetText(&people.look, false); } else if(type == "name") { - who->GetText(&talk.people[id].name, false); + who->GetText(&people.name, false); } else if(type == "job") { - who->GetText(&talk.people[id].job, false); + who->GetText(&people.job, false); } else if(type == "unknown") { - who->GetText(&talk.people[id].dunno, false); + who->GetText(&people.dunno, false); } else throw xBadNode(type, who->Row(), who->Column(), fname); } if(!reqs.empty()) @@ -2348,7 +2350,7 @@ bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy: else if(i >= 17 && i < 20) the_town.comment[i-17] = tmp; else if(i >= 20 && i < 120) - the_town.spec_strs[i-20] = tmp; + the_town.get_special_string(i-20) = tmp; else if(i >= 120 && i < 140) the_town.sign_locs[i-120].text = tmp; } @@ -2460,7 +2462,7 @@ bool load_outdoors_v1(fs::path scen_file, location which_out,cOutdoors& the_out, else if(i == 9) the_out.comment = tmp; else if(i < 9) the_out.area_desc[i-1].descr = tmp; else if(i >= 10 && i < 100) - the_out.spec_strs[i-10] = tmp; + the_out.get_special_string(i-10) = tmp; else if(i >= 100 && i < 108) the_out.sign_locs[i-100].text = tmp; } diff --git a/src/game/boe.actions.cpp b/src/game/boe.actions.cpp index eb135dc9..b3705df9 100644 --- a/src/game/boe.actions.cpp +++ b/src/game/boe.actions.cpp @@ -585,7 +585,7 @@ static void handle_talk(location destination, bool& did_something, bool& need_re small_talk = -univ.town.monst[i].personality; std::string str = "No response."; if(small_talk > 1000 && small_talk < 1000 + univ.scenario.spec_strs.size()) - str = univ.scenario.spec_strs[small_talk - 1000]; + str = univ.scenario.get_special_string(small_talk - 1000); // TODO: Come up with a set of pre-cooked responses. add_string_to_buf("Talk: " + str, 4); } else if (univ.town.monst[i].active) { diff --git a/src/game/boe.dlgutil.cpp b/src/game/boe.dlgutil.cpp index 1bf75747..016b3f69 100644 --- a/src/game/boe.dlgutil.cpp +++ b/src/game/boe.dlgutil.cpp @@ -1114,8 +1114,8 @@ void handle_talk_event(location p) { run_special(eSpecCtx::TALK, eSpecCtxType::TOWN, a, univ.party.town_loc, &s1, &s2); // check s1 & s2 to see if we got diff str, and, if so, munch old strs if((s1 >= 0) || (s2 >= 0)) { - save_talk_str1 = s1 >= 0 ? univ.town->spec_strs[s1] : ""; - save_talk_str2 = s2 >= 0 ? univ.town->spec_strs[s2] : ""; + save_talk_str1 = s1 >= 0 ? univ.town->get_special_string(s1) : ""; + save_talk_str2 = s2 >= 0 ? univ.town->get_special_string(s2) : ""; } get_strs(save_talk_str1, save_talk_str2, eSpecCtxType::TOWN, s1, s2); put_pc_screen(); @@ -1125,8 +1125,8 @@ void handle_talk_event(location p) { run_special(eSpecCtx::TALK, eSpecCtxType::SCEN, a, univ.party.town_loc, &s1, &s2); // check s1 & s2 to see if we got diff str, and, if so, munch old strs if((s1 >= 0) || (s2 >= 0)) { - save_talk_str1 = s1 >= 0 ? univ.scenario.spec_strs[s1] : ""; - save_talk_str2 = s2 >= 0 ? univ.scenario.spec_strs[s2] : ""; + save_talk_str1 = s1 >= 0 ? univ.scenario.get_special_string(s1) : ""; + save_talk_str2 = s2 >= 0 ? univ.scenario.get_special_string(s2) : ""; } get_strs(save_talk_str1, save_talk_str2, eSpecCtxType::SCEN, s1, s2); put_pc_screen(); diff --git a/src/game/boe.infodlg.cpp b/src/game/boe.infodlg.cpp index eebc88dc..2295673c 100644 --- a/src/game/boe.infodlg.cpp +++ b/src/game/boe.infodlg.cpp @@ -690,21 +690,21 @@ void cStringRecorder::operator()(cDialog& me) { std::string str1, str2; switch(type) { case NOTE_SCEN: - str1 = univ.scenario.spec_strs[label1]; + str1 = univ.scenario.get_special_string(label1); if (label2>=univ.scenario.spec_strs.size()) add_string_to_buf("cStringRecorder()[scenario]: empty label 2."); else str2 = univ.scenario.spec_strs[label2]; break; case NOTE_TOWN: - str1 = univ.town->spec_strs[label1]; + str1 = univ.town->get_special_string(label1); if (label2>=univ.town->spec_strs.size()) add_string_to_buf("cStringRecorder()[town]: empty label 2."); else str2 = univ.town->spec_strs[label2]; break; case NOTE_OUT: - str1 = univ.scenario.outdoors[label1b][label2b]->spec_strs[label1]; + str1 = univ.scenario.outdoors[label1b][label2b]->get_special_string(label1); // memory problem, ie. called with label=65535(-1) if (label2>=univ.scenario.outdoors[label1b][label2b]->spec_strs.size()) add_string_to_buf("cStringRecorder()[out]: empty label 2."); diff --git a/src/game/boe.items.cpp b/src/game/boe.items.cpp index 8bce0f15..d9c3d08e 100644 --- a/src/game/boe.items.cpp +++ b/src/game/boe.items.cpp @@ -641,11 +641,11 @@ void story_dialog(std::string title, str_num_t first, str_num_t last, eSpecCtxTy cur++; } if(which_str_type == eSpecCtxType::SCEN) - me["str"].setText(univ.scenario.spec_strs[cur]); + me["str"].setText(univ.scenario.get_special_string(cur)); else if(which_str_type == eSpecCtxType::OUTDOOR) - me["str"].setText(univ.out->spec_strs[cur]); + me["str"].setText(univ.out->get_special_string(cur)); else if(which_str_type == eSpecCtxType::TOWN) - me["str"].setText(univ.town->spec_strs[cur]); + me["str"].setText(univ.town->get_special_string(cur)); return true; }, {"left", "right", "done"}); story_dlg["left"].triggerClickHandler(story_dlg, "left", eKeyMod()); diff --git a/src/game/boe.specials.cpp b/src/game/boe.specials.cpp index f10c465e..ceb2cdf5 100644 --- a/src/game/boe.specials.cpp +++ b/src/game/boe.specials.cpp @@ -4584,21 +4584,21 @@ void get_strs(std::string& str1,std::string& str2,eSpecCtxType cur_type,short wh switch(cur_type) { case eSpecCtxType::SCEN: if(which_str1 >= 0) - str1 = univ.scenario.spec_strs[which_str1]; + str1 = univ.scenario.get_special_string(which_str1); if(which_str2 >= 0) - str2 = univ.scenario.spec_strs[which_str2]; + str2 = univ.scenario.get_special_string(which_str2); break; case eSpecCtxType::OUTDOOR: if(which_str1 >= 0) - str1 = univ.out->spec_strs[which_str1]; + str1 = univ.out->get_special_string(which_str1); if(which_str2 >= 0) - str2 = univ.out->spec_strs[which_str2]; + str2 = univ.out->get_special_string(which_str2); break; case eSpecCtxType::TOWN: if(which_str1 >= 0) - str1 = univ.town->spec_strs[which_str1]; + str1 = univ.town->get_special_string(which_str1); if(which_str2 >= 0) - str2 = univ.town->spec_strs[which_str2]; + str2 = univ.town->get_special_string(which_str2); break; } @@ -4614,7 +4614,7 @@ void set_campaign_flag(short sdf_a, short sdf_b, short cpf_a, short cpf_b, short // get_send = true: Retrieve value from Campaign Flag and put in SDF try { if(str >= 0 && str < univ.scenario.spec_strs.size()) { - std::string cp_id = univ.scenario.spec_strs[str]; + std::string const &cp_id = univ.scenario.spec_strs[str]; if(get_send) univ.party.stuff_done[sdf_a][sdf_b] = univ.cpn_flag(cpf_a, cpf_b, cp_id); else diff --git a/src/scenario/outdoors.cpp b/src/scenario/outdoors.cpp index a4c18967..2ca741b3 100644 --- a/src/scenario/outdoors.cpp +++ b/src/scenario/outdoors.cpp @@ -17,6 +17,27 @@ #include "oldstructs.hpp" #include "scenario.hpp" +std::string &cOutdoors::get_special_string(int id) +{ + if (id>=0 && id=0 && id<200) { + spec_strs.resize(id+1); + return spec_strs[id]; + } + static std::string badString; + badString="Bad Special String"; + return badString; +} + +std::string const &cOutdoors::get_special_string(int id) const +{ + if (id>=0 && id=0 && id=0 && id<200) { + spec_strs.resize(id+1); + return spec_strs[id]; + } + static std::string badString; + badString="Bad Special String"; + return badString; +} + +std::string const &cScenario::get_special_string(int id) const +{ + if (id>=0 && id=0 && id=0 && id<200) { + spec_strs.resize(id+1); + return spec_strs[id]; + } + static std::string badString; + badString="Bad Special String"; + return badString; +} + +std::string const &cTown::get_special_string(int id) const +{ + if (id>=0 && idspec_strs.pop_back(); else if(j == size_before) current_terrain->spec_strs.resize(size_before + 8, "*"); - else current_terrain->spec_strs[j] = "*"; + else current_terrain->get_special_string(j) = "*"; } else { if(j == size_before) current_terrain->spec_strs.emplace_back("*"); - if(!edit_text_str(j,STRS_OUT) && j == size_before && current_terrain->spec_strs[j] == "*") + if(!edit_text_str(j,STRS_OUT) && j == size_before && current_terrain->get_special_string(j) == "*") current_terrain->spec_strs.pop_back(); } start_string_editing(STRS_OUT,size_before == current_terrain->spec_strs.size()); @@ -484,11 +484,11 @@ static bool handle_rb_action(location the_point, bool option_hit) { town->spec_strs.pop_back(); else if(j == size_before) town->spec_strs.resize(size_before + 8, "*"); - else town->spec_strs[j] = "*"; + else town->get_special_string(j) = "*"; } else { if(j == size_before) town->spec_strs.emplace_back("*"); - if(!edit_text_str(j,STRS_TOWN) && j == size_before && town->spec_strs[j] == "*") + if(!edit_text_str(j,STRS_TOWN) && j == size_before && town->get_special_string(j) == "*") town->spec_strs.pop_back(); } start_string_editing(STRS_TOWN,size_before == town->spec_strs.size()); @@ -2547,15 +2547,15 @@ void start_string_editing(eStrMode mode,short just_redo_text) { std::ostringstream str; switch(mode) { case 0: - str << i << " - " << scenario.spec_strs[i].substr(0,30); + str << i << " - " << scenario.get_special_string(i).substr(0,30); set_rb(i,RB_SCEN_STR, i,str.str()); break; case 1: - str << i << " - " << current_terrain->spec_strs[i].substr(0,30); + str << i << " - " << current_terrain->get_special_string(i).substr(0,30); set_rb(i,RB_OUT_STR, i,str.str()); break; case 2: - str << i << " - " << town->spec_strs[i].substr(0,30); + str << i << " - " << town->get_special_string(i).substr(0,30); set_rb(i,RB_TOWN_STR, i,str.str()); break; case 3: diff --git a/src/scenedit/scen.fileio.cpp b/src/scenedit/scen.fileio.cpp index 6bb88e9a..f9d4d3b3 100644 --- a/src/scenedit/scen.fileio.cpp +++ b/src/scenedit/scen.fileio.cpp @@ -227,7 +227,7 @@ void writeScenarioToXml(ticpp::Printer&& data, cScenario& scenario) { data.CloseElement("quest"); } for(size_t i = 0; i < scenario.shops.size(); i++) { - cShop& shop = scenario.shops[i]; + cShop const &shop = scenario.shops[i]; data.OpenElement("shop"); data.PushElement("name", shop.getName()); data.PushElement("type", shop.getType()); diff --git a/src/scenedit/scen.keydlgs.cpp b/src/scenedit/scen.keydlgs.cpp index e4ee3dc9..cce0d1d1 100644 --- a/src/scenedit/scen.keydlgs.cpp +++ b/src/scenedit/scen.keydlgs.cpp @@ -68,9 +68,9 @@ static void ensure_str(eStrMode str_mode, size_t which) { static std::string& fetch_str(eStrMode str_mode, size_t which) { ensure_str(str_mode, which); switch(str_mode) { - case 0: return scenario.spec_strs[which]; - case 1: return current_terrain->spec_strs[which]; - case 2: return town->spec_strs[which]; + case 0: return scenario.get_special_string(which); + case 1: return current_terrain->get_special_string(which); + case 2: return town->get_special_string(which); case 3: return scenario.journal_strs[which]; case 4: return current_terrain->sign_locs[which].text; case 5: return town->sign_locs[which].text; diff --git a/src/universe/party.cpp b/src/universe/party.cpp index f44da926..9236d552 100644 --- a/src/universe/party.cpp +++ b/src/universe/party.cpp @@ -313,11 +313,14 @@ void cParty::import_legacy(legacy::setup_save_type const & old){ } void cParty::cConvers::import_legacy(legacy::talk_save_type const &old, const cScenario& scenario){ - who_said = scenario.towns[old.personality / 10]->talking.people[old.personality % 10].title; + if (old.personality<0) // fixme: add an error message here + return; + cTown const *town=scenario.towns[old.personality/10]; + who_said = town->talking.people[old.personality%10].title; in_town = scenario.towns[old.town_num]->name; - int strnums[2] = {old.str1, old.str2}; - std::string* strs[2] = {&the_str1, &the_str2}; for(int i = 0; i < 2; i++) { + int num=i==0 ? old.str1 : old.str2; + std::string &str=i==0 ? the_str1 : the_str2; // Okay, so there's a ton of different places where the actual strings might be found. // 0 means no string // 10 + n is the "look" string for the nth personality in the town (ie, n is personality % 10) @@ -327,21 +330,21 @@ void cParty::cConvers::import_legacy(legacy::talk_save_type const &old, const cS // 40 + 2n + 1 is the second string from the nth talk not in the town // 2000 + n is the nth town special text // 3000 + n is the nth scenario special text - if(strnums[i] == 0) continue; - if(strnums[i] >= 3000) - strs[i]->assign(scenario.spec_strs[strnums[i] - 3000]); - else if(strnums[i] >= 2000) - strs[i]->assign(scenario.towns[old.personality / 10]->spec_strs[strnums[i] - 2000]); - else if(strnums[i] >= 40 && strnums[i] % 2 == 0) - strs[i]->assign(scenario.towns[old.personality / 10]->talking.talk_nodes[(strnums[i] - 40) / 2].str1); - else if(strnums[i] >= 40 && strnums[i] % 2 == 1) - strs[i]->assign(scenario.towns[old.personality / 10]->talking.talk_nodes[(strnums[i] - 40) / 2].str2); - else if(strnums[i] >= 30) - strs[i]->assign(scenario.towns[old.personality / 10]->talking.people[old.personality % 10].job); - else if(strnums[i] >= 20) - strs[i]->assign(scenario.towns[old.personality / 10]->talking.people[old.personality % 10].name); - else if(strnums[i] >= 10) - strs[i]->assign(scenario.towns[old.personality / 10]->talking.people[old.personality % 10].look); + if(num == 0) continue; + if(num >= 3000) + str.assign(scenario.get_special_string(num - 3000)); + else if(num >= 2000) + str.assign(town->get_special_string(num - 2000)); + else if(num >= 40 && num % 2 == 0) + str.assign(town->talking.talk_nodes[(num - 40) / 2].str1); + else if(num >= 40 && num % 2 == 1) + str.assign(town->talking.talk_nodes[(num - 40) / 2].str2); + else if(num >= 30) + str.assign(town->talking.people[num-30].job); + else if(num >= 20) + str.assign(town->talking.people[num-20].name); + else if(num >= 10) + str.assign(town->talking.people[num-10].look); } } @@ -350,17 +353,17 @@ void cParty::cEncNote::import_legacy(int16_t const (& old)[2], const cScenario& // TODO: Need to verify that I have the correct offsets here. switch(old[0] / 1000) { case 0: - the_str = scenario.spec_strs[old[0] - 160]; + the_str = scenario.get_special_string(old[0] - 160); where = scenario.scen_name; // Best we can do here; the actual location is long forgotten type = NOTE_SCEN; break; case 1: - the_str = scenario.outdoors[old[1] % scenario.outdoors.width()][old[1] / scenario.outdoors.width()]->spec_strs[old[0] - 1010]; + the_str = scenario.outdoors[old[1] % scenario.outdoors.width()][old[1] / scenario.outdoors.width()]->get_special_string(old[0] - 1010); where = scenario.outdoors[old[1] % scenario.outdoors.width()][old[1] / scenario.outdoors.width()]->name; type = NOTE_OUT; break; case 2: - the_str = scenario.towns[old[1]]->spec_strs[old[0] - 2020]; + the_str = scenario.towns[old[1]]->get_special_string(old[0] - 2020); where = scenario.towns[old[1]]->name; type= NOTE_TOWN; break;