diff --git a/src/Base/Tools.cpp b/src/Base/Tools.cpp index eab37f58601f..71f6021bee1e 100644 --- a/src/Base/Tools.cpp +++ b/src/Base/Tools.cpp @@ -393,3 +393,17 @@ std::vector Base::Tools::splitSubName(const std::string& subname) return subNames; } + +// ------------------------------------------------------------------------------------------------ + +void Base::ZipTools::rewrite(const std::string& source, const std::string& target) +{ + Base::PyGILStateLocker lock; + PyObject* module = PyImport_ImportModule("freecad.utils_zip"); + if (!module) { + throw Py::Exception(); + } + + Py::Module commands(module, true); + commands.callMemberFunction("rewrite", Py::TupleN(Py::String(source), Py::String(target))); +} diff --git a/src/Base/Tools.h b/src/Base/Tools.h index e2018b988919..7e07dc841ace 100644 --- a/src/Base/Tools.h +++ b/src/Base/Tools.h @@ -329,6 +329,14 @@ struct BaseExport Tools static std::vector splitSubName(const std::string& subname); }; +struct BaseExport ZipTools +{ + /** + * @brief rewrite Rewrite a zip file under a new name. + */ + static void rewrite(const std::string& source, const std::string& target); +}; + } // namespace Base diff --git a/src/Ext/freecad/CMakeLists.txt b/src/Ext/freecad/CMakeLists.txt index caaf5b5eb5e0..4681b8f88199 100644 --- a/src/Ext/freecad/CMakeLists.txt +++ b/src/Ext/freecad/CMakeLists.txt @@ -35,6 +35,7 @@ set(EXT_FILES sketcher.py UiTools.py utils.py + utils_zip.py ) foreach (it ${EXT_FILES}) diff --git a/src/Ext/freecad/utils_zip.py b/src/Ext/freecad/utils_zip.py new file mode 100644 index 000000000000..d3ae1d007fc9 --- /dev/null +++ b/src/Ext/freecad/utils_zip.py @@ -0,0 +1,18 @@ +# (c) 2024 Werner Mayer LGPL + +__author__ = "Werner Mayer" +__url__ = "https://www.freecad.org" +__doc__ = "Helper module to convert zip files" + + +import zipfile + +def rewrite(source: str, target: str): + source_zip = zipfile.ZipFile(source, "r") + target_zip = zipfile.ZipFile(target, "w") + + for name in source_zip.namelist(): + target_zip.writestr(name, source_zip.open(name).read()) + + source_zip.close() + target_zip.close() diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index 47ccec3adbfb..6f12b48662fc 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -108,6 +108,31 @@ struct QUAD int iV[4]; }; +class ZipFixer +{ +public: + ZipFixer(const char* filename) + : tmp {Base::FileInfo::getTempFileName()} + { + Base::ZipTools::rewrite(filename, tmp.filePath().c_str()); + str.open(tmp, std::ios::in | std::ios::binary); + } + + ~ZipFixer() + { + tmp.deleteFile(); + } + + Base::ifstream& getStream() + { + return str; + } + +private: + Base::FileInfo tmp; + Base::ifstream str; +}; + } // namespace MeshCore // -------------------------------------------------------------- @@ -227,7 +252,13 @@ bool MeshInput::LoadAny(const char* FileName) ok = LoadSMF(str); } else if (fi.hasExtension("3mf")) { - ok = Load3MF(str); + try { + ok = Load3MF(str); + } + catch (const zipios::FCollException&) { + ZipFixer zip(FileName); + ok = Load3MF(zip.getStream()); + } } else if (fi.hasExtension("off")) { ok = LoadOFF(str);