Add really simple 7z extraction, using the 7z VFS

This commit is contained in:
Henrik Rydgård
2026-03-27 12:12:28 -06:00
parent 0c077acc74
commit 5e0a9a0113
7 changed files with 76 additions and 8 deletions
+2
View File
@@ -36,6 +36,8 @@ static bool IsLocalAbsolutePath(std::string_view path) {
return isUnixLocal || isWindowsLocal || isContentURI;
}
// This allows empty prefixes for multiple systems, which effectively becomes a union mount.
// Which is useful for PPSSPP's asset files, but not much else. We should use prefixes for everything.
template<class RetType, class Func>
inline RetType RouteVFSOperation(const std::vector<VFSEntry> &entries, std::string_view filename, Func func) {
const int fn_len = (int)filename.length();
+2
View File
@@ -59,6 +59,8 @@ void OnScreenDisplay::Show(OSDType type, std::string_view text, std::string_view
return;
}
INFO_LOG(Log::UI, "OSD: %.*s (%.*s)", STR_VIEW(text), STR_VIEW(text2));
// Automatic duration based on type.
if (duration_s <= 0.0f) {
switch (type) {
+19
View File
@@ -451,7 +451,26 @@ static bool ZipExtractFileToMemory(struct zip *z, int fileIndex, std::string *da
}
}
// TODO: Make this generic and handle all the things.
// For now, it'll just handle unpacking ISOs.
bool DetectArchiveContents(VFSInterface *vfs, ZipFileInfo *info) {
info->archiveType = ArchiveType::SevenZ;
info->contents = ZipFileContents::UNKNOWN;
std::vector<File::FileInfo> listing;
vfs->GetFileListing("", &listing, nullptr);
for (auto &file : listing) {
std::string ext = file.fullName.GetFileExtension(); // always lowercase
if (ext == ".iso" || ext == ".cso") {
info->contents = ZipFileContents::ISO_FILE;
info->isoFilename = file.fullName.ToString();
return true;
}
}
return false;
}
void DetectZipFileContents(zip_t *z, ZipFileInfo *info) {
info->archiveType = ArchiveType::ZIP;
int numFiles = zip_get_num_files(z);
if (numFiles < 0) {
// Broken zip archive?
+8 -1
View File
@@ -162,6 +162,10 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin
bool UmdReplace(const Path &filepath, FileLoader **fileLoader, std::string &error);
enum class ArchiveType {
ZIP,
SevenZ,
};
enum class ZipFileContents {
NOT_A_ZIP_FILE = 0,
@@ -176,7 +180,9 @@ enum class ZipFileContents {
PRX_PLUGIN,
};
// TODO: Rename to ArchiveContentsInfo or something.
struct ZipFileInfo {
ArchiveType archiveType;
ZipFileContents contents = ZipFileContents::NOT_A_ZIP_FILE;
int numFiles = 0;
int stripChars = 0; // for PSP game - how much to strip from the path.
@@ -189,6 +195,7 @@ struct ZipFileInfo {
std::string savedataDir;
std::string mTime;
std::string iniContents;
std::string isoFilename; // Used by SevenZ only right now.
s64 totalFileSize = 0;
std::string contentName;
@@ -197,5 +204,5 @@ struct ZipFileInfo {
ZipContainer ZipOpenPath(const Path &fileName);
void ZipClose(ZipContainer &z);
bool DetectZipFileContents(const Path &fileName, ZipFileInfo *info);
void DetectZipFileContents(zip_t *z, ZipFileInfo *info);
bool DetectArchiveContents(VFSInterface *vfs, ZipFileInfo *info);
+27 -2
View File
@@ -40,6 +40,8 @@
#include "Common/System/Request.h"
#include "Common/System/OSD.h"
#include "Common/File/FileUtil.h"
#include "Common/File/VFS/VFS.h"
#include "Common/File/VFS/SevenZipFileReader.h"
#include "Common/StringUtils.h"
#include "Common/Thread/ThreadUtil.h"
#include "Core/Config.h"
@@ -257,6 +259,25 @@ void GameManager::InstallZipContents(ZipFileTask task) {
return;
}
// Check for 7z. We don't support very many scenarios here yet, but we do support ISO install.
if (task.zipFileInfo->archiveType == ArchiveType::SevenZ) {
Path destPath = task.destination;
g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f);
VFSInterface *reader = SevenZipFileReader::Create(task.fileName, "", true);
// TODO: We need streaming reads here.
size_t size;
u8 *data = reader->ReadFile(task.zipFileInfo->isoFilename, &size);
Path fn(task.zipFileInfo->isoFilename);
Path destFile = destPath / fn.GetFilename();
File::WriteDataToFile(false, data, size, destFile);
g_OSD.RemoveProgressBar("install", true, 0.5f);
installProgress_ = 1.0f;
InstallDone();
return;
}
int error = 0;
ZipContainer z = ZipOpenPath(task.fileName);
@@ -739,7 +760,9 @@ bool GameManager::InstallZipOnThread(ZipFileTask task) {
return false;
}
installThread_ = std::thread(std::bind(&GameManager::InstallZipContents, this, task));
installThread_ = std::thread([this, task]() {
InstallZipContents(task);
});
return true;
}
@@ -751,7 +774,9 @@ bool GameManager::UninstallGameOnThread(const std::string &name) {
if (InstallInProgress() || installDonePending_ || curDownload_.get() != nullptr) {
return false;
}
installThread_ = std::thread(std::bind(&GameManager::UninstallGame, this, name));
installThread_ = std::thread([this, name]() {
UninstallGame(name);
});
return true;
}
+16 -4
View File
@@ -24,6 +24,8 @@
#include "Common/Data/Text/I18n.h"
#include "Common/Data/Text/Parsers.h"
#include "Common/Data/Format/IniFile.h"
#include "Common/File/VFS/VFS.h"
#include "Common/File/VFS/SevenZipFileReader.h"
#include "Core/Config.h"
#include "Core/System.h"
@@ -40,15 +42,25 @@
InstallZipScreen::InstallZipScreen(const Path &zipPath) : UITwoPaneBaseDialogScreen(Path(), TwoPaneFlags::SettingsToTheRight | TwoPaneFlags::ContentsCanScroll), zipPath_(zipPath) {
g_GameManager.ResetInstallError();
ZipContainer zipFile = ZipOpenPath(zipPath_);
if (zipFile) {
DetectZipFileContents(zipFile, &zipFileInfo_); // Even if this fails, it sets zipInfo->contents.
ZipClose(zipFile);
if (zipPath.GetFileExtension() == ".7z") {
SevenZipFileReader *sevenZipFile = SevenZipFileReader::Create(zipPath, "");
DetectArchiveContents(sevenZipFile, &zipFileInfo_); // Even if this fails, it sets zipInfo->contents.
delete sevenZipFile;
} else {
ZipContainer zipFile = ZipOpenPath(zipPath_);
if (zipFile) {
DetectZipFileContents(zipFile, &zipFileInfo_); // Even if this fails, it sets zipInfo->contents.
ZipClose(zipFile);
}
}
}
std::string_view InstallZipScreen::GetTitle() const {
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
if (zipFileInfo_.archiveType == ArchiveType::SevenZ) {
return iz->T("7z file");
}
return iz->T("ZIP file");
}
+2 -1
View File
@@ -75,7 +75,8 @@
bool MainScreen::showHomebrewTab = false;
static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, const Path &path) {
if (path.GetFileExtension() == ".zip") {
std::string extension = path.GetFileExtension();
if (extension == ".zip" || extension == ".7z") {
// If is a zip file, we have a screen for that.
screenManager->push(new InstallZipScreen(path));
} else {