Use multibyte encoding aware libarchive functions when dealing with filenames (#4457)
This commit is contained in:
@@ -42,7 +42,7 @@ bool ArchiveReader::collectFiles(bool onlyFiles)
|
|||||||
|
|
||||||
QString ArchiveReader::File::filename()
|
QString ArchiveReader::File::filename()
|
||||||
{
|
{
|
||||||
return QString::fromUtf8(archive_entry_pathname(m_entry));
|
return QString::fromUtf8(archive_entry_pathname_utf8(m_entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ArchiveReader::File::readAll(int* outStatus)
|
QByteArray ArchiveReader::File::readAll(int* outStatus)
|
||||||
@@ -84,8 +84,8 @@ auto ArchiveReader::goToFile(QString filename) -> std::unique_ptr<File>
|
|||||||
auto a = f->m_archive.get();
|
auto a = f->m_archive.get();
|
||||||
archive_read_support_format_all(a);
|
archive_read_support_format_all(a);
|
||||||
archive_read_support_filter_all(a);
|
archive_read_support_filter_all(a);
|
||||||
auto fileName = m_archivePath.toUtf8();
|
auto fileName = m_archivePath.toStdWString();
|
||||||
if (archive_read_open_filename(a, fileName.constData(), m_blockSize) != ARCHIVE_OK) {
|
if (archive_read_open_filename_w(a, fileName.data(), m_blockSize) != ARCHIVE_OK) {
|
||||||
qCritical() << "Failed to open archive file:" << m_archivePath << "-" << archive_error_string(a);
|
qCritical() << "Failed to open archive file:" << m_archivePath << "-" << archive_error_string(a);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ bool ArchiveReader::File::writeFile(archive* out, QString targetFileName, bool n
|
|||||||
entryClone.reset(archive_entry_clone(m_entry));
|
entryClone.reset(archive_entry_clone(m_entry));
|
||||||
entry = entryClone.get();
|
entry = entryClone.get();
|
||||||
auto nameUtf8 = targetFileName.toUtf8();
|
auto nameUtf8 = targetFileName.toUtf8();
|
||||||
archive_entry_set_pathname(entry, nameUtf8.constData());
|
archive_entry_set_pathname_utf8(entry, nameUtf8.constData());
|
||||||
}
|
}
|
||||||
if (archive_write_header(out, entry) < ARCHIVE_OK) {
|
if (archive_write_header(out, entry) < ARCHIVE_OK) {
|
||||||
qCritical() << "Failed to write header to entry:" << filename() << "-" << archive_error_string(out);
|
qCritical() << "Failed to write header to entry:" << filename() << "-" << archive_error_string(out);
|
||||||
@@ -160,8 +160,8 @@ bool ArchiveReader::parse(std::function<bool(File*, bool&)> doStuff)
|
|||||||
auto a = f->m_archive.get();
|
auto a = f->m_archive.get();
|
||||||
archive_read_support_format_all(a);
|
archive_read_support_format_all(a);
|
||||||
archive_read_support_filter_all(a);
|
archive_read_support_filter_all(a);
|
||||||
auto fileName = m_archivePath.toUtf8();
|
auto fileName = m_archivePath.toStdWString();
|
||||||
if (archive_read_open_filename(a, fileName.constData(), m_blockSize) != ARCHIVE_OK) {
|
if (archive_read_open_filename_w(a, fileName.data(), m_blockSize) != ARCHIVE_OK) {
|
||||||
qCritical() << "Failed to open archive file:" << m_archivePath << "-" << f->error();
|
qCritical() << "Failed to open archive file:" << m_archivePath << "-" << f->error();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,16 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
// clang-format off
|
||||||
|
#include <windows.h>
|
||||||
|
#include <fileapi.h>
|
||||||
|
// clang-format on
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MMCZip {
|
namespace MMCZip {
|
||||||
|
|
||||||
ArchiveWriter::ArchiveWriter(const QString& archiveName) : m_filename(archiveName) {}
|
ArchiveWriter::ArchiveWriter(const QString& archiveName) : m_filename(archiveName) {}
|
||||||
@@ -55,8 +65,8 @@ bool ArchiveWriter::open()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto archiveNameUtf8 = m_filename.toUtf8();
|
auto archiveNameW = m_filename.toStdWString();
|
||||||
if (archive_write_open_filename(m_archive, archiveNameUtf8.constData()) != ARCHIVE_OK) {
|
if (archive_write_open_filename_w(m_archive, archiveNameW.data()) != ARCHIVE_OK) {
|
||||||
qCritical() << "Failed to open archive file:" << m_filename << "-" << archive_error_string(m_archive);
|
qCritical() << "Failed to open archive file:" << m_filename << "-" << archive_error_string(m_archive);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -97,16 +107,46 @@ bool ArchiveWriter::addFile(const QString& fileName, const QString& fileDest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto fileDestUtf8 = fileDest.toUtf8();
|
auto fileDestUtf8 = fileDest.toUtf8();
|
||||||
archive_entry_set_pathname(entry, fileDestUtf8.constData());
|
archive_entry_set_pathname_utf8(entry, fileDestUtf8.constData());
|
||||||
|
|
||||||
QByteArray utf8 = fileInfo.absoluteFilePath().toUtf8();
|
#if defined Q_OS_WIN32
|
||||||
const char* cpath = utf8.constData();
|
{
|
||||||
struct stat st;
|
// Windows needs to use this method, thanks I hate it.
|
||||||
if (stat(cpath, &st) != 0) {
|
|
||||||
qCritical() << "Failed to stat file:" << fileInfo.filePath();
|
auto widePath = fileInfo.absoluteFilePath().toStdWString();
|
||||||
|
HANDLE file_handle = CreateFileW(widePath.data(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||||
|
qCritical() << "Failed to stat file:" << fileInfo.filePath();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BY_HANDLE_FILE_INFORMATION file_info;
|
||||||
|
if (!GetFileInformationByHandle(file_handle, &file_info)) {
|
||||||
|
qCritical() << "Failed to stat file:" << fileInfo.filePath();
|
||||||
|
CloseHandle(file_handle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
archive_entry_copy_bhfi(entry, &file_info);
|
||||||
|
CloseHandle(file_handle);
|
||||||
}
|
}
|
||||||
// This should handle the copying of most attributes
|
#else
|
||||||
archive_entry_copy_stat(entry, &st);
|
{
|
||||||
|
// this only works for multibyte encoded filenames if the local is properly set,
|
||||||
|
// a wide character version doesn't seem to exist: here's hoping...
|
||||||
|
|
||||||
|
QByteArray utf8 = fileInfo.absoluteFilePath().toUtf8();
|
||||||
|
const char* cpath = utf8.constData();
|
||||||
|
struct stat st;
|
||||||
|
if (stat(cpath, &st) != 0) {
|
||||||
|
qCritical() << "Failed to stat file:" << fileInfo.filePath();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should handle the copying of most attributes
|
||||||
|
archive_entry_copy_stat(entry, &st);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// However:
|
// However:
|
||||||
// "The [filetype] constants used by stat(2) may have different numeric values from the corresponding [libarchive constants]."
|
// "The [filetype] constants used by stat(2) may have different numeric values from the corresponding [libarchive constants]."
|
||||||
@@ -116,11 +156,11 @@ bool ArchiveWriter::addFile(const QString& fileName, const QString& fileDest)
|
|||||||
|
|
||||||
// We also need to manually copy some attributes from the link itself, as `stat` above operates on its target
|
// We also need to manually copy some attributes from the link itself, as `stat` above operates on its target
|
||||||
auto target = fileInfo.symLinkTarget().toUtf8();
|
auto target = fileInfo.symLinkTarget().toUtf8();
|
||||||
archive_entry_set_symlink(entry, target.constData());
|
archive_entry_set_symlink_utf8(entry, target.constData());
|
||||||
archive_entry_set_size(entry, 0);
|
archive_entry_set_size(entry, 0);
|
||||||
archive_entry_set_perm(entry, fileInfo.permissions());
|
archive_entry_set_perm(entry, fileInfo.permissions());
|
||||||
} else if (fileInfo.isFile()) {
|
} else if (fileInfo.isFile()) {
|
||||||
archive_entry_set_filetype(entry, AE_IFREG);
|
archive_entry_set_filetype(entry, AE_IFREG);
|
||||||
} else {
|
} else {
|
||||||
qCritical() << "Unsupported file type:" << fileInfo.filePath();
|
qCritical() << "Unsupported file type:" << fileInfo.filePath();
|
||||||
return false;
|
return false;
|
||||||
@@ -169,7 +209,7 @@ bool ArchiveWriter::addFile(const QString& fileDest, const QByteArray& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto fileDestUtf8 = fileDest.toUtf8();
|
auto fileDestUtf8 = fileDest.toUtf8();
|
||||||
archive_entry_set_pathname(entry, fileDestUtf8.constData());
|
archive_entry_set_pathname_utf8(entry, fileDestUtf8.constData());
|
||||||
archive_entry_set_perm(entry, 0644);
|
archive_entry_set_perm(entry, 0644);
|
||||||
|
|
||||||
archive_entry_set_filetype(entry, AE_IFREG);
|
archive_entry_set_filetype(entry, AE_IFREG);
|
||||||
@@ -210,4 +250,4 @@ std::unique_ptr<archive, void (*)(archive*)> ArchiveWriter::createDiskWriter()
|
|||||||
|
|
||||||
return extPtr;
|
return extPtr;
|
||||||
}
|
}
|
||||||
} // namespace MMCZip
|
} // namespace MMCZip
|
||||||
|
|||||||
@@ -37,13 +37,6 @@
|
|||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
// try to set the utf-8 locale for the libarchive
|
|
||||||
for (auto name : { ".UTF-8", "en_US.UTF-8", "C.UTF-8" }) {
|
|
||||||
if (std::setlocale(LC_CTYPE, name)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize Qt
|
// initialize Qt
|
||||||
Application app(argc, argv);
|
Application app(argc, argv);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user