mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-25 03:42:05 +00:00
Fix garbled Chinese filenames when importing ZIP files. (#14633)
* Fix garbled Chinese filenames when importing ZIP files. * fix: avoid repeated ZIP path CRC calculation
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include "miniz_extension.hpp"
|
#include "miniz_extension.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW64__)
|
#if defined(_MSC_VER) || defined(__MINGW64__)
|
||||||
#include "boost/nowide/cstdio.hpp"
|
#include "boost/nowide/cstdio.hpp"
|
||||||
@@ -15,6 +17,33 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
namespace {
|
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<const unsigned char*>(path.data()), path.size());
|
||||||
|
|
||||||
|
while (offset + 4 <= extra.size()) {
|
||||||
|
const unsigned char* field = reinterpret_cast<const unsigned char*>(extra.data() + offset);
|
||||||
|
const std::uint16_t len = field[2] | (static_cast<std::uint16_t>(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<mz_uint32>(field[5]) |
|
||||||
|
(static_cast<mz_uint32>(field[6]) << 8) |
|
||||||
|
(static_cast<mz_uint32>(field[7]) << 16) |
|
||||||
|
(static_cast<mz_uint32>(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)
|
bool open_zip(mz_zip_archive *zip, const char *fname, bool isread)
|
||||||
{
|
{
|
||||||
if (!zip) return false;
|
if (!zip) return false;
|
||||||
@@ -76,6 +105,16 @@ bool open_zip_writer(mz_zip_archive *zip, const std::string &fname)
|
|||||||
bool close_zip_reader(mz_zip_archive *zip) { return close_zip(zip, true); }
|
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); }
|
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_Archive::MZ_Archive()
|
||||||
{
|
{
|
||||||
mz_zip_zero_struct(&arch);
|
mz_zip_zero_struct(&arch);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ bool open_zip_reader(mz_zip_archive *zip, const std::string &fname_utf8);
|
|||||||
bool open_zip_writer(mz_zip_archive *zip, const std::string &fname_utf8);
|
bool open_zip_writer(mz_zip_archive *zip, const std::string &fname_utf8);
|
||||||
bool close_zip_reader(mz_zip_archive *zip);
|
bool close_zip_reader(mz_zip_archive *zip);
|
||||||
bool close_zip_writer(mz_zip_archive *zip);
|
bool close_zip_writer(mz_zip_archive *zip);
|
||||||
|
std::string decode_archive_entry_path(mz_zip_archive *zip, const mz_zip_archive_file_stat &stat);
|
||||||
|
|
||||||
class MZ_Archive {
|
class MZ_Archive {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -221,16 +221,7 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
|
|||||||
std::vector<std::pair<boost::filesystem::path, size_t>> filtered_entries; // second is unzipped size
|
std::vector<std::pair<boost::filesystem::path, size_t>> filtered_entries; // second is unzipped size
|
||||||
for (mz_uint i = 0; i < num_entries; ++i) {
|
for (mz_uint i = 0; i < num_entries; ++i) {
|
||||||
if (mz_zip_reader_file_stat(archive, i, &stat)) {
|
if (mz_zip_reader_file_stat(archive, i, &stat)) {
|
||||||
std::string extra(1024, 0);
|
boost::filesystem::path path = Slic3r::decode_archive_entry_path(archive, stat);
|
||||||
boost::filesystem::path path;
|
|
||||||
size_t extra_size = mz_zip_reader_get_filename_from_extra(archive, i, extra.data(), extra.size());
|
|
||||||
if (extra_size > 0) {
|
|
||||||
path = boost::filesystem::path(extra.substr(0, extra_size));
|
|
||||||
} else {
|
|
||||||
wxString wname = boost::nowide::widen(stat.m_filename);
|
|
||||||
std::string name = into_u8(wname);
|
|
||||||
path = boost::filesystem::path(name);
|
|
||||||
}
|
|
||||||
assert(!path.empty());
|
assert(!path.empty());
|
||||||
if (!path.has_extension())
|
if (!path.has_extension())
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -13923,17 +13923,9 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
|
|||||||
if (mz_zip_reader_file_stat(&archive, i, &stat)) {
|
if (mz_zip_reader_file_stat(&archive, i, &stat)) {
|
||||||
if (size != stat.m_uncomp_size) // size must fit
|
if (size != stat.m_uncomp_size) // size must fit
|
||||||
continue;
|
continue;
|
||||||
wxString wname = boost::nowide::widen(stat.m_filename);
|
std::string name = Slic3r::decode_archive_entry_path(&archive, stat);
|
||||||
std::string name = into_u8(wname);
|
|
||||||
fs::path archive_path(name);
|
fs::path archive_path(name);
|
||||||
|
|
||||||
std::string extra(1024, 0);
|
|
||||||
size_t extra_size = mz_zip_reader_get_filename_from_extra(&archive, i, extra.data(), extra.size());
|
|
||||||
if (extra_size > 0) {
|
|
||||||
archive_path = fs::path(extra.substr(0, extra_size));
|
|
||||||
name = archive_path.string();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (archive_path.empty())
|
if (archive_path.empty())
|
||||||
continue;
|
continue;
|
||||||
if (path != archive_path)
|
if (path != archive_path)
|
||||||
|
|||||||
Reference in New Issue
Block a user