1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-07 03:12:36 +01:00

config: fix reading of illegal values

The parser would crash when trying to convert e.g. "d" to an integer.
This commit is contained in:
Anonymous Maarten 2017-02-17 19:19:02 +01:00 committed by Daniel Evans
parent fe156e2984
commit 90001b11ac
2 changed files with 54 additions and 33 deletions

View File

@ -70,10 +70,10 @@ struct StringTranslator {
typedef std::string internal_type; typedef std::string internal_type;
typedef std::string external_type; typedef std::string external_type;
boost::optional<external_type> get_value(const internal_type &str) { boost::optional<external_type> get_value(const internal_type &str) {
return boost::optional<external_type>(stripComments(str)); return stripComments(str);
} }
boost::optional<internal_type> put_value(const external_type &str) { boost::optional<internal_type> put_value(const external_type &str) {
return boost::optional<internal_type>(str); return str;
} }
}; };
@ -81,10 +81,15 @@ struct BoolTranslator {
typedef std::string internal_type; typedef std::string internal_type;
typedef bool external_type; typedef bool external_type;
boost::optional<external_type> get_value(const internal_type &str) { boost::optional<external_type> get_value(const internal_type &str) {
return boost::optional<external_type>(std::stoi(stripComments(str)) != 0); boost::optional<external_type> res;
try {
res = std::stoi(stripComments(str)) != 0;
} catch (std::invalid_argument &e) {
}
return res;
} }
boost::optional<internal_type> put_value(const external_type &b) { boost::optional<internal_type> put_value(const external_type &b) {
return boost::optional<internal_type>(b ? "1" : "0"); return internal_type(b ? "1" : "0");
} }
}; };
@ -92,7 +97,12 @@ struct IntTranslator {
typedef std::string internal_type; typedef std::string internal_type;
typedef int external_type; typedef int external_type;
boost::optional<external_type> get_value(const internal_type &str) { boost::optional<external_type> get_value(const internal_type &str) {
return boost::optional<external_type>(std::stoi(stripComments(str))); boost::optional<external_type> res;
try {
res = std::stoi(stripComments(str));
} catch (std::invalid_argument &e) {
}
return res;
} }
boost::optional<internal_type> put_value(const external_type &i) { boost::optional<internal_type> put_value(const external_type &i) {
return boost::optional<internal_type>(std::to_string(i)); return boost::optional<internal_type>(std::to_string(i));
@ -125,10 +135,16 @@ bool GameConfig::parseConfig(
pt::read_ini(ifs, srcTree); pt::read_ini(ifs, srcTree);
} }
} catch (pt::ini_parser_error &e) { } catch (pt::ini_parser_error &e) {
// Catches illegal input files (nonsensical input, duplicate keys)
RW_MESSAGE(e.what()); RW_MESSAGE(e.what());
return false; return false;
} }
if (destType == ParseType::DEFAULT) {
RW_ERROR("Target cannot be DEFAULT.");
return false;
}
bool success = true; bool success = true;
auto read_config = [&](const std::string &key, auto &target, auto read_config = [&](const std::string &key, auto &target,
@ -150,13 +166,19 @@ bool GameConfig::parseConfig(
try { try {
sourceValue = srcTree.get<config_t>(key, translator); sourceValue = srcTree.get<config_t>(key, translator);
} catch (pt::ptree_bad_path &e) { } catch (pt::ptree_bad_path &e) {
if (optional) { // Catches missing key-value pairs: fail when required
sourceValue = defaultValue; if (!optional) {
} else {
success = false; success = false;
RW_MESSAGE(e.what()); RW_MESSAGE(e.what());
return; return;
} }
sourceValue = defaultValue;
} catch (pt::ptree_bad_data &e) {
// Catches illegal value data: always fail
success = false;
RW_MESSAGE("invalid data");
RW_MESSAGE(e.what());
return;
} }
break; break;
} }
@ -164,7 +186,7 @@ bool GameConfig::parseConfig(
switch (destType) { switch (destType) {
case ParseType::DEFAULT: case ParseType::DEFAULT:
RW_ERROR("Target cannot be DEFAULT."); // Target cannot be DEFAULT (case already handled)
success = false; success = false;
break; break;
case ParseType::CONFIG: case ParseType::CONFIG:
@ -192,32 +214,18 @@ bool GameConfig::parseConfig(
if (!success) if (!success)
return success; return success;
if ((destType == ParseType::STRING) || (destType == ParseType::FILE)) {
std::ostringstream ostream;
try { try {
if (destType == ParseType::STRING) {
std::ostringstream ostream;
pt::write_ini(ostream, srcTree); pt::write_ini(ostream, srcTree);
destination = ostream.str();
} else if (destType == ParseType::FILE) {
pt::write_ini(destination, srcTree);
}
} catch (pt::ini_parser_error &e) { } catch (pt::ini_parser_error &e) {
success = false; success = false;
RW_MESSAGE(e.what()); RW_MESSAGE(e.what());
} }
switch (destType) {
case ParseType::STRING:
destination = ostream.str();
break;
case ParseType::FILE:
{
std::ofstream ofs(destination);
ofs << ostream.str();
ofs.close();
success &= !ofs.fail();
break;
}
default:
//Cannot reach here
success = false;
break;
}
}
return success; return success;
} }

View File

@ -168,6 +168,19 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_required_missing) {
BOOST_CHECK(!config.isValid()); BOOST_CHECK(!config.isValid());
} }
BOOST_AUTO_TEST_CASE(test_config_invalid_wrong_type) {
// Test wrong data type
auto cfg = getValidConfig();
cfg["input"]["invert_y"]="d";
TempFile tempFile;
tempFile.write(cfg);
GameConfig config(tempFile.filename(), tempFile.dirname());
BOOST_CHECK(!config.isValid());
}
BOOST_AUTO_TEST_CASE(test_config_invalid_empty) { BOOST_AUTO_TEST_CASE(test_config_invalid_empty) {
// Test reading empty configuration file // Test reading empty configuration file