add methods get_special_string to check access bounds of spec_strs...

This commit is contained in:
ALONSO Laurent
2021-10-22 13:39:28 +02:00
committed by Celtic Minstrel
parent 0c269c420c
commit a51ba34650
16 changed files with 143 additions and 67 deletions

View File

@@ -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<std::string> reqs = {"title", "look", "name", "job"};
Iterator<Element> 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;
}

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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.");

View File

@@ -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());

View File

@@ -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

View File

@@ -17,6 +17,27 @@
#include "oldstructs.hpp"
#include "scenario.hpp"
std::string &cOutdoors::get_special_string(int id)
{
if (id>=0 && id<spec_strs.size())
return spec_strs[id];
if (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<spec_strs.size())
return spec_strs[id];
static std::string badString="Bad Special String";
return badString;
}
void cOutdoors::import_legacy(legacy::outdoor_record_type const &old){
ambient_sound = AMBIENT_NONE;
// Collect a list of unused special nodes, to be used for fixing specials that could be triggered in a boat.

View File

@@ -74,6 +74,9 @@ public:
explicit cOutdoors(cScenario& scenario);
void import_legacy(legacy::outdoor_record_type const &old);
void reattach(cScenario& to);
std::string &get_special_string(int id);
std::string const &get_special_string(int id) const;
};
#endif

View File

@@ -303,12 +303,34 @@ cShop &cScenario::get_shop(int shop)
return badShop;
}
std::string &cScenario::get_special_string(int id)
{
if (id>=0 && id<spec_strs.size())
return spec_strs[id];
if (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<spec_strs.size())
return spec_strs[id];
static std::string badString="Bad Special String";
return badString;
}
static cTerrain getBadTerrain() {
cTerrain badTerrain;
badTerrain.picture = -3;
badTerrain.map_pic = -3;
return badTerrain;
}
cTerrain const &cScenario::get_terrain(ter_num_t ter) const
{
if (ter<ter_types.size())

View File

@@ -58,6 +58,8 @@ public:
cSpecItem &get_special_item(item_num_t item);
cShop const &get_shop(int shop) const;
cShop &get_shop(int shop);
std::string &get_special_string(int id);
std::string const &get_special_string(int id) const;
cTerrain const &get_terrain(ter_num_t ter) const;
cTerrain &get_terrain(ter_num_t ter);

View File

@@ -128,6 +128,27 @@ void cTown::init_start() {
in_town_rect.right = s - 4;
}
std::string &cTown::get_special_string(int id)
{
if (id>=0 && id<spec_strs.size())
return spec_strs[id];
if (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 && id<spec_strs.size())
return spec_strs[id];
static std::string badString="Bad Special String";
return badString;
}
void cTown::cWandering::import_legacy(legacy::wandering_type const &old){
monst[0] = old.monst[0];
monst[1] = old.monst[1];

View File

@@ -119,6 +119,8 @@ public:
bool is_item_taken(size_t i) const;
void clear_items_taken();
void set_item_taken(size_t i, bool val = true);
std::string &get_special_string(int id);
std::string const &get_special_string(int id) const;
};
std::ostream& operator<< (std::ostream& out, eLighting light);

View File

@@ -446,11 +446,11 @@ static bool handle_rb_action(location the_point, bool option_hit) {
scenario.spec_strs.pop_back();
else if(j == size_before)
scenario.spec_strs.resize(size_before + 8, "*");
else scenario.spec_strs[j] = "*";
else scenario.get_special_string(j) = "*";
} else {
if(j == size_before)
scenario.spec_strs.emplace_back("*");
if(!edit_text_str(j,STRS_SCEN) && j == size_before && scenario.spec_strs[j] == "*")
if(!edit_text_str(j,STRS_SCEN) && j == size_before && scenario.get_special_string(j) == "*")
scenario.spec_strs.pop_back();
}
start_string_editing(STRS_SCEN,size_before == scenario.spec_strs.size());
@@ -465,11 +465,11 @@ static bool handle_rb_action(location the_point, bool option_hit) {
current_terrain->spec_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:

View File

@@ -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());

View File

@@ -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;

View File

@@ -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;