From 87286fa6a30e2cbc6aa489261f9f97560ebdb86b Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:11:53 -0700 Subject: [PATCH 1/3] fix(libarchive): use multibyte encoding aware libarchive functions when dealing with filenames Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/archive/ArchiveReader.cpp | 12 +++--- launcher/archive/ArchiveWriter.cpp | 68 ++++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/launcher/archive/ArchiveReader.cpp b/launcher/archive/ArchiveReader.cpp index a866b49c5..f10191cf2 100644 --- a/launcher/archive/ArchiveReader.cpp +++ b/launcher/archive/ArchiveReader.cpp @@ -41,7 +41,7 @@ bool ArchiveReader::collectFiles(bool onlyFiles) 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) @@ -83,8 +83,8 @@ auto ArchiveReader::goToFile(QString filename) -> std::unique_ptr auto a = f->m_archive.get(); archive_read_support_format_all(a); archive_read_support_filter_all(a); - auto fileName = m_archivePath.toUtf8(); - if (archive_read_open_filename(a, fileName.constData(), m_blockSize) != ARCHIVE_OK) { + auto fileName = m_archivePath.toStdWString(); + 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); return nullptr; } @@ -133,7 +133,7 @@ bool ArchiveReader::File::writeFile(archive* out, QString targetFileName, bool n if (!targetFileName.isEmpty()) { entry = archive_entry_clone(m_entry); 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) { qCritical() << "Failed to write header to entry:" << filename() << "-" << archive_error_string(out); @@ -157,8 +157,8 @@ bool ArchiveReader::parse(std::function doStuff) auto a = f->m_archive.get(); archive_read_support_format_all(a); archive_read_support_filter_all(a); - auto fileName = m_archivePath.toUtf8(); - if (archive_read_open_filename(a, fileName.constData(), m_blockSize) != ARCHIVE_OK) { + auto fileName = m_archivePath.toStdWString(); + if (archive_read_open_filename_w(a, fileName.data(), m_blockSize) != ARCHIVE_OK) { qCritical() << "Failed to open archive file:" << m_archivePath << "-" << f->error(); return false; } diff --git a/launcher/archive/ArchiveWriter.cpp b/launcher/archive/ArchiveWriter.cpp index 87cead69c..0ec8259f1 100644 --- a/launcher/archive/ArchiveWriter.cpp +++ b/launcher/archive/ArchiveWriter.cpp @@ -25,6 +25,16 @@ #include +#if defined Q_OS_WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +// clang-format off +#include +#include +// clang-format on +#endif + namespace MMCZip { ArchiveWriter::ArchiveWriter(const QString& archiveName) : m_filename(archiveName) {} @@ -55,8 +65,8 @@ bool ArchiveWriter::open() return false; } - auto archiveNameUtf8 = m_filename.toUtf8(); - if (archive_write_open_filename(m_archive, archiveNameUtf8.constData()) != ARCHIVE_OK) { + auto archiveNameW = m_filename.toStdWString(); + 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); return false; } @@ -97,16 +107,46 @@ bool ArchiveWriter::addFile(const QString& fileName, const QString& fileDest) } auto fileDestUtf8 = fileDest.toUtf8(); - archive_entry_set_pathname(entry, fileDestUtf8.constData()); + archive_entry_set_pathname_utf8(entry, fileDestUtf8.constData()); - 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(); +#if defined Q_OS_WIN32 + { + // Windows needs to use this method, thanks I hate it. + + 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 - archive_entry_copy_stat(entry, &st); +#else + { + // this only works for myltibyte encoded filenames if the local is properly set, + // a wide charater version doens't seem to exist: here's hopeing... + + 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: // "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 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_perm(entry, fileInfo.permissions()); } else if (fileInfo.isFile()) { - archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_filetype(entry, AE_IFREG); } else { qCritical() << "Unsupported file type:" << fileInfo.filePath(); return false; @@ -169,7 +209,7 @@ bool ArchiveWriter::addFile(const QString& fileDest, const QByteArray& data) } 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_filetype(entry, AE_IFREG); @@ -210,4 +250,4 @@ std::unique_ptr ArchiveWriter::createDiskWriter() return extPtr; } -} // namespace MMCZip \ No newline at end of file +} // namespace MMCZip From 5e7de6bc53716e9b89eb647577c61b24f81fba62 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Wed, 10 Dec 2025 22:01:36 -0700 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/archive/ArchiveWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/archive/ArchiveWriter.cpp b/launcher/archive/ArchiveWriter.cpp index 0ec8259f1..a546f2bb7 100644 --- a/launcher/archive/ArchiveWriter.cpp +++ b/launcher/archive/ArchiveWriter.cpp @@ -132,8 +132,8 @@ bool ArchiveWriter::addFile(const QString& fileName, const QString& fileDest) } #else { - // this only works for myltibyte encoded filenames if the local is properly set, - // a wide charater version doens't seem to exist: here's hopeing... + // 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(); From b40544dc55d95ec03e5635f70e628b63351e9070 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sun, 14 Dec 2025 22:43:22 -0700 Subject: [PATCH 3/3] fix: remove locale forcing as unnecessary Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/main.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/launcher/main.cpp b/launcher/main.cpp index 46368e72e..2bce655d2 100644 --- a/launcher/main.cpp +++ b/launcher/main.cpp @@ -37,13 +37,6 @@ 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 Application app(argc, argv);