From c7cdb2fd3e19ae9560f540b65e2d47759cdb59d0 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 23 Aug 2019 13:12:31 +0200 Subject: [PATCH] Added version check for .3mf and .amf project files. PrusaSlicer will refuse to import files with newer version numbers. --- src/libslic3r/Format/3mf.cpp | 36 ++++++++++++++++++++++++++++-------- src/libslic3r/Format/3mf.hpp | 2 +- src/libslic3r/Format/AMF.cpp | 33 ++++++++++++++++++++++----------- src/libslic3r/Format/AMF.hpp | 2 +- src/libslic3r/Model.cpp | 12 ++++++------ src/libslic3r/Model.hpp | 4 ++-- src/slic3r/GUI/Plater.cpp | 4 ++-- 7 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index fd1d11c2fb..9da0d4fd99 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -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; } diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp index b5927651ec..f387192ab5 100644 --- a/src/libslic3r/Format/3mf.hpp +++ b/src/libslic3r/Format/3mf.hpp @@ -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 diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 08820f2ea1..be15f833b5 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -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(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; diff --git a/src/libslic3r/Format/AMF.hpp b/src/libslic3r/Format/AMF.hpp index e085ad22ea..1206d60d07 100644 --- a/src/libslic3r/Format/AMF.hpp +++ b/src/libslic3r/Format/AMF.hpp @@ -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 diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 4331c43798..5121a1fe21 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -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."); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 2678ddfcc6..422467e088 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -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(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index bb6c1e2f64..c8ffa2ef04 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2215,7 +2215,7 @@ std::vector Plater::priv::load_files(const std::vector& 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 Plater::priv::load_files(const std::vector& 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();