mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 09:39:33 +01:00
Zip install: Reject PS3 save data
A zipped PS3 save folder has a PARAM.SFO and ICON0.PNG, the same layout as a PSP save, so it was offered for install as one. PS3 saves have CATEGORY SD in the SFO (PSP saves have MS) and a PARAM.PFD; either now makes the zip unrecognized. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4da13731aa
commit
e3ea1adc48
2 files changed
+60
No files matched your search
@@ -676,6 +676,7 @@ void DetectZipFileContents(zip_t *z, ZipFileInfo *info) {
|
||||
bool hasIcon0PNG = false;
|
||||
bool hasPRX = false;
|
||||
bool hasPluginIni = false;
|
||||
bool isPS3SaveData = false; // Same PARAM.SFO + ICON0.PNG layout as a PSP save, but useless to us.
|
||||
s64 totalFileSize = 0;
|
||||
std::vector<ArchiveEntry> archiveEntries; // In the root or one level down, where a disc image can be.
|
||||
|
||||
@@ -757,6 +758,10 @@ void DetectZipFileContents(zip_t *z, ZipFileInfo *info) {
|
||||
if (ZipExtractFileToMemory(z, i, ¶mSFOContents)) {
|
||||
ParamSFOData sfo;
|
||||
if (sfo.ReadSFO((const u8 *)paramSFOContents.data(), paramSFOContents.size())) {
|
||||
// PSP saves have category MS, PS3 saves SD.
|
||||
if (sfo.GetValueString("CATEGORY") == "SD") {
|
||||
isPS3SaveData = true;
|
||||
}
|
||||
if (sfo.HasKey("TITLE")) {
|
||||
info->gameTitle = sfo.GetValueString("TITLE");
|
||||
info->savedataTitle = sfo.GetValueString("SAVEDATA_TITLE");
|
||||
@@ -772,6 +777,9 @@ void DetectZipFileContents(zip_t *z, ZipFileInfo *info) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (lowerCaseName == "param.pfd" || endsWith(lowerCaseName, "/param.pfd")) {
|
||||
// The PS3's save data protection file. PSP saves don't have one.
|
||||
isPS3SaveData = true;
|
||||
} else if (endsWith(lowerCaseName, "/icon0.png")) {
|
||||
hasIcon0PNG = true;
|
||||
} else if (endsWith(lowerCaseName, "/plugin.ini") && slashCount >= 1) {
|
||||
@@ -827,6 +835,9 @@ void DetectZipFileContents(zip_t *z, ZipFileInfo *info) {
|
||||
info->stripChars = stripCharsTexturePack;
|
||||
info->ignoreMetaFiles = true;
|
||||
info->contents = ZipFileContents::TEXTURE_PACK;
|
||||
} else if (isPS3SaveData) {
|
||||
WARN_LOG(Log::Loader, "Zip contains PS3 save data, not PSP");
|
||||
info->contents = ZipFileContents::UNKNOWN;
|
||||
} else if (stripChars == 0 && filesInRoot == 0 && hasParamSFO && hasIcon0PNG && !isExtractedISO) {
|
||||
// As downloaded from GameFAQs, for example.
|
||||
info->contents = ZipFileContents::SAVE_DATA;
|
||||
|
||||
@@ -184,6 +184,53 @@ static bool TestRootSaveDataZip() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// A PS3 save folder has the same PARAM.SFO + ICON0.PNG layout as a PSP one. Each signal alone must reject it.
|
||||
static bool TestPS3SaveDataZip() {
|
||||
Path tempRoot = File::GetCurDirectory() / "unittest_zip_ps3save_test";
|
||||
File::DeleteDirRecursively(tempRoot);
|
||||
EXPECT_TRUE(File::CreateDir(tempRoot));
|
||||
|
||||
for (int variant = 0; variant < 2; variant++) {
|
||||
const bool sdCategory = variant == 0;
|
||||
ParamSFOData sfo;
|
||||
sfo.SetValue("CATEGORY", sdCategory ? "SD" : "MS", 4);
|
||||
sfo.SetValue("TITLE", "Some PS3 game", 128);
|
||||
sfo.SetValue("SAVEDATA_DIRECTORY", "BCES00141", 64);
|
||||
u8 *sfoData = nullptr;
|
||||
size_t sfoSize = 0;
|
||||
sfo.WriteSFO(&sfoData, &sfoSize);
|
||||
std::string sfoContents((const char *)sfoData, sfoSize);
|
||||
delete[] sfoData;
|
||||
|
||||
Path zipPath = tempRoot / "ps3save.zip";
|
||||
int errorp = 0;
|
||||
zip_t *z = zip_open(zipPath.c_str(), ZIP_CREATE | ZIP_TRUNCATE, &errorp);
|
||||
EXPECT_TRUE(z != nullptr);
|
||||
static const char *const contents = "data";
|
||||
zip_source_t *source = zip_source_buffer(z, sfoContents.data(), sfoContents.size(), 0);
|
||||
EXPECT_TRUE(zip_file_add(z, "BCES00141/PARAM.SFO", source, ZIP_FL_ENC_UTF_8) >= 0);
|
||||
std::vector<const char *> names = { "BCES00141/ICON0.PNG", "BCES00141/0" };
|
||||
if (!sdCategory) {
|
||||
names.push_back("BCES00141/PARAM.PFD");
|
||||
}
|
||||
for (const char *name : names) {
|
||||
source = zip_source_buffer(z, contents, strlen(contents), 0);
|
||||
EXPECT_TRUE(zip_file_add(z, name, source, ZIP_FL_ENC_UTF_8) >= 0);
|
||||
}
|
||||
EXPECT_TRUE(zip_close(z) == 0);
|
||||
|
||||
z = zip_open(zipPath.c_str(), 0, &errorp);
|
||||
EXPECT_TRUE(z != nullptr);
|
||||
ZipFileInfo info;
|
||||
DetectZipFileContents(z, &info);
|
||||
zip_close(z);
|
||||
EXPECT_EQ_INT((int)info.contents, (int)ZipFileContents::UNKNOWN);
|
||||
}
|
||||
|
||||
File::DeleteDirRecursively(tempRoot);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestIsSafePathComponent() {
|
||||
EXPECT_TRUE(IsSafePathComponent("ULUS10041"));
|
||||
EXPECT_TRUE(IsSafePathComponent("NPJH-50465"));
|
||||
@@ -214,5 +261,7 @@ bool TestZipSlip() {
|
||||
return false;
|
||||
if (!TestRootSaveDataZip())
|
||||
return false;
|
||||
if (!TestPS3SaveDataZip())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
Reference in new issue
Block a user