Added version check for .3mf and .amf project files. PrusaSlicer will refuse to import files with newer version numbers.

This commit is contained in:
Enrico Turri 2019-08-23 13:12:31 +02:00
parent 058a1d9a98
commit c7cdb2fd3e
7 changed files with 62 additions and 31 deletions

View file

@ -350,6 +350,7 @@ namespace Slic3r {
// Version of the 3mf file
unsigned int m_version;
bool m_check_version;
XML_Parser m_xml_parser;
Model* m_model;
@ -372,7 +373,7 @@ namespace Slic3r {
_3MF_Importer();
~_3MF_Importer();
bool load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
bool load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, bool check_version);
private:
void _destroy_xml_parser();
@ -465,6 +466,7 @@ namespace Slic3r {
_3MF_Importer::_3MF_Importer()
: m_version(0)
, m_check_version(false)
, m_xml_parser(nullptr)
, m_model(nullptr)
, m_unit_factor(1.0f)
@ -479,9 +481,10 @@ namespace Slic3r {
_destroy_xml_parser();
}
bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config)
bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, bool check_version)
{
m_version = 0;
m_check_version = check_version;
m_model = &model;
m_unit_factor = 1.0f;
m_curr_object.reset();
@ -543,12 +546,21 @@ namespace Slic3r {
if (boost::algorithm::istarts_with(name, MODEL_FOLDER) && boost::algorithm::iends_with(name, MODEL_EXTENSION))
{
// valid model name -> extract model
if (!_extract_model_from_archive(archive, stat))
try
{
// valid model name -> extract model
if (!_extract_model_from_archive(archive, stat))
{
close_zip_reader(&archive);
add_error("Archive does not contain a valid model");
return false;
}
}
catch (const std::exception& e)
{
// ensure the zip archive is closed and rethrow the exception
close_zip_reader(&archive);
add_error("Archive does not contain a valid model");
return false;
throw e;
}
}
}
@ -1399,8 +1411,16 @@ namespace Slic3r {
bool _3MF_Importer::_handle_end_metadata()
{
if (m_curr_metadata_name == SLIC3RPE_3MF_VERSION)
{
m_version = (unsigned int)atoi(m_curr_characters.c_str());
if (m_check_version && (m_version > VERSION_3MF))
{
std::string msg = "The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatibile.";
throw std::runtime_error(msg.c_str());
}
}
return true;
}
@ -2316,13 +2336,13 @@ namespace Slic3r {
return true;
}
bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model)
bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version)
{
if ((path == nullptr) || (config == nullptr) || (model == nullptr))
return false;
_3MF_Importer importer;
bool res = importer.load_model_from_file(path, *model, *config);
bool res = importer.load_model_from_file(path, *model, *config, check_version);
importer.log_errors();
return res;
}

View file

@ -24,7 +24,7 @@ namespace Slic3r {
class DynamicPrintConfig;
// Load the content of a 3mf file into the given model and preset bundle.
extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model);
extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version);
// Save the given model and the config data contained in the given Print into a 3mf file.
// The model could be modified during the export process if meshes are not repaired or have no shared vertices

View file

@ -44,7 +44,7 @@ namespace Slic3r
struct AMFParserContext
{
AMFParserContext(XML_Parser parser, DynamicPrintConfig *config, Model *model) :
AMFParserContext(XML_Parser parser, DynamicPrintConfig* config, Model* model) :
m_version(0),
m_parser(parser),
m_model(*model),
@ -755,7 +755,7 @@ bool load_amf_file(const char *path, DynamicPrintConfig *config, Model *model)
return result;
}
bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig* config, Model* model, unsigned int& version)
bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig* config, Model* model, bool check_version)
{
if (stat.m_uncomp_size == 0)
{
@ -801,19 +801,21 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
ctx.endDocument();
version = ctx.m_version;
if (check_version && (ctx.m_version > VERSION_AMF))
{
std::string msg = "The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatibile.";
throw std::runtime_error(msg.c_str());
}
return true;
}
// Load an AMF archive into a provided model.
bool load_amf_archive(const char *path, DynamicPrintConfig *config, Model *model)
bool load_amf_archive(const char* path, DynamicPrintConfig* config, Model* model, bool check_version)
{
if ((path == nullptr) || (model == nullptr))
return false;
unsigned int version = 0;
mz_zip_archive archive;
mz_zip_zero_struct(&archive);
@ -833,11 +835,20 @@ bool load_amf_archive(const char *path, DynamicPrintConfig *config, Model *model
{
if (boost::iends_with(stat.m_filename, ".amf"))
{
if (!extract_model_from_archive(archive, stat, config, model, version))
try
{
if (!extract_model_from_archive(archive, stat, config, model, check_version))
{
close_zip_reader(&archive);
printf("Archive does not contain a valid model");
return false;
}
}
catch (const std::exception& e)
{
// ensure the zip archive is closed and rethrow the exception
close_zip_reader(&archive);
printf("Archive does not contain a valid model");
return false;
throw e;
}
break;
@ -862,7 +873,7 @@ bool load_amf_archive(const char *path, DynamicPrintConfig *config, Model *model
// Load an AMF file into a provided model.
// If config is not a null pointer, updates it if the amf file/archive contains config data
bool load_amf(const char *path, DynamicPrintConfig *config, Model *model)
bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version)
{
if (boost::iends_with(path, ".amf.xml"))
// backward compatibility with older slic3r output
@ -877,7 +888,7 @@ bool load_amf(const char *path, DynamicPrintConfig *config, Model *model)
file.read(const_cast<char*>(zip_mask.data()), 2);
file.close();
return (zip_mask == "PK") ? load_amf_archive(path, config, model) : load_amf_file(path, config, model);
return (zip_mask == "PK") ? load_amf_archive(path, config, model, check_version) : load_amf_file(path, config, model);
}
else
return false;

View file

@ -7,7 +7,7 @@ class Model;
class DynamicPrintConfig;
// Load the content of an amf file into the given model and configuration.
extern bool load_amf(const char *path, DynamicPrintConfig *config, Model *model);
extern bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version);
// Save the given model and the config data into an amf file.
// The model could be modified during the export process if meshes are not repaired or have no shared vertices

View file

@ -84,7 +84,7 @@ void Model::update_links_bottom_up_recursive()
}
}
Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances)
Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* config, bool add_default_instances, bool check_version)
{
Model model;
@ -98,9 +98,9 @@ Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *c
else if (boost::algorithm::iends_with(input_file, ".obj"))
result = load_obj(input_file.c_str(), &model);
else if (boost::algorithm::iends_with(input_file, ".amf") || boost::algorithm::iends_with(input_file, ".amf.xml"))
result = load_amf(input_file.c_str(), config, &model);
result = load_amf(input_file.c_str(), config, &model, check_version);
else if (boost::algorithm::iends_with(input_file, ".3mf"))
result = load_3mf(input_file.c_str(), config, &model);
result = load_3mf(input_file.c_str(), config, &model, false);
else if (boost::algorithm::iends_with(input_file, ".prusa"))
result = load_prus(input_file.c_str(), &model);
else
@ -121,15 +121,15 @@ Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *c
return model;
}
Model Model::read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances)
Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig* config, bool add_default_instances, bool check_version)
{
Model model;
bool result = false;
if (boost::algorithm::iends_with(input_file, ".3mf"))
result = load_3mf(input_file.c_str(), config, &model);
result = load_3mf(input_file.c_str(), config, &model, check_version);
else if (boost::algorithm::iends_with(input_file, ".zip.amf"))
result = load_amf(input_file.c_str(), config, &model);
result = load_amf(input_file.c_str(), config, &model, check_version);
else
throw std::runtime_error("Unknown file format. Input file must have .3mf or .zip.amf extension.");

View file

@ -747,8 +747,8 @@ public:
OBJECTBASE_DERIVED_COPY_MOVE_CLONE(Model)
static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true);
static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true);
static Model read_from_file(const std::string& input_file, DynamicPrintConfig* config = nullptr, bool add_default_instances = true, bool check_version = false);
static Model read_from_archive(const std::string& input_file, DynamicPrintConfig* config, bool add_default_instances = true, bool check_version = false);
// Add a new ModelObject to this Model, generate a new ID for this ModelObject.
ModelObject* add_object();

View file

@ -2215,7 +2215,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
DynamicPrintConfig config;
{
DynamicPrintConfig config_loaded;
model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, false);
model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, false, load_config);
if (load_config && !config_loaded.empty()) {
// Based on the printer technology field found in the loaded config, select the base for the config,
PrinterTechnology printer_technology = Preset::printer_technology(config_loaded);
@ -2255,7 +2255,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
}
else {
model = Slic3r::Model::read_from_file(path.string(), nullptr, false);
model = Slic3r::Model::read_from_file(path.string(), nullptr, false, load_config);
for (auto obj : model.objects)
if (obj->name.empty())
obj->name = fs::path(obj->input_file).filename().string();