#include #include #include "miniz_extension.hpp" #include "Utils.hpp" #if defined(_MSC_VER) || defined(__MINGW64__) #include "boost/nowide/cstdio.hpp" #endif #include "I18N.hpp" //! macro used to mark string used at localization, //! return same string #define L(s) Slic3r::I18N::translate(s) namespace Slic3r { namespace { std::string decode_zip_unicode_path_extra_field(const std::string& extra, const std::string& path) { size_t offset = 0; const mz_uint32 path_crc = mz_crc32(0, reinterpret_cast(path.data()), path.size()); while (offset + 4 <= extra.size()) { const unsigned char* field = reinterpret_cast(extra.data() + offset); const std::uint16_t len = field[2] | (static_cast(field[3]) << 8); if (offset + 4 + len > extra.size()) break; if (field[0] == 0x75 && field[1] == 0x70 && len >= 5 && field[4] == 0x01) { const mz_uint32 stored_crc = static_cast(field[5]) | (static_cast(field[6]) << 8) | (static_cast(field[7]) << 16) | (static_cast(field[8]) << 24); if (stored_crc == path_crc) return std::string(extra.data() + offset + 9, extra.data() + offset + 4 + len); } offset += 4 + len; } return Slic3r::decode_path(path.c_str()); } bool open_zip(mz_zip_archive *zip, const char *fname, bool isread) { if (!zip) return false; const char *mode = isread ? "rb" : "wb"; FILE *f = nullptr; #if defined(_MSC_VER) || defined(__MINGW64__) f = boost::nowide::fopen(fname, mode); #elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) f = fopen64(fname, mode); #else f = fopen(fname, mode); #endif if (!f) { zip->m_last_error = MZ_ZIP_FILE_OPEN_FAILED; return false; } bool res = false; if (isread) { res = mz_zip_reader_init_cfile(zip, f, 0, 0); if (!res) // if we get here it means we tried to open a non-zip file // we need to close the file here because the call to mz_zip_get_cfile() made into close_zip() returns a null pointer // see: https://github.com/prusa3d/PrusaSlicer/issues/3536 fclose(f); } else res = mz_zip_writer_init_cfile(zip, f, 0); return res; } bool close_zip(mz_zip_archive *zip, bool isread) { bool ret = false; if (zip) { FILE *f = mz_zip_get_cfile(zip); ret = bool(isread ? mz_zip_reader_end(zip) : mz_zip_writer_end(zip)); if (f) fclose(f); } return ret; } } bool open_zip_reader(mz_zip_archive *zip, const std::string &fname) { return open_zip(zip, fname.c_str(), true); } bool open_zip_writer(mz_zip_archive *zip, const std::string &fname) { return open_zip(zip, fname.c_str(), false); } bool close_zip_reader(mz_zip_archive *zip) { return close_zip(zip, true); } bool close_zip_writer(mz_zip_archive *zip) { return close_zip(zip, false); } std::string decode_archive_entry_path(mz_zip_archive *zip, const mz_zip_archive_file_stat &stat) { if (stat.m_is_utf8) return stat.m_filename; std::string extra(1024, 0); const size_t extra_size = mz_zip_reader_get_extra(zip, stat.m_file_index, extra.data(), extra.size()); return decode_zip_unicode_path_extra_field(extra.substr(0, extra_size > 0 ? extra_size - 1 : 0), stat.m_filename); } MZ_Archive::MZ_Archive() { mz_zip_zero_struct(&arch); } std::string MZ_Archive::get_errorstr(mz_zip_error mz_err) { switch (mz_err) { case MZ_ZIP_NO_ERROR: return "no error"; case MZ_ZIP_UNDEFINED_ERROR: return L("undefined error"); case MZ_ZIP_TOO_MANY_FILES: return L("too many files"); case MZ_ZIP_FILE_TOO_LARGE: return L("File too large"); case MZ_ZIP_UNSUPPORTED_METHOD: return L("unsupported method"); case MZ_ZIP_UNSUPPORTED_ENCRYPTION: return L("unsupported encryption"); case MZ_ZIP_UNSUPPORTED_FEATURE: return L("unsupported feature"); case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: return L("failed finding central directory"); case MZ_ZIP_NOT_AN_ARCHIVE: return L("not a ZIP archive"); case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: return L("invalid header or corrupted"); case MZ_ZIP_UNSUPPORTED_MULTIDISK: return L("Saving to RAID is not supported."); case MZ_ZIP_DECOMPRESSION_FAILED: return L("decompression failed"); case MZ_ZIP_COMPRESSION_FAILED: return L("compression failed"); case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: return L("unexpected decompressed size"); case MZ_ZIP_CRC_CHECK_FAILED: return L("CRC check failed"); case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: return L("unsupported central directory size"); case MZ_ZIP_ALLOC_FAILED: return L("allocation failed"); case MZ_ZIP_FILE_OPEN_FAILED: return L("file open failed"); case MZ_ZIP_FILE_CREATE_FAILED: return L("file create failed"); case MZ_ZIP_FILE_WRITE_FAILED: return L("file write failed"); case MZ_ZIP_FILE_READ_FAILED: return L("file read failed"); case MZ_ZIP_FILE_CLOSE_FAILED: return L("file close failed"); case MZ_ZIP_FILE_SEEK_FAILED: return L("file seek failed"); case MZ_ZIP_FILE_STAT_FAILED: return L("file stat failed"); case MZ_ZIP_INVALID_PARAMETER: return L("invalid parameter"); case MZ_ZIP_INVALID_FILENAME: return L("invalid filename"); case MZ_ZIP_BUF_TOO_SMALL: return L("Buffer too small"); case MZ_ZIP_INTERNAL_ERROR: return L("internal error"); case MZ_ZIP_FILE_NOT_FOUND: return L("file not found"); case MZ_ZIP_ARCHIVE_TOO_LARGE: return L("Archive too large"); case MZ_ZIP_VALIDATION_FAILED: return L("validation failed"); case MZ_ZIP_WRITE_CALLBACK_FAILED: return L("write callback failed"); default: break; } return "unknown error"; } } // namespace Slic3r