Merge pull request #614 from jpcima/reloading

Avoid reloading invalid files in a loop
This commit is contained in:
JP Cimalando 2021-02-01 16:40:05 +01:00 committed by GitHub
commit 872bc69b1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 29 deletions

View file

@ -35,6 +35,9 @@
namespace sfz { namespace sfz {
// unless set to permissive, the loader rejects sfz files with errors
static constexpr bool loaderParsesPermissively = true;
Synth::Synth() Synth::Synth()
: impl_(new Impl) // NOLINT: (paul) I don't get why clang-tidy complains here : impl_(new Impl) // NOLINT: (paul) I don't get why clang-tidy complains here
{ {
@ -252,7 +255,7 @@ void Synth::Impl::clear()
masterOpcodes_.clear(); masterOpcodes_.clear();
groupOpcodes_.clear(); groupOpcodes_.clear();
unknownOpcodes_.clear(); unknownOpcodes_.clear();
modificationTime_ = fs::file_time_type::min(); modificationTime_ = absl::nullopt;
// set default controllers // set default controllers
// midistate is reset above // midistate is reset above
@ -493,18 +496,22 @@ bool Synth::loadSfzFile(const fs::path& file)
std::error_code ec; std::error_code ec;
fs::path realFile = fs::canonical(file, ec); fs::path realFile = fs::canonical(file, ec);
impl.parser_.parseFile(ec ? file : realFile); bool success = true;
Parser& parser = impl.parser_;
parser.parseFile(ec ? file : realFile);
// permissive parsing for compatibility // permissive parsing for compatibility
if (false) { if (!loaderParsesPermissively)
if (impl.parser_.getErrorCount() > 0) success = parser.getErrorCount() == 0;
return false;
success = success && !impl.regions_.empty();
if (!success) {
parser.clear();
return false;
} }
if (impl.regions_.empty())
return false;
impl.finalizeSfzLoad(); impl.finalizeSfzLoad();
return true; return true;
} }
@ -515,18 +522,22 @@ bool Synth::loadSfzString(const fs::path& path, absl::string_view text)
impl.clear(); impl.clear();
impl.parser_.parseString(path, text); bool success = true;
Parser& parser = impl.parser_;
parser.parseString(path, text);
// permissive parsing for compatibility // permissive parsing for compatibility
if (false) { if (!loaderParsesPermissively)
if (impl.parser_.getErrorCount() > 0) success = parser.getErrorCount() == 0;
return false;
success = success && !impl.regions_.empty();
if (!success) {
parser.clear();
return false;
} }
if (impl.regions_.empty())
return false;
impl.finalizeSfzLoad(); impl.finalizeSfzLoad();
return true; return true;
} }
@ -1668,22 +1679,33 @@ void Synth::Impl::resetAllControllers(int delay) noexcept
} }
} }
fs::file_time_type Synth::Impl::checkModificationTime() absl::optional<fs::file_time_type> Synth::Impl::checkModificationTime() const
{ {
auto returnedTime = modificationTime_; absl::optional<fs::file_time_type> resultTime;
for (const auto& file : parser_.getIncludedFiles()) { for (const auto& file : parser_.getIncludedFiles()) {
std::error_code ec; std::error_code ec;
const auto fileTime = fs::last_write_time(file, ec); const auto fileTime = fs::last_write_time(file, ec);
if (!ec && returnedTime < fileTime) if (!ec) {
returnedTime = fileTime; if (!resultTime || fileTime > *resultTime)
resultTime = fileTime;
}
} }
return returnedTime; return resultTime;
} }
bool Synth::shouldReloadFile() bool Synth::shouldReloadFile()
{ {
Impl& impl = *impl_; Impl& impl = *impl_;
return (impl.checkModificationTime() > impl.modificationTime_);
absl::optional<fs::file_time_type> then = impl.modificationTime_;
if (!then) // file not loaded or failed
return false;
absl::optional<fs::file_time_type> now = impl.checkModificationTime();
if (!now) // file not currently existing
return false;
return *now > *then;
} }
bool Synth::shouldReloadScala() bool Synth::shouldReloadScala()

View file

@ -110,9 +110,9 @@ struct Synth::Impl final: public Parser::Listener {
/** /**
* @brief Get the modification time of all included sfz files * @brief Get the modification time of all included sfz files
* *
* @return fs::file_time_type * @return absl::optional<fs::file_time_type>
*/ */
fs::file_time_type checkModificationTime(); absl::optional<fs::file_time_type> checkModificationTime() const;
/** /**
* @brief Check all regions and start voices for note on events * @brief Check all regions and start voices for note on events
@ -277,7 +277,7 @@ struct Synth::Impl final: public Parser::Listener {
std::chrono::time_point<std::chrono::high_resolution_clock> lastGarbageCollection_; std::chrono::time_point<std::chrono::high_resolution_clock> lastGarbageCollection_;
Parser parser_; Parser parser_;
fs::file_time_type modificationTime_ { }; absl::optional<fs::file_time_type> modificationTime_ { };
std::array<float, config::numCCs> defaultCCValues_; std::array<float, config::numCCs> defaultCCValues_;
std::bitset<config::numCCs> currentUsedCCs_; std::bitset<config::numCCs> currentUsedCCs_;

View file

@ -19,7 +19,7 @@ Parser::~Parser()
{ {
} }
void Parser::reset() void Parser::clear()
{ {
_pathsIncluded.clear(); _pathsIncluded.clear();
_currentDefinitions = _externalDefinitions; _currentDefinitions = _externalDefinitions;
@ -51,7 +51,7 @@ void Parser::parseString(const fs::path& path, absl::string_view sfzView)
void Parser::parseVirtualFile(const fs::path& path, std::unique_ptr<Reader> reader) void Parser::parseVirtualFile(const fs::path& path, std::unique_ptr<Reader> reader)
{ {
reset(); clear();
if (_listener) if (_listener)
_listener->onParseBegin(); _listener->onParseBegin();

View file

@ -27,6 +27,8 @@ public:
Parser(); Parser();
~Parser(); ~Parser();
void clear();
void addExternalDefinition(absl::string_view id, absl::string_view value); void addExternalDefinition(absl::string_view id, absl::string_view value);
void clearExternalDefinitions(); void clearExternalDefinitions();
@ -71,7 +73,6 @@ private:
void processDirective(); void processDirective();
void processHeader(); void processHeader();
void processOpcode(); void processOpcode();
void reset();
// errors and warnings // errors and warnings
void emitError(const SourceRange& range, const std::string& message); void emitError(const SourceRange& range, const std::string& message);