mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Masterlist update now only tests condition parsing.
Instead of evaluating the conditions, and modifying the data stored in the masterlist object. This will probably also speed up masterlist updating a little. Fixes #257.
This commit is contained in:
+3
-6
@@ -424,17 +424,14 @@ namespace loot {
|
||||
try {
|
||||
this->MetadataList::Load(game.MasterlistPath());
|
||||
|
||||
unordered_set<Plugin> tempSet;
|
||||
for (auto &plugin : plugins) {
|
||||
tempSet.insert(Plugin(plugin).EvalAllConditions(game, language));
|
||||
plugin.ParseAllConditions(game);
|
||||
}
|
||||
plugins = tempSet;
|
||||
for (auto &plugin : regexPlugins) {
|
||||
plugin.EvalAllConditions(game, language);
|
||||
plugin.ParseAllConditions(game);
|
||||
}
|
||||
|
||||
for (auto &message: messages) {
|
||||
message.EvalCondition(game, language);
|
||||
message.ParseCondition(game);
|
||||
}
|
||||
|
||||
parsingFailed = false;
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace loot {
|
||||
return _condition;
|
||||
}
|
||||
|
||||
bool ConditionStruct::EvalCondition(loot::Game& game) const {
|
||||
bool ConditionStruct::EvalCondition(Game& game) const {
|
||||
if (_condition.empty())
|
||||
return true;
|
||||
|
||||
@@ -128,12 +128,11 @@ namespace loot {
|
||||
if (it != game.conditionCache.end())
|
||||
return it->second;
|
||||
|
||||
condition_grammar<std::string::const_iterator, boost::spirit::qi::space_type> grammar;
|
||||
condition_grammar<std::string::const_iterator, boost::spirit::qi::space_type> grammar(game, false);
|
||||
boost::spirit::qi::space_type skipper;
|
||||
std::string::const_iterator begin, end;
|
||||
bool eval;
|
||||
|
||||
grammar.SetGame(game);
|
||||
begin = _condition.begin();
|
||||
end = _condition.end();
|
||||
|
||||
@@ -155,6 +154,39 @@ namespace loot {
|
||||
return eval;
|
||||
}
|
||||
|
||||
void ConditionStruct::ParseCondition(Game& game) const {
|
||||
if (_condition.empty())
|
||||
return;
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Testing condition syntax: " << _condition;
|
||||
|
||||
// If the same condition string has already been evaluated, it must be written correctly.
|
||||
unordered_map<std::string, bool>::const_iterator it = game.conditionCache.find(boost::locale::to_lower(_condition));
|
||||
if (it != game.conditionCache.end())
|
||||
return;
|
||||
|
||||
condition_grammar<std::string::const_iterator, boost::spirit::qi::space_type> grammar(game, true);
|
||||
boost::spirit::qi::space_type skipper;
|
||||
std::string::const_iterator begin, end;
|
||||
|
||||
begin = _condition.begin();
|
||||
end = _condition.end();
|
||||
|
||||
bool r;
|
||||
try {
|
||||
r = boost::spirit::qi::phrase_parse(begin, end, grammar, skipper);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to parse condition \"" << _condition << "\": " << e.what();
|
||||
throw loot::error(loot::error::condition_eval_fail, (boost::format(lc::translate("Failed to parse condition \"%1%\": %2%")) % _condition % e.what()).str());
|
||||
}
|
||||
|
||||
if (!r || begin != end) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to parse condition \"" << _condition << "\".";
|
||||
throw loot::error(loot::error::condition_eval_fail, (boost::format(lc::translate("Failed to parse condition \"%1%\".")) % _condition).str());
|
||||
}
|
||||
}
|
||||
|
||||
MessageContent::MessageContent() : _language(Language::english) {}
|
||||
|
||||
MessageContent::MessageContent(const std::string& str, const unsigned int language) : _str(str), _language(language) {}
|
||||
@@ -574,7 +606,7 @@ namespace loot {
|
||||
_dirtyInfo = dirtyInfo;
|
||||
}
|
||||
|
||||
Plugin& Plugin::EvalAllConditions(loot::Game& game, const unsigned int language) {
|
||||
Plugin& Plugin::EvalAllConditions(Game& game, const unsigned int language) {
|
||||
for (auto it = loadAfter.begin(); it != loadAfter.end();) {
|
||||
if (!it->EvalCondition(game))
|
||||
loadAfter.erase(it++);
|
||||
@@ -634,6 +666,24 @@ namespace loot {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Plugin::ParseAllConditions(Game& game) const {
|
||||
for (const File& file : loadAfter) {
|
||||
file.ParseCondition(game);
|
||||
}
|
||||
for (const File& file : requirements) {
|
||||
file.ParseCondition(game);
|
||||
}
|
||||
for (const File& file : incompatibilities) {
|
||||
file.ParseCondition(game);
|
||||
}
|
||||
for (const Message& message : messages) {
|
||||
message.ParseCondition(game);
|
||||
}
|
||||
for (const Tag& tag : tags) {
|
||||
tag.ParseCondition(game);
|
||||
}
|
||||
}
|
||||
|
||||
bool Plugin::HasNameOnly() const {
|
||||
return !IsPriorityExplicit() && loadAfter.empty() && requirements.empty() && incompatibilities.empty() && messages.empty() && tags.empty() && _dirtyInfo.empty();
|
||||
}
|
||||
|
||||
@@ -83,7 +83,8 @@ namespace loot {
|
||||
ConditionStruct(const std::string& condition);
|
||||
|
||||
bool IsConditional() const;
|
||||
bool EvalCondition(loot::Game& game) const;
|
||||
bool EvalCondition(Game& game) const;
|
||||
void ParseCondition(Game& game) const; // Throws error on parsing failure.
|
||||
|
||||
std::string Condition() const;
|
||||
private:
|
||||
@@ -116,7 +117,7 @@ namespace loot {
|
||||
bool operator < (const Message& rhs) const;
|
||||
bool operator == (const Message& rhs) const;
|
||||
|
||||
bool EvalCondition(loot::Game& game, const unsigned int language);
|
||||
bool EvalCondition(Game& game, const unsigned int language);
|
||||
|
||||
unsigned int Type() const;
|
||||
std::vector<MessageContent> Content() const;
|
||||
@@ -166,7 +167,7 @@ namespace loot {
|
||||
public:
|
||||
Plugin();
|
||||
Plugin(const std::string& name);
|
||||
Plugin(loot::Game& game, const std::string& name, const bool headerOnly);
|
||||
Plugin(Game& game, const std::string& name, const bool headerOnly);
|
||||
|
||||
//Merges from the given plugin into this one, unless there is already equal metadata present.
|
||||
//For 'enabled' and 'priority' metadata, use the given plugin's values, but if the 'priority' user value is zero, ignore it.
|
||||
@@ -204,7 +205,8 @@ namespace loot {
|
||||
void Tags(const std::set<Tag>& tags);
|
||||
void DirtyInfo(const std::set<PluginDirtyInfo>& info);
|
||||
|
||||
Plugin& EvalAllConditions(loot::Game& game, const unsigned int language);
|
||||
Plugin& EvalAllConditions(Game& game, const unsigned int language);
|
||||
void ParseAllConditions(Game& game) const;
|
||||
bool HasNameOnly() const;
|
||||
bool IsRegexPlugin() const;
|
||||
bool LoadsBSA(const Game& game) const;
|
||||
|
||||
+27
-19
@@ -400,7 +400,7 @@ namespace loot {
|
||||
template<typename Iterator, typename Skipper>
|
||||
class condition_grammar : public qi::grammar<Iterator, bool(), Skipper> {
|
||||
public:
|
||||
condition_grammar() : condition_grammar::base_type(expression, "condition grammar") {
|
||||
condition_grammar(Game& game, bool parseOnly) : condition_grammar::base_type(expression, "condition grammar"), _game(game), _parseOnly(parseOnly) {
|
||||
|
||||
expression =
|
||||
compound [qi::labels::_val = qi::labels::_1]
|
||||
@@ -468,19 +468,18 @@ namespace loot {
|
||||
qi::on_error<qi::fail>(invalidPathChars, phoenix::bind(&condition_grammar::SyntaxError, this, qi::labels::_1, qi::labels::_2, qi::labels::_3, qi::labels::_4));
|
||||
}
|
||||
|
||||
void SetGame(loot::Game& g) {
|
||||
game = &g;
|
||||
}
|
||||
|
||||
private:
|
||||
qi::rule<Iterator, bool(), Skipper> expression, compound, condition, function;
|
||||
qi::rule<Iterator, std::string()> quotedStr, filePath, comparator;
|
||||
qi::rule<Iterator, char()> invalidPathChars;
|
||||
|
||||
loot::Game * game;
|
||||
Game& _game;
|
||||
bool _parseOnly;
|
||||
|
||||
//Eval's exact paths. Check for files and ghosted plugins.
|
||||
void CheckFile(bool& result, const std::string& file) {
|
||||
if (_parseOnly)
|
||||
return;
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking to see if the file \"" << file << "\" exists.";
|
||||
|
||||
@@ -495,9 +494,9 @@ namespace loot {
|
||||
}
|
||||
|
||||
if (IsPlugin(file))
|
||||
result = boost::filesystem::exists(game->DataPath() / file) || boost::filesystem::exists(game->DataPath() / (file + ".ghost"));
|
||||
result = boost::filesystem::exists(_game.DataPath() / file) || boost::filesystem::exists(_game.DataPath() / (file + ".ghost"));
|
||||
else
|
||||
result = boost::filesystem::exists(game->DataPath() / file);
|
||||
result = boost::filesystem::exists(_game.DataPath() / file);
|
||||
|
||||
if (result)
|
||||
BOOST_LOG_TRIVIAL(trace) << "The file does exist.";
|
||||
@@ -506,6 +505,8 @@ namespace loot {
|
||||
}
|
||||
|
||||
void CheckRegex(bool& result, const std::string& regexStr) {
|
||||
if (_parseOnly)
|
||||
return;
|
||||
result = false;
|
||||
//Can't support a regex string where all path components may be regex, since this could
|
||||
//lead to massive scanning if an unfortunately-named directory is encountered.
|
||||
@@ -549,7 +550,7 @@ namespace loot {
|
||||
//Now we have a valid parent path and a regex filename. Check that
|
||||
//the parent path exists and is a directory.
|
||||
|
||||
boost::filesystem::path parent_path = game->DataPath() / parent;
|
||||
boost::filesystem::path parent_path = _game.DataPath() / parent;
|
||||
if (!boost::filesystem::exists(parent_path) || !boost::filesystem::is_directory(parent_path)) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "The path \"" << parent_path << "\" does not exist or is not a directory.";
|
||||
return;
|
||||
@@ -573,6 +574,8 @@ namespace loot {
|
||||
}
|
||||
|
||||
void CheckSum(bool& result, const std::string& file, const uint32_t checksum) {
|
||||
if (_parseOnly)
|
||||
return;
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking the CRC of the file \"" << file << "\".";
|
||||
|
||||
@@ -582,29 +585,31 @@ namespace loot {
|
||||
}
|
||||
|
||||
uint32_t crc;
|
||||
unordered_map<std::string,uint32_t>::iterator it = game->crcCache.find(boost::to_lower_copy(file));
|
||||
unordered_map<std::string,uint32_t>::iterator it = _game.crcCache.find(boost::to_lower_copy(file));
|
||||
|
||||
if (it != game->crcCache.end())
|
||||
if (it != _game.crcCache.end())
|
||||
crc = it->second;
|
||||
else {
|
||||
if (file == "LOOT")
|
||||
crc = GetCrc32(boost::filesystem::absolute("LOOT.exe"));
|
||||
if (boost::filesystem::exists(game->DataPath() / file))
|
||||
crc = GetCrc32(game->DataPath() / file);
|
||||
else if (IsPlugin(file) && boost::filesystem::exists(game->DataPath() / (file + ".ghost")))
|
||||
crc = GetCrc32(game->DataPath() / (file + ".ghost"));
|
||||
if (boost::filesystem::exists(_game.DataPath() / file))
|
||||
crc = GetCrc32(_game.DataPath() / file);
|
||||
else if (IsPlugin(file) && boost::filesystem::exists(_game.DataPath() / (file + ".ghost")))
|
||||
crc = GetCrc32(_game.DataPath() / (file + ".ghost"));
|
||||
else {
|
||||
result = false;
|
||||
return;
|
||||
}
|
||||
|
||||
game->crcCache.emplace(boost::to_lower_copy(file), crc);
|
||||
_game.crcCache.emplace(boost::to_lower_copy(file), crc);
|
||||
}
|
||||
|
||||
result = checksum == crc;
|
||||
}
|
||||
|
||||
void CheckVersion(bool& result, const std::string& file, const std::string& version, const std::string& comparator) {
|
||||
if (_parseOnly)
|
||||
return;
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking version of file \"" << file << "\".";
|
||||
|
||||
@@ -621,10 +626,10 @@ namespace loot {
|
||||
if (file == "LOOT")
|
||||
trueVersion = Version(boost::filesystem::absolute("LOOT.exe"));
|
||||
else if (IsPlugin(file)) {
|
||||
Plugin plugin(*game, file, true);
|
||||
Plugin plugin(_game, file, true);
|
||||
trueVersion = Version(plugin.Version());
|
||||
} else
|
||||
trueVersion = Version(game->DataPath() / file);
|
||||
trueVersion = Version(_game.DataPath() / file);
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Version extracted: " << trueVersion.AsString();
|
||||
|
||||
@@ -640,10 +645,13 @@ namespace loot {
|
||||
}
|
||||
|
||||
void CheckActive(bool& result, const std::string& file) {
|
||||
if (_parseOnly)
|
||||
return;
|
||||
|
||||
if (file == "LOOT")
|
||||
result = false;
|
||||
else
|
||||
result = game->IsActive(file);
|
||||
result = _game.IsActive(file);
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Active check result: " << result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user