More refactoring of installzip code

This commit is contained in:
Henrik Rydgård
2024-09-04 17:08:26 +02:00
parent 472a812ff5
commit db550fc433
4 changed files with 87 additions and 54 deletions
+48 -30
View File
@@ -167,7 +167,11 @@ void GameManager::Update() {
return;
}
// Game downloaded to temporary file - install it!
InstallGameOnThread(Path(curDownload_->url()), fileName, true);
ZipFileTask task;
task.url = Path(curDownload_->url());
task.fileName = fileName;
task.deleteAfter = true;
InstallZipOnThread(task);
} else {
ERROR_LOG(Log::HLE, "Expected HTTP status code 200, got status code %d. Install cancelled, deleting partial file '%s'",
curDownload_->ResultCode(), fileName.c_str());
@@ -294,70 +298,83 @@ void DetectZipFileContents(struct zip *z, ZipFileInfo *info) {
}
// Parameters need to be by value, since this is a thread func.
bool GameManager::InstallZipContents(const Path &url, const Path &fileName, bool deleteAfter) {
void GameManager::InstallZipContents(ZipFileTask task) {
SetCurrentThreadName("InstallZipContents");
if (installDonePending_) {
ERROR_LOG(Log::HLE, "Cannot have two installs in progress at the same time");
return false;
return;
}
AndroidJNIThreadContext context; // Destructor detaches.
if (!File::Exists(fileName)) {
ERROR_LOG(Log::HLE, "Game file '%s' doesn't exist", fileName.c_str());
return false;
if (!File::Exists(task.fileName)) {
ERROR_LOG(Log::HLE, "Game file '%s' doesn't exist", task.fileName.c_str());
return;
}
auto st = GetI18NCategory(I18NCat::STORE);
auto di = GetI18NCategory(I18NCat::DIALOG);
auto sy = GetI18NCategory(I18NCat::SYSTEM);
std::string extension = url.GetFileExtension();
std::string urlExtension = task.url.GetFileExtension();
// Examine the URL to guess out what we're installing.
if (extension == ".cso" || extension == ".iso" || extension == ".chd") {
// TODO: Bad idea due to Android content api where we don't always get the filename.
if (urlExtension == ".cso" || urlExtension == ".iso" || urlExtension == ".chd") {
// It's a raw ISO or CSO file. We just copy it to the destination.
std::string shortFilename = url.GetFilename();
bool success = InstallRawISO(fileName, shortFilename, deleteAfter);
return success;
std::string shortFilename = task.url.GetFilename();
bool success = InstallRawISO(task.fileName, shortFilename, task.deleteAfter);
if (!success) {
ERROR_LOG(Log::HLE, "Raw ISO install failed");
// This shouldn't normally happen at all (only when putting ISOs in a store, which is not a normal use case), so skipping the translation string
SetInstallError("Failed to install raw ISO");
}
return;
}
Path pspGame = GetSysDirectory(DIRECTORY_GAME);
Path dest = pspGame;
int error = 0;
struct zip *z = ZipOpenPath(fileName);
struct zip *z = ZipOpenPath(task.fileName);
if (!z) {
g_OSD.RemoveProgressBar("install", false, 0.5f);
SetInstallError(sy->T("Unable to open zip file"));
return false;
return;
}
ZipFileInfo info;
DetectZipFileContents(z, &info);
bool success = false;
switch (info.contents) {
ZipFileInfo zipInfo;
if (task.zipFileInfo) {
// The normal case
zipInfo = task.zipFileInfo.value();
} else {
DetectZipFileContents(task.fileName, &zipInfo);
}
switch (zipInfo.contents) {
case ZipFileContents::PSP_GAME_DIR:
INFO_LOG(Log::HLE, "Installing '%s' into '%s'", fileName.c_str(), pspGame.c_str());
INFO_LOG(Log::HLE, "Installing '%s' into '%s'", task.fileName.c_str(), pspGame.c_str());
// InstallMemstickGame contains code to close (and delete) z.
success = InstallMemstickGame(z, fileName, pspGame, info, false, deleteAfter);
success = InstallMemstickGame(z, task.fileName, pspGame, zipInfo, false, task.deleteAfter);
break;
case ZipFileContents::ISO_FILE:
INFO_LOG(Log::HLE, "Installing '%s' into its containing directory", fileName.c_str());
INFO_LOG(Log::HLE, "Installing '%s' into its containing directory", task.fileName.c_str());
// InstallZippedISO contains code to close z.
success = InstallZippedISO(z, info.isoFileIndex, fileName, deleteAfter);
success = InstallZippedISO(z, zipInfo.isoFileIndex, task.fileName, task.deleteAfter);
break;
case ZipFileContents::TEXTURE_PACK:
// InstallMemstickGame contains code to close z, and works for textures too.
if (DetectTexturePackDest(z, info.textureIniIndex, dest)) {
INFO_LOG(Log::HLE, "Installing texture pack '%s' into '%s'", fileName.c_str(), dest.c_str());
if (DetectTexturePackDest(z, zipInfo.textureIniIndex, dest)) {
INFO_LOG(Log::HLE, "Installing texture pack '%s' into '%s'", task.fileName.c_str(), dest.c_str());
File::CreateFullPath(dest);
// Install as a zip file if textures.ini is in the root. Performs better on Android.
if (info.stripChars == 0) {
success = InstallMemstickZip(z, fileName, dest / "textures.zip", info, deleteAfter);
if (zipInfo.stripChars == 0) {
success = InstallMemstickZip(z, task.fileName, dest / "textures.zip", zipInfo, task.deleteAfter);
} else {
// TODO: Can probably remove this, as we now put .nomedia in /TEXTURES directly.
File::CreateEmptyFile(dest / ".nomedia");
success = InstallMemstickGame(z, fileName, dest, info, true, deleteAfter);
success = InstallMemstickGame(z, task.fileName, dest, zipInfo, true, task.deleteAfter);
}
} else {
zip_close(z);
@@ -369,12 +386,12 @@ bool GameManager::InstallZipContents(const Path &url, const Path &fileName, bool
SetInstallError(sy->T("Not a PSP game"));
zip_close(z);
z = nullptr;
if (deleteAfter)
File::Delete(fileName);
if (task.deleteAfter) {
File::Delete(task.fileName);
}
break;
}
g_OSD.RemoveProgressBar("install", success, 0.5f);
return success;
}
bool GameManager::DetectTexturePackDest(struct zip *z, int iniIndex, Path &dest) {
@@ -770,11 +787,12 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &
return true;
}
bool GameManager::InstallGameOnThread(const Path &url, const Path &fileName, bool deleteAfter) {
bool GameManager::InstallZipOnThread(ZipFileTask task) {
if (InstallInProgress() || installDonePending_) {
return false;
}
installThread_ = std::thread(std::bind(&GameManager::InstallZipContents, this, url, fileName, deleteAfter));
installThread_ = std::thread(std::bind(&GameManager::InstallZipContents, this, task));
return true;
}
+29 -19
View File
@@ -24,6 +24,7 @@
#include <thread>
#include <atomic>
#include <optional>
#include "Common/Net/HTTPClient.h"
#include "Common/File/Path.h"
@@ -34,6 +35,29 @@ enum class GameManagerState {
INSTALLING,
};
enum class ZipFileContents {
UNKNOWN,
PSP_GAME_DIR,
ISO_FILE,
TEXTURE_PACK,
};
struct ZipFileInfo {
ZipFileContents contents;
int numFiles;
int stripChars; // for PSP game
int isoFileIndex; // for ISO
int textureIniIndex; // for textures
bool ignoreMetaFiles;
};
struct ZipFileTask {
std::optional<ZipFileInfo> zipFileInfo;
Path url; // Same as filename if installing from disk. Probably not really useful.
Path fileName;
bool deleteAfter;
};
struct zip;
class FileLoader;
struct ZipFileInfo;
@@ -74,12 +98,14 @@ public:
}
// Only returns false if there's already an installation in progress.
bool InstallGameOnThread(const Path &url, const Path &tempFileName, bool deleteAfter);
bool InstallZipOnThread(ZipFileTask task);
// Separate kind of functionality from InstallZipOnThread, so doesn't re-use the task struct.
bool UninstallGameOnThread(const std::string &name);
private:
// TODO: The return value on this is a bit pointless, we can't get at it.
bool InstallZipContents(const Path &url, const Path &tempFileName, bool deleteAfter);
void InstallZipContents(ZipFileTask task);
bool InstallMemstickGame(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info, bool allowRoot, bool deleteAfter);
bool InstallMemstickZip(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info, bool deleteAfter);
bool InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter);
@@ -109,21 +135,5 @@ private:
extern GameManager g_GameManager;
enum class ZipFileContents {
UNKNOWN,
PSP_GAME_DIR,
ISO_FILE,
TEXTURE_PACK,
};
struct ZipFileInfo {
ZipFileContents contents;
int numFiles;
int stripChars; // for PSP game
int isoFileIndex; // for ISO
int textureIniIndex; // for textures
bool ignoreMetaFiles;
};
void DetectZipFileContents(struct zip *z, ZipFileInfo *info);
bool DetectZipFileContents(const Path &fileName, ZipFileInfo *info);
+9 -5
View File
@@ -50,10 +50,9 @@ void InstallZipScreen::CreateViews() {
std::string shortFilename = zipPath_.GetFilename();
// TODO: Do in the background?
ZipFileInfo zipInfo{};
DetectZipFileContents(zipPath_, &zipInfo); // Even if this fails, it sets zipInfo->contents.
DetectZipFileContents(zipPath_, &zipFileInfo_); // Even if this fails, it sets zipInfo->contents.
if (zipInfo.contents == ZipFileContents::ISO_FILE || zipInfo.contents == ZipFileContents::PSP_GAME_DIR) {
if (zipFileInfo_.contents == ZipFileContents::ISO_FILE || zipFileInfo_.contents == ZipFileContents::PSP_GAME_DIR) {
std::string_view question = iz->T("Install game from ZIP file?");
leftColumn->Add(new TextView(question, ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE)));
leftColumn->Add(new TextView(shortFilename, ALIGN_LEFT, false, new AnchorLayoutParams(10, 60, NONE, NONE)));
@@ -67,7 +66,7 @@ void InstallZipScreen::CreateViews() {
rightColumnItems->Add(new CheckBox(&deleteZipFile_, iz->T("Delete ZIP file")));
returnToHomebrew_ = true;
} else if (zipInfo.contents == ZipFileContents::TEXTURE_PACK) {
} else if (zipFileInfo_.contents == ZipFileContents::TEXTURE_PACK) {
std::string_view question = iz->T("Install textures from ZIP file?");
leftColumn->Add(new TextView(question, ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE)));
leftColumn->Add(new TextView(shortFilename, ALIGN_LEFT, false, new AnchorLayoutParams(10, 60, NONE, NONE)));
@@ -102,7 +101,12 @@ bool InstallZipScreen::key(const KeyInput &key) {
}
UI::EventReturn InstallZipScreen::OnInstall(UI::EventParams &params) {
if (g_GameManager.InstallGameOnThread(zipPath_, zipPath_, deleteZipFile_)) {
ZipFileTask task;
task.url = zipPath_;
task.fileName = zipPath_;
task.deleteAfter = deleteZipFile_;
task.zipFileInfo = zipFileInfo_;
if (g_GameManager.InstallZipOnThread(task)) {
installStarted_ = true;
if (installChoice_) {
installChoice_->SetEnabled(false);
+1
View File
@@ -43,6 +43,7 @@ private:
UI::ProgressBar *progressBar_ = nullptr;
UI::TextView *doneView_ = nullptr;
Path zipPath_;
ZipFileInfo zipFileInfo_{};
bool returnToHomebrew_ = true;
bool installStarted_ = false;
bool deleteZipFile_ = false;