mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 15:30:00 +01:00
BugFix: interrupting recursive session loading
Prevent crash on recursive (infinite) loading of session file (containing itself).
This commit is contained in:
@@ -948,7 +948,7 @@ void Mixer::load(const std::string& filename)
|
|||||||
if (sessionLoaders_.empty()) {
|
if (sessionLoaders_.empty()) {
|
||||||
// Start async thread for loading the session
|
// Start async thread for loading the session
|
||||||
// Will be obtained in the future in update()
|
// Will be obtained in the future in update()
|
||||||
sessionLoaders_.emplace_back( std::async(std::launch::async, Session::load, filename) );
|
sessionLoaders_.emplace_back( std::async(std::launch::async, Session::load, filename, 0) );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
set( Session::load(filename) );
|
set( Session::load(filename) );
|
||||||
@@ -986,7 +986,7 @@ void Mixer::import(const std::string& filename)
|
|||||||
if (sessionImporters_.empty()) {
|
if (sessionImporters_.empty()) {
|
||||||
// Start async thread for loading the session
|
// Start async thread for loading the session
|
||||||
// Will be obtained in the future in update()
|
// Will be obtained in the future in update()
|
||||||
sessionImporters_.emplace_back( std::async(std::launch::async, Session::load, filename) );
|
sessionImporters_.emplace_back( std::async(std::launch::async, Session::load, filename, 0) );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
merge( Session::load(filename) );
|
merge( Session::load(filename) );
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "SearchVisitor.h"
|
#include "SearchVisitor.h"
|
||||||
|
|
||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
|
#include "MediaSource.h"
|
||||||
|
#include "Session.h"
|
||||||
|
#include "SessionSource.h"
|
||||||
|
|
||||||
SearchVisitor::SearchVisitor(Node *node) : Visitor(), node_(node), found_(false)
|
SearchVisitor::SearchVisitor(Node *node) : Visitor(), node_(node), found_(false)
|
||||||
{
|
{
|
||||||
@@ -42,12 +47,11 @@ void SearchVisitor::visit(Scene &n)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
SearchFileVisitor::SearchFileVisitor(std::string filename) : Visitor(), filename_(filename), found_(false)
|
SearchFileVisitor::SearchFileVisitor() : Visitor()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SearchFileVisitor::visit(Node &n)
|
void SearchFileVisitor::visit(Node &n)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -55,13 +59,8 @@ void SearchFileVisitor::visit(Node &n)
|
|||||||
|
|
||||||
void SearchFileVisitor::visit(Group &n)
|
void SearchFileVisitor::visit(Group &n)
|
||||||
{
|
{
|
||||||
if (found_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
|
for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
|
||||||
(*node)->accept(*this);
|
(*node)->accept(*this);
|
||||||
if (found_)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,10 +80,29 @@ void SearchFileVisitor::visit(Scene &n)
|
|||||||
|
|
||||||
void SearchFileVisitor::visit (MediaSource& s)
|
void SearchFileVisitor::visit (MediaSource& s)
|
||||||
{
|
{
|
||||||
|
filenames_.push_back( s.path() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchFileVisitor::visit (SessionFileSource& s)
|
void SearchFileVisitor::visit (SessionFileSource& s)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
filenames_.push_back( s.path() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<std::string> SearchFileVisitor::parse (Session *se)
|
||||||
|
{
|
||||||
|
SearchFileVisitor sv;
|
||||||
|
|
||||||
|
for (auto iter = se->begin(); iter != se->end(); iter++){
|
||||||
|
(*iter)->accept(sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sv.filenames();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchFileVisitor::find (Session *se, std::string path)
|
||||||
|
{
|
||||||
|
std::list<std::string> filenames = parse (se);
|
||||||
|
return std::find(filenames.begin(), filenames.end(), path) != filenames.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#ifndef SEARCHVISITOR_H
|
#ifndef SEARCHVISITOR_H
|
||||||
#define SEARCHVISITOR_H
|
#define SEARCHVISITOR_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "Visitor.h"
|
#include "Visitor.h"
|
||||||
|
|
||||||
|
class Session;
|
||||||
|
|
||||||
class SearchVisitor: public Visitor
|
class SearchVisitor: public Visitor
|
||||||
{
|
{
|
||||||
Node *node_;
|
Node *node_;
|
||||||
@@ -15,33 +18,35 @@ public:
|
|||||||
inline Node *node() const { return found_ ? node_ : nullptr; }
|
inline Node *node() const { return found_ ? node_ : nullptr; }
|
||||||
|
|
||||||
// Elements of Scene
|
// Elements of Scene
|
||||||
void visit(Scene& n) override;
|
void visit (Scene& n) override;
|
||||||
void visit(Node& n) override;
|
void visit (Node& n) override;
|
||||||
void visit(Primitive&) override {}
|
void visit (Primitive&) override {}
|
||||||
void visit(Group& n) override;
|
void visit (Group& n) override;
|
||||||
void visit(Switch& n) override;
|
void visit (Switch& n) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SearchFileVisitor: public Visitor
|
class SearchFileVisitor: public Visitor
|
||||||
{
|
{
|
||||||
std::string filename_;
|
std::list<std::string> filenames_;
|
||||||
bool found_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SearchFileVisitor(std::string filename);
|
SearchFileVisitor();
|
||||||
inline bool found() const { return found_; }
|
inline std::list<std::string> filenames() const { return filenames_; }
|
||||||
|
|
||||||
// Elements of Scene
|
// Elements of Scene
|
||||||
void visit(Scene& n) override;
|
void visit (Scene& n) override;
|
||||||
void visit(Node& n) override;
|
void visit (Node& n) override;
|
||||||
void visit(Primitive&) override {}
|
void visit (Primitive&) override {}
|
||||||
void visit(Group& n) override;
|
void visit (Group& n) override;
|
||||||
void visit(Switch& n) override;
|
void visit (Switch& n) override;
|
||||||
|
|
||||||
// Sources
|
// Sources
|
||||||
void visit (MediaSource& s) override;
|
void visit (MediaSource& s) override;
|
||||||
void visit (SessionFileSource& s) override;
|
void visit (SessionFileSource& s) override;
|
||||||
|
|
||||||
|
static std::list<std::string> parse (Session *se);
|
||||||
|
static bool find (Session *se, std::string path);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SEARCHVISITOR_H
|
#endif // SEARCHVISITOR_H
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "FrameBuffer.h"
|
#include "FrameBuffer.h"
|
||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
#include "GarbageVisitor.h"
|
|
||||||
#include "FrameGrabber.h"
|
#include "FrameGrabber.h"
|
||||||
#include "SessionCreator.h"
|
#include "SessionCreator.h"
|
||||||
#include "SessionSource.h"
|
#include "SessionSource.h"
|
||||||
@@ -323,9 +322,9 @@ void Session::unlock()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Session *Session::load(const std::string& filename)
|
Session *Session::load(const std::string& filename, uint recursion)
|
||||||
{
|
{
|
||||||
SessionCreator creator;
|
SessionCreator creator(recursion);
|
||||||
creator.load(filename);
|
creator.load(filename);
|
||||||
|
|
||||||
return creator.session();
|
return creator.session();
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public:
|
|||||||
Session();
|
Session();
|
||||||
~Session();
|
~Session();
|
||||||
|
|
||||||
static Session *load(const std::string& filename);
|
static Session *load(const std::string& filename, uint recursion = 0);
|
||||||
|
|
||||||
// add given source into the session
|
// add given source into the session
|
||||||
SourceList::iterator addSource (Source *s);
|
SourceList::iterator addSource (Source *s);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ std::string SessionCreator::info(const std::string& filename)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionCreator::SessionCreator(): SessionLoader(nullptr)
|
SessionCreator::SessionCreator(uint recursion): SessionLoader(nullptr, recursion)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ void SessionCreator::loadConfig(XMLElement *viewsNode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionLoader::SessionLoader(Session *session): Visitor(), session_(session)
|
SessionLoader::SessionLoader(Session *session, uint recursion): Visitor(), session_(session), recursion_(recursion)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -117,6 +117,11 @@ void SessionLoader::load(XMLElement *sessionNode)
|
|||||||
{
|
{
|
||||||
sources_id_.clear();
|
sources_id_.clear();
|
||||||
|
|
||||||
|
if (recursion_ > MAX_SESSION_LEVEL) {
|
||||||
|
Log::Warning("Recursive or imbricated sessions detected! Interrupting loading after %d iterations.\n", MAX_SESSION_LEVEL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (sessionNode != nullptr && session_ != nullptr) {
|
if (sessionNode != nullptr && session_ != nullptr) {
|
||||||
|
|
||||||
XMLElement* sourceNode = sessionNode->FirstChildElement("Source");
|
XMLElement* sourceNode = sessionNode->FirstChildElement("Source");
|
||||||
@@ -534,11 +539,11 @@ void SessionLoader::visit (SessionFileSource& s)
|
|||||||
XMLElement* pathNode = xmlCurrent_->FirstChildElement("path");
|
XMLElement* pathNode = xmlCurrent_->FirstChildElement("path");
|
||||||
if (pathNode) {
|
if (pathNode) {
|
||||||
std::string path = std::string ( pathNode->GetText() );
|
std::string path = std::string ( pathNode->GetText() );
|
||||||
|
|
||||||
// load only new files
|
// load only new files
|
||||||
if ( path != s.path() )
|
if ( path != s.path() )
|
||||||
s.load(path);
|
s.load(path, recursion_ + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionLoader::visit (SessionGroupSource& s)
|
void SessionLoader::visit (SessionGroupSource& s)
|
||||||
@@ -550,10 +555,9 @@ void SessionLoader::visit (SessionGroupSource& s)
|
|||||||
XMLElement* sessionGroupNode = xmlCurrent_->FirstChildElement("Session");
|
XMLElement* sessionGroupNode = xmlCurrent_->FirstChildElement("Session");
|
||||||
if (sessionGroupNode) {
|
if (sessionGroupNode) {
|
||||||
// load session inside group
|
// load session inside group
|
||||||
SessionLoader grouploader( s.session() );
|
SessionLoader grouploader( s.session(), recursion_ + 1 );
|
||||||
grouploader.load( sessionGroupNode );
|
grouploader.load( sessionGroupNode );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionLoader::visit (RenderSource& s)
|
void SessionLoader::visit (RenderSource& s)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class SessionLoader : public Visitor {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SessionLoader(Session *session);
|
SessionLoader(Session *session, uint recursion = 0);
|
||||||
inline Session *session() const { return session_; }
|
inline Session *session() const { return session_; }
|
||||||
|
|
||||||
void load(tinyxml2::XMLElement *sessionNode);
|
void load(tinyxml2::XMLElement *sessionNode);
|
||||||
@@ -58,6 +58,7 @@ protected:
|
|||||||
tinyxml2::XMLElement *xmlCurrent_;
|
tinyxml2::XMLElement *xmlCurrent_;
|
||||||
Session *session_;
|
Session *session_;
|
||||||
std::list<uint64_t> sources_id_;
|
std::list<uint64_t> sources_id_;
|
||||||
|
uint recursion_;
|
||||||
|
|
||||||
static void XMLToNode(tinyxml2::XMLElement *xml, Node &n);
|
static void XMLToNode(tinyxml2::XMLElement *xml, Node &n);
|
||||||
};
|
};
|
||||||
@@ -69,7 +70,7 @@ class SessionCreator : public SessionLoader {
|
|||||||
void loadConfig(tinyxml2::XMLElement *viewsNode);
|
void loadConfig(tinyxml2::XMLElement *viewsNode);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SessionCreator();
|
SessionCreator(uint recursion = 0);
|
||||||
|
|
||||||
void load(const std::string& filename);
|
void load(const std::string& filename);
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ SessionFileSource::SessionFileSource() : SessionSource(), path_("")
|
|||||||
wait_for_sources_ = false;
|
wait_for_sources_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionFileSource::load(const std::string &p)
|
void SessionFileSource::load(const std::string &p, uint recursion)
|
||||||
{
|
{
|
||||||
path_ = p;
|
path_ = p;
|
||||||
|
|
||||||
@@ -142,10 +142,11 @@ void SessionFileSource::load(const std::string &p)
|
|||||||
if ( path_.empty() ) {
|
if ( path_.empty() ) {
|
||||||
// empty session
|
// empty session
|
||||||
session_ = new Session;
|
session_ = new Session;
|
||||||
|
Log::Warning("Empty Session filename provided.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// launch a thread to load the session file
|
// launch a thread to load the session file
|
||||||
sessionLoader_ = std::async(std::launch::async, Session::load, path_);
|
sessionLoader_ = std::async(std::launch::async, Session::load, path_, recursion);
|
||||||
Log::Notify("Opening %s", p.c_str());
|
Log::Notify("Opening %s", p.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
|
|
||||||
// SessionFile Source specific interface
|
// SessionFile Source specific interface
|
||||||
void load(const std::string &p = "");
|
void load(const std::string &p = "", uint recursion = 0);
|
||||||
|
|
||||||
inline std::string path() const { return path_; }
|
inline std::string path() const { return path_; }
|
||||||
glm::ivec2 icon() const override { return glm::ivec2(2, 16); }
|
glm::ivec2 icon() const override { return glm::ivec2(2, 16); }
|
||||||
|
|||||||
@@ -433,9 +433,10 @@ void SessionVisitor::visit (SessionGroupSource& s)
|
|||||||
XMLElement *rootgroup = xmlDoc_->NewElement("Session");
|
XMLElement *rootgroup = xmlDoc_->NewElement("Session");
|
||||||
xmlCurrent_->InsertEndChild(rootgroup);
|
xmlCurrent_->InsertEndChild(rootgroup);
|
||||||
|
|
||||||
setRoot(rootgroup);
|
for (auto iter = se->begin(); iter != se->end(); iter++){
|
||||||
for (auto iter = se->begin(); iter != se->end(); iter++, setRoot(rootgroup) )
|
setRoot(rootgroup);
|
||||||
(*iter)->accept(*this);
|
(*iter)->accept(*this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define XML_VERSION_MAJOR 0
|
#define XML_VERSION_MAJOR 0
|
||||||
#define XML_VERSION_MINOR 2
|
#define XML_VERSION_MINOR 2
|
||||||
#define MAX_RECENT_HISTORY 20
|
#define MAX_RECENT_HISTORY 20
|
||||||
|
#define MAX_SESSION_LEVEL 3
|
||||||
|
|
||||||
#define MINI(a, b) (((a) < (b)) ? (a) : (b))
|
#define MINI(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
#define MAXI(a, b) (((a) > (b)) ? (a) : (b))
|
#define MAXI(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|||||||
Reference in New Issue
Block a user