mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-11 16:49:27 +01:00
Install PS1 discs from zip and 7z archives, and show them as playable only with a firmware that runs them
A zip or 7z with a PS1 disc in it (a cue sheet and the files it names, a .ccd with its .img and .sub, or a lone raw .bin or .img) is now installed like a zipped ISO. A disc of several files goes into a folder of its own, named after the cue sheet or .ccd. An ISO in the archive still takes priority, and a lone .bin or .img only counts when nothing else does. The game screen offers Play for a PS1 disc image only when the installed firmware's POPS can run it: 3.95 to 6.61, with popsman.prx. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
23dffa9db3
commit
34a0090a18
11 files changed
+330
-52
No files matched your search
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "Common/File/DirListing.h"
|
||||
@@ -148,11 +149,15 @@ bool IsPS1CueOrCcd(FileLoader *fileLoader) {
|
||||
}
|
||||
|
||||
std::vector<std::string> CueSheetFileNames(const Path &cuePath) {
|
||||
std::vector<std::string> names;
|
||||
std::string text;
|
||||
if (!ReadSmallTextFile(cuePath, &text)) {
|
||||
return names;
|
||||
return {};
|
||||
}
|
||||
return CueSheetFileNamesFromText(text);
|
||||
}
|
||||
|
||||
std::vector<std::string> CueSheetFileNamesFromText(std::string_view text) {
|
||||
std::vector<std::string> names;
|
||||
std::vector<std::string_view> lines;
|
||||
SplitString(text, '\n', lines);
|
||||
for (std::string_view line : lines) {
|
||||
@@ -208,6 +213,77 @@ void RemoveDescribedDiscImages(std::vector<File::FileInfo> *files) {
|
||||
}), files->end());
|
||||
}
|
||||
|
||||
bool FindPS1DiscFiles(const std::vector<ArchiveEntry> &entries, const std::function<bool(const std::string &name, std::string *text)> &readText, std::vector<std::string> *discFiles) {
|
||||
std::map<std::string, std::string> byLowerName;
|
||||
for (const ArchiveEntry &entry : entries) {
|
||||
byLowerName[AsciiToLower(ReplaceAll(entry.name, "\\", "/"))] = entry.name;
|
||||
}
|
||||
auto find = [&](const std::string &name, std::string *found) {
|
||||
auto it = byLowerName.find(AsciiToLower(ReplaceAll(name, "\\", "/")));
|
||||
if (it == byLowerName.end()) {
|
||||
return false;
|
||||
}
|
||||
*found = it->second;
|
||||
return true;
|
||||
};
|
||||
auto extension = [](const std::string &name) {
|
||||
const size_t dot = name.find_last_of("./");
|
||||
return dot != std::string::npos && name[dot] == '.' ? AsciiToLower(name.substr(dot)) : std::string();
|
||||
};
|
||||
|
||||
for (const ArchiveEntry &entry : entries) {
|
||||
const std::string ext = extension(entry.name);
|
||||
const std::string stem = entry.name.substr(0, entry.name.size() - ext.size());
|
||||
const size_t slash = entry.name.find_last_of("/\\");
|
||||
const std::string dir = slash == std::string::npos ? "" : entry.name.substr(0, slash + 1);
|
||||
std::vector<std::string> files = { entry.name };
|
||||
std::string found;
|
||||
if (ext == ".cue") {
|
||||
std::string text;
|
||||
if (!readText(entry.name, &text)) {
|
||||
continue;
|
||||
}
|
||||
const std::vector<std::string> names = CueSheetFileNamesFromText(text);
|
||||
bool all = !names.empty();
|
||||
for (const std::string &name : names) {
|
||||
if (find(dir + name, &found) || (names.size() == 1 && (find(stem + ".bin", &found) || find(stem + ".img", &found)))) {
|
||||
files.push_back(found);
|
||||
} else {
|
||||
all = false;
|
||||
}
|
||||
}
|
||||
if (!all) {
|
||||
continue;
|
||||
}
|
||||
} else if (ext == ".ccd") {
|
||||
if (!find(stem + ".img", &found)) {
|
||||
continue;
|
||||
}
|
||||
files.push_back(found);
|
||||
if (find(stem + ".sub", &found)) {
|
||||
files.push_back(found);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
*discFiles = files;
|
||||
return true;
|
||||
}
|
||||
|
||||
const ArchiveEntry *largest = nullptr;
|
||||
for (const ArchiveEntry &entry : entries) {
|
||||
const std::string ext = extension(entry.name);
|
||||
if ((ext == ".bin" || ext == ".img") && entry.size > 0 && entry.size % SECTOR_SIZE == 0 && (!largest || entry.size > largest->size)) {
|
||||
largest = &entry;
|
||||
}
|
||||
}
|
||||
if (largest) {
|
||||
*discFiles = { largest->name };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PS1EbootFileLoader::PS1EbootFileLoader(const Path &path) : path_(path) {
|
||||
const std::string ext = path.GetFileExtension();
|
||||
std::string text;
|
||||
|
||||
Reference in new issue
Block a user