Zipper.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. ///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, David Kocík @kocikdav, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, Vojtěch Král @vojtechkral
  2. ///|/
  3. ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
  4. ///|/
  5. #include <exception>
  6. #include "Exception.hpp"
  7. #include "Zipper.hpp"
  8. #include "miniz_extension.hpp"
  9. #include <boost/log/trivial.hpp>
  10. #include "I18N.hpp"
  11. #if defined(_MSC_VER) && _MSC_VER <= 1800 || __cplusplus < 201103L
  12. #define SLIC3R_NORETURN
  13. #elif __cplusplus >= 201103L
  14. #define SLIC3R_NORETURN [[noreturn]]
  15. #endif
  16. namespace Slic3r {
  17. class Zipper::Impl: public MZ_Archive {
  18. public:
  19. std::string m_zipname;
  20. std::string formatted_errorstr() const
  21. {
  22. return _u8L("Error with ZIP archive") + " " + m_zipname + ": " +
  23. get_errorstr();
  24. }
  25. SLIC3R_NORETURN void blow_up() const
  26. {
  27. throw Slic3r::ExportError(formatted_errorstr());
  28. }
  29. bool is_alive()
  30. {
  31. return arch.m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
  32. }
  33. };
  34. Zipper::Zipper(const std::string &zipfname, e_compression compression)
  35. {
  36. m_impl.reset(new Impl());
  37. m_compression = compression;
  38. m_impl->m_zipname = zipfname;
  39. memset(&m_impl->arch, 0, sizeof(m_impl->arch));
  40. if (!open_zip_writer(&m_impl->arch, zipfname)) {
  41. m_impl->blow_up();
  42. }
  43. }
  44. Zipper::~Zipper()
  45. {
  46. if(m_impl->is_alive()) {
  47. // Flush the current entry if not finished yet.
  48. try { finish_entry(); } catch(...) {
  49. BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr();
  50. }
  51. if(!mz_zip_writer_finalize_archive(&m_impl->arch))
  52. BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr();
  53. }
  54. // The file should be closed no matter what...
  55. if(!close_zip_writer(&m_impl->arch))
  56. BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr();
  57. }
  58. Zipper::Zipper(Zipper &&m):
  59. m_impl(std::move(m.m_impl)),
  60. m_data(std::move(m.m_data)),
  61. m_entry(std::move(m.m_entry)),
  62. m_compression(m.m_compression) {}
  63. Zipper &Zipper::operator=(Zipper &&m) {
  64. m_impl = std::move(m.m_impl);
  65. m_data = std::move(m.m_data);
  66. m_entry = std::move(m.m_entry);
  67. m_compression = m.m_compression;
  68. return *this;
  69. }
  70. void Zipper::add_entry(const std::string &name)
  71. {
  72. if(!m_impl->is_alive()) return;
  73. finish_entry(); // finish previous business
  74. m_entry = name;
  75. }
  76. void Zipper::add_entry(const std::string &name, const void *data, size_t l)
  77. {
  78. if(!m_impl->is_alive()) return;
  79. finish_entry();
  80. mz_uint cmpr = MZ_NO_COMPRESSION;
  81. switch (m_compression) {
  82. case NO_COMPRESSION: cmpr = MZ_NO_COMPRESSION; break;
  83. case FAST_COMPRESSION: cmpr = MZ_BEST_SPEED; break;
  84. case TIGHT_COMPRESSION: cmpr = MZ_BEST_COMPRESSION; break;
  85. }
  86. if(!mz_zip_writer_add_mem(&m_impl->arch, name.c_str(), data, l, cmpr))
  87. m_impl->blow_up();
  88. m_entry.clear();
  89. m_data.clear();
  90. }
  91. void Zipper::finish_entry()
  92. {
  93. if(!m_impl->is_alive()) return;
  94. if(!m_data.empty() && !m_entry.empty()) {
  95. mz_uint compression = MZ_NO_COMPRESSION;
  96. switch (m_compression) {
  97. case NO_COMPRESSION: compression = MZ_NO_COMPRESSION; break;
  98. case FAST_COMPRESSION: compression = MZ_BEST_SPEED; break;
  99. case TIGHT_COMPRESSION: compression = MZ_BEST_COMPRESSION; break;
  100. }
  101. if(!mz_zip_writer_add_mem(&m_impl->arch, m_entry.c_str(),
  102. m_data.c_str(),
  103. m_data.size(),
  104. compression)) m_impl->blow_up();
  105. }
  106. m_data.clear();
  107. m_entry.clear();
  108. }
  109. void Zipper::finalize()
  110. {
  111. finish_entry();
  112. if(m_impl->is_alive()) if(!mz_zip_writer_finalize_archive(&m_impl->arch))
  113. m_impl->blow_up();
  114. }
  115. const std::string &Zipper::get_filename() const
  116. {
  117. return m_impl->m_zipname;
  118. }
  119. }