// TODO : improve, look in the file more IdentifiedFileType Identify_File(FileLoader *fileLoader) { if (fileLoader == nullptr) { ERROR_LOG(LOADER, "Invalid fileLoader"); return FILETYPE_ERROR; } if (fileLoader->Path().size() == 0) { ERROR_LOG(LOADER, "Invalid filename %s", fileLoader->Path().c_str()); return FILETYPE_ERROR; } if (!fileLoader->Exists()) { return FILETYPE_ERROR; } std::string extension = fileLoader->Extension(); if (!strcasecmp(extension.c_str(), ".iso")) { // may be a psx iso, they have 2352 byte sectors. You never know what some people try to open if ((fileLoader->FileSize() % 2352) == 0) { unsigned char sync[12]; fileLoader->ReadAt(0, 12, sync); // each sector in a mode2 image starts with these 12 bytes if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00",12) == 0) { return FILETYPE_ISO_MODE2; } // maybe it also just happened to have that size, } return FILETYPE_PSP_ISO; } else if (!strcasecmp(extension.c_str(),".cso")) { return FILETYPE_PSP_ISO; } else if (!strcasecmp(extension.c_str(),".ppst")) { return FILETYPE_PPSSPP_SAVESTATE; } // First, check if it's a directory with an EBOOT.PBP in it. if (fileLoader->IsDirectory()) { std::string filename = fileLoader->Path(); if (filename.size() > 4) { // Check for existence of EBOOT.PBP, as required for "Directory games". if (File::Exists((filename + "/EBOOT.PBP").c_str())) { return FILETYPE_PSP_PBP_DIRECTORY; } // check if it's a disc directory if (File::Exists((filename + "/PSP_GAME").c_str())) { return FILETYPE_PSP_DISC_DIRECTORY; } // Not that, okay, let's guess it's a savedata directory if it has a param.sfo... if (File::Exists((filename + "/PARAM.SFO").c_str())) { return FILETYPE_PSP_SAVEDATA_DIRECTORY; } } return FILETYPE_NORMAL_DIRECTORY; } u32_le id; size_t readSize = fileLoader->ReadAt(0, 4, 1, &id); if (readSize != 1) { return FILETYPE_ERROR; } u32 psar_offset = 0, psar_id = 0; u32 _id = id; switch (_id) { case 'PBP\x00': fileLoader->ReadAt(0x24, 4, 1, &psar_offset); fileLoader->ReadAt(psar_offset, 4, 1, &psar_id); break; case '!raR': return FILETYPE_ARCHIVE_RAR; case '\x04\x03KP': case '\x06\x05KP': case '\x08\x07KP': return FILETYPE_ARCHIVE_ZIP; } if (id == 'FLE\x7F') { std::string filename = fileLoader->Path(); // There are a few elfs misnamed as pbp (like Trig Wars), accept that. if (!strcasecmp(extension.c_str(), ".plf") || strstr(filename.c_str(),"BOOT.BIN") || !strcasecmp(extension.c_str(), ".elf") || !strcasecmp(extension.c_str(), ".prx") || !strcasecmp(extension.c_str(), ".pbp")) { return FILETYPE_PSP_ELF; } return FILETYPE_UNKNOWN_ELF; } else if (id == 'PBP\x00') { // Do this PS1 eboot check FIRST before checking other eboot types. // It seems like some are malformed and slip through the PSAR check below. PBPReader pbp(fileLoader); if (pbp.IsValid() && !pbp.IsELF()) { std::vector<u8> sfoData; if (pbp.GetSubFile(PBP_PARAM_SFO, &sfoData)) { ParamSFOData paramSFO; paramSFO.ReadSFO(sfoData); // PS1 Eboots are supposed to use "ME" as their PARAM SFO category. // If they don't, and they're still malformed (e.g. PSISOIMG0000 isn't found), there's nothing we can do. if (paramSFO.GetValueString("CATEGORY") == "ME") return FILETYPE_PSP_PS1_PBP; } } if (psar_id == 'MUPN') { return FILETYPE_PSP_ISO_NP; } // PS1 PSAR begins with "PSISOIMG0000" if (psar_id == 'SISP') { return FILETYPE_PSP_PS1_PBP; } // Let's check if we got pointed to a PBP within such a directory. // If so we just move up and return the directory itself as the game. std::string path = File::GetDir(fileLoader->Path()); // If loading from memstick... size_t pos = path.find("/PSP/GAME/"); if (pos != std::string::npos) { return FILETYPE_PSP_PBP_DIRECTORY; } return FILETYPE_PSP_PBP; } else if (!strcasecmp(extension.c_str(),".pbp")) { ERROR_LOG(LOADER, "A PBP with the wrong magic number?"); return FILETYPE_PSP_PBP; } else if (!strcasecmp(extension.c_str(),".bin")) { return FILETYPE_UNKNOWN_BIN; } else if (!strcasecmp(extension.c_str(),".zip")) { return FILETYPE_ARCHIVE_ZIP; } else if (!strcasecmp(extension.c_str(),".rar")) { return FILETYPE_ARCHIVE_RAR; } else if (!strcasecmp(extension.c_str(),".r00")) { return FILETYPE_ARCHIVE_RAR; } else if (!strcasecmp(extension.c_str(),".r01")) { return FILETYPE_ARCHIVE_RAR; } else if (!extension.empty() && !strcasecmp(extension.substr(1).c_str(), ".7z")) { return FILETYPE_ARCHIVE_7Z; } return FILETYPE_UNKNOWN; }
virtual void run() { delete info_->fileLoader; info_->fileLoader = ConstructFileLoader(gamePath_); if (!info_->fileLoader->Exists()) return; std::string filename = gamePath_; info_->path = gamePath_; info_->fileType = Identify_File(info_->fileLoader); // Fallback title info_->title = getFilename(info_->path); switch (info_->fileType) { case FILETYPE_PSP_PBP: case FILETYPE_PSP_PBP_DIRECTORY: { std::string pbpFile = filename; if (info_->fileType == FILETYPE_PSP_PBP_DIRECTORY) pbpFile += "/EBOOT.PBP"; PBPReader pbp(pbpFile.c_str()); if (!pbp.IsValid()) { if (pbp.IsELF()) { goto handleELF; } ERROR_LOG(LOADER, "invalid pbp %s\n", pbpFile.c_str()); return; } // First, PARAM.SFO. size_t sfoSize; u8 *sfoData = pbp.GetSubFile(PBP_PARAM_SFO, &sfoSize); { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO(sfoData, sfoSize); info_->ParseParamSFO(); } delete [] sfoData; // Then, ICON0.PNG. { lock_guard lock(info_->lock); if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) { pbp.GetSubFileAsString(PBP_ICON0_PNG, &info_->iconTextureData); } else { // Read standard icon size_t sz; DEBUG_LOG(LOADER, "Loading unknown.png because a PBP was missing an icon"); uint8_t *contents = VFSReadFile("unknown.png", &sz); if (contents) { lock_guard lock(info_->lock); info_->iconTextureData = std::string((const char *)contents, sz); } delete [] contents; } info_->iconDataLoaded = true; } if (info_->wantFlags & GAMEINFO_WANTBG) { if (pbp.GetSubFileSize(PBP_PIC0_PNG) > 0) { lock_guard lock(info_->lock); pbp.GetSubFileAsString(PBP_PIC0_PNG, &info_->pic0TextureData); info_->pic0DataLoaded = true; } if (pbp.GetSubFileSize(PBP_PIC1_PNG) > 0) { lock_guard lock(info_->lock); pbp.GetSubFileAsString(PBP_PIC1_PNG, &info_->pic1TextureData); info_->pic1DataLoaded = true; } } if (info_->wantFlags & GAMEINFO_WANTSND) { if (pbp.GetSubFileSize(PBP_SND0_AT3) > 0) { lock_guard lock(info_->lock); pbp.GetSubFileAsString(PBP_SND0_AT3, &info_->sndFileData); info_->sndDataLoaded = true; } } } break; case FILETYPE_PSP_ELF: handleELF: // An elf on its own has no usable information, no icons, no nothing. info_->title = getFilename(filename); info_->id = "ELF000000"; info_->id_version = "ELF000000_1.00"; info_->paramSFOLoaded = true; { // Read standard icon size_t sz; uint8_t *contents = VFSReadFile("unknown.png", &sz); DEBUG_LOG(LOADER, "Loading unknown.png because there was an ELF"); if (contents) { lock_guard lock(info_->lock); info_->iconTextureData = std::string((const char *)contents, sz); info_->iconDataLoaded = true; } delete [] contents; } break; case FILETYPE_PSP_DISC_DIRECTORY: { info_->fileType = FILETYPE_PSP_ISO; SequentialHandleAllocator handles; VirtualDiscFileSystem umd(&handles, gamePath_.c_str()); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; if (ReadFileToString(&umd, "/PSP_GAME/PARAM.SFO", ¶mSFOcontents, 0)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->ParseParamSFO(); } ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->iconTextureData, &info_->lock); info_->iconDataLoaded = true; if (info_->wantFlags & GAMEINFO_WANTBG) { ReadFileToString(&umd, "/PSP_GAME/PIC0.PNG", &info_->pic0TextureData, &info_->lock); info_->pic0DataLoaded = true; ReadFileToString(&umd, "/PSP_GAME/PIC1.PNG", &info_->pic1TextureData, &info_->lock); info_->pic1DataLoaded = true; } if (info_->wantFlags & GAMEINFO_WANTSND) { ReadFileToString(&umd, "/PSP_GAME/SND0.AT3", &info_->sndFileData, &info_->lock); info_->pic1DataLoaded = true; } break; } case FILETYPE_PSP_ISO: case FILETYPE_PSP_ISO_NP: { info_->fileType = FILETYPE_PSP_ISO; SequentialHandleAllocator handles; // Let's assume it's an ISO. // TODO: This will currently read in the whole directory tree. Not really necessary for just a // few files. BlockDevice *bd = constructBlockDevice(info_->fileLoader); if (!bd) return; // nothing to do here.. ISOFileSystem umd(&handles, bd, "/PSP_GAME"); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; if (ReadFileToString(&umd, "/PSP_GAME/PARAM.SFO", ¶mSFOcontents, 0)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->ParseParamSFO(); if (info_->wantFlags & GAMEINFO_WANTBG) { ReadFileToString(&umd, "/PSP_GAME/PIC0.PNG", &info_->pic0TextureData, &info_->lock); info_->pic0DataLoaded = true; ReadFileToString(&umd, "/PSP_GAME/PIC1.PNG", &info_->pic1TextureData, &info_->lock); info_->pic1DataLoaded = true; } if (info_->wantFlags & GAMEINFO_WANTSND) { ReadFileToString(&umd, "/PSP_GAME/SND0.AT3", &info_->sndFileData, &info_->lock); info_->pic1DataLoaded = true; } } // Fall back to unknown icon if ISO is broken/is a homebrew ISO, override is allowed though if (!ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->iconTextureData, &info_->lock)) { size_t sz; uint8_t *contents = VFSReadFile("unknown.png", &sz); DEBUG_LOG(LOADER, "Loading unknown.png because no icon was found"); if (contents) { lock_guard lock(info_->lock); info_->iconTextureData = std::string((const char *)contents, sz); } delete [] contents; } info_->iconDataLoaded = true; break; } case FILETYPE_ARCHIVE_ZIP: info_->paramSFOLoaded = true; { // Read standard icon size_t sz; uint8_t *contents = VFSReadFile("zip.png", &sz); if (contents) { lock_guard lock(info_->lock); info_->iconTextureData = std::string((const char *)contents, sz); info_->iconDataLoaded = true; } delete [] contents; } break; case FILETYPE_ARCHIVE_RAR: info_->paramSFOLoaded = true; { // Read standard icon size_t sz; uint8_t *contents = VFSReadFile("rargray.png", &sz); if (contents) { lock_guard lock(info_->lock); info_->iconTextureData = std::string((const char *)contents, sz); info_->iconDataLoaded = true; } delete [] contents; } break; case FILETYPE_ARCHIVE_7Z: info_->paramSFOLoaded = true; { // Read standard icon size_t sz; uint8_t *contents = VFSReadFile("7z.png", &sz); if (contents) { lock_guard lock(info_->lock); info_->iconTextureData = std::string((const char *)contents, sz); info_->iconDataLoaded = true; } delete[] contents; } break; case FILETYPE_NORMAL_DIRECTORY: default: info_->paramSFOLoaded = true; break; } if (info_->wantFlags & GAMEINFO_WANTSIZE) { info_->gameSize = info_->GetGameSizeInBytes(); info_->saveDataSize = info_->GetSaveDataSizeInBytes(); info_->installDataSize = info_->GetInstallDataSizeInBytes(); } }
virtual void run() { getFileInfo(gamePath_.c_str(), &info_->fileInfo); if (!info_->fileInfo.exists) return; std::string filename = gamePath_; info_->fileType = Identify_File(filename); switch (info_->fileType) { case FILETYPE_PSP_PBP: case FILETYPE_PSP_PBP_DIRECTORY: { std::string pbpFile = filename; if (info_->fileType == FILETYPE_PSP_PBP_DIRECTORY) pbpFile += "/EBOOT.PBP"; PBPReader pbp(pbpFile.c_str()); if (!pbp.IsValid()) return; // First, PARAM.SFO. size_t sfoSize; u8 *sfoData = pbp.GetSubFile(PBP_PARAM_SFO, &sfoSize); { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO(sfoData, sfoSize); info_->title = info_->paramSFO.GetValueString("TITLE"); info_->id = info_->paramSFO.GetValueString("DISC_ID"); info_->id_version = info_->paramSFO.GetValueString("DISC_ID") + "_" + info_->paramSFO.GetValueString("DISC_VERSION"); info_->paramSFOLoaded = true; } delete [] sfoData; // Then, ICON0.PNG. { lock_guard lock(info_->lock); if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) { pbp.GetSubFileAsString(PBP_ICON0_PNG, &info_->iconTextureData); } else { // Read standard icon size_t sz; INFO_LOG(HLE, "Loading unknown.png because a PBP was missing an icon"); uint8_t *contents = VFSReadFile("unknown.png", &sz); if (contents) { lock_guard lock(info_->lock); info_->iconTextureData = std::string((const char *)contents, sz); } delete [] contents; } } if (info_->wantBG) { if (pbp.GetSubFileSize(PBP_PIC1_PNG) > 0) { lock_guard lock(info_->lock); pbp.GetSubFileAsString(PBP_PIC1_PNG, &info_->pic1TextureData); } } } break; case FILETYPE_PSP_ELF: // An elf on its own has no usable information, no icons, no nothing. info_->title = getFilename(filename); info_->id = "ELF000000"; info_->id_version = "ELF000000_1.00"; info_->paramSFOLoaded = true; { // Read standard icon size_t sz; uint8_t *contents = VFSReadFile("unknown.png", &sz); INFO_LOG(HLE, "Loading unknown.png because there was an ELF"); if (contents) { lock_guard lock(info_->lock); info_->iconTextureData = std::string((const char *)contents, sz); } delete [] contents; } break; case FILETYPE_PSP_DISC_DIRECTORY: { info_->fileType = FILETYPE_PSP_ISO; SequentialHandleAllocator handles; VirtualDiscFileSystem umd(&handles,gamePath_.c_str()); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; if (ReadFileToString(&umd, "/PSP_GAME/PARAM.SFO", ¶mSFOcontents, 0)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->title = info_->paramSFO.GetValueString("TITLE"); info_->id = info_->paramSFO.GetValueString("DISC_ID"); info_->id_version = info_->paramSFO.GetValueString("DISC_ID") + "_" + info_->paramSFO.GetValueString("DISC_VERSION"); info_->paramSFOLoaded = true; } ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->iconTextureData, &info_->lock); if (info_->wantBG) { ReadFileToString(&umd, "/PSP_GAME/PIC0.PNG", &info_->pic0TextureData, &info_->lock); } ReadFileToString(&umd, "/PSP_GAME/PIC1.PNG", &info_->pic1TextureData, &info_->lock); break; } case FILETYPE_PSP_ISO: case FILETYPE_PSP_ISO_NP: { info_->fileType = FILETYPE_PSP_ISO; SequentialHandleAllocator handles; // Let's assume it's an ISO. // TODO: This will currently read in the whole directory tree. Not really necessary for just a // few files. BlockDevice *bd = constructBlockDevice(gamePath_.c_str()); if (!bd) return; // nothing to do here.. ISOFileSystem umd(&handles, bd, "/PSP_GAME"); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; if (ReadFileToString(&umd, "/PSP_GAME/PARAM.SFO", ¶mSFOcontents, 0)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->title = info_->paramSFO.GetValueString("TITLE"); info_->id = info_->paramSFO.GetValueString("DISC_ID"); info_->id_version = info_->paramSFO.GetValueString("DISC_ID") + "_" + info_->paramSFO.GetValueString("DISC_VERSION"); info_->paramSFOLoaded = true; } else { // Fall back to the filename for title if ISO is broken info_->title = gamePath_; } ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->iconTextureData, &info_->lock); if (info_->wantBG) { ReadFileToString(&umd, "/PSP_GAME/PIC0.PNG", &info_->pic0TextureData, &info_->lock); } ReadFileToString(&umd, "/PSP_GAME/PIC1.PNG", &info_->pic1TextureData, &info_->lock); break; } case FILETYPE_NORMAL_DIRECTORY: info_->title = gamePath_; break; default: { std::string fn, ext; SplitPath(gamePath_, 0, &fn, &ext); info_->title = fn + "." + ext; } break; } // probably only want these when we ask for the background image... // should maybe flip the flag to "onlyIcon" if (info_->wantBG) { info_->gameSize = info_->GetGameSizeInBytes(); info_->saveDataSize = info_->GetSaveDataSizeInBytes(); } }
virtual void run() { if (!info_->LoadFromPath(gamePath_)) return; std::string filename = gamePath_; { lock_guard lock(info_->lock); info_->fileType = Identify_File(info_->GetFileLoader()); } switch (info_->fileType) { case FILETYPE_PSP_PBP: case FILETYPE_PSP_PBP_DIRECTORY: { FileLoader *pbpLoader = info_->GetFileLoader(); std::unique_ptr<FileLoader> altLoader; if (info_->fileType == FILETYPE_PSP_PBP_DIRECTORY) { pbpLoader = ConstructFileLoader(pbpLoader->Path() + "/EBOOT.PBP"); altLoader.reset(pbpLoader); } PBPReader pbp(pbpLoader); if (!pbp.IsValid()) { if (pbp.IsELF()) { goto handleELF; } ERROR_LOG(LOADER, "invalid pbp %s\n", pbpLoader->Path().c_str()); return; } // First, PARAM.SFO. std::vector<u8> sfoData; if (pbp.GetSubFile(PBP_PARAM_SFO, &sfoData)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO(sfoData); info_->ParseParamSFO(); } // Then, ICON0.PNG. if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) { lock_guard lock(info_->lock); pbp.GetSubFileAsString(PBP_ICON0_PNG, &info_->iconTextureData); } else { // Read standard icon DEBUG_LOG(LOADER, "Loading unknown.png because a PBP was missing an icon"); ReadVFSToString("unknown.png", &info_->iconTextureData, &info_->lock); } info_->iconDataLoaded = true; if (info_->wantFlags & GAMEINFO_WANTBG) { if (pbp.GetSubFileSize(PBP_PIC0_PNG) > 0) { lock_guard lock(info_->lock); pbp.GetSubFileAsString(PBP_PIC0_PNG, &info_->pic0TextureData); info_->pic0DataLoaded = true; } if (pbp.GetSubFileSize(PBP_PIC1_PNG) > 0) { lock_guard lock(info_->lock); pbp.GetSubFileAsString(PBP_PIC1_PNG, &info_->pic1TextureData); info_->pic1DataLoaded = true; } } if (info_->wantFlags & GAMEINFO_WANTSND) { if (pbp.GetSubFileSize(PBP_SND0_AT3) > 0) { lock_guard lock(info_->lock); pbp.GetSubFileAsString(PBP_SND0_AT3, &info_->sndFileData); info_->sndDataLoaded = true; } } } break; case FILETYPE_PSP_ELF: handleELF: // An elf on its own has no usable information, no icons, no nothing. { lock_guard lock(info_->lock); info_->id = "ELF000000"; info_->id_version = "ELF000000_1.00"; info_->paramSFOLoaded = true; } // Read standard icon DEBUG_LOG(LOADER, "Loading unknown.png because there was an ELF"); ReadVFSToString("unknown.png", &info_->iconTextureData, &info_->lock); info_->iconDataLoaded = true; break; case FILETYPE_PSP_SAVEDATA_DIRECTORY: { SequentialHandleAllocator handles; VirtualDiscFileSystem umd(&handles, gamePath_.c_str()); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; if (ReadFileToString(&umd, "/PARAM.SFO", ¶mSFOcontents, 0)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->ParseParamSFO(); } ReadFileToString(&umd, "/ICON0.PNG", &info_->iconTextureData, &info_->lock); info_->iconDataLoaded = true; if (info_->wantFlags & GAMEINFO_WANTBG) { ReadFileToString(&umd, "/PIC1.PNG", &info_->pic1TextureData, &info_->lock); info_->pic1DataLoaded = true; } break; } case FILETYPE_PPSSPP_SAVESTATE: { info_->SetTitle(SaveState::GetTitle(gamePath_)); lock_guard guard(info_->lock); // Let's use the screenshot as an icon, too. std::string screenshotPath = ReplaceAll(gamePath_, ".ppst", ".jpg"); if (File::Exists(screenshotPath)) { if (readFileToString(false, screenshotPath.c_str(), info_->iconTextureData)) { info_->iconDataLoaded = true; } } break; } case FILETYPE_PSP_DISC_DIRECTORY: { info_->fileType = FILETYPE_PSP_ISO; SequentialHandleAllocator handles; VirtualDiscFileSystem umd(&handles, gamePath_.c_str()); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; if (ReadFileToString(&umd, "/PSP_GAME/PARAM.SFO", ¶mSFOcontents, 0)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->ParseParamSFO(); } ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->iconTextureData, &info_->lock); info_->iconDataLoaded = true; if (info_->wantFlags & GAMEINFO_WANTBG) { ReadFileToString(&umd, "/PSP_GAME/PIC0.PNG", &info_->pic0TextureData, &info_->lock); info_->pic0DataLoaded = true; ReadFileToString(&umd, "/PSP_GAME/PIC1.PNG", &info_->pic1TextureData, &info_->lock); info_->pic1DataLoaded = true; } if (info_->wantFlags & GAMEINFO_WANTSND) { ReadFileToString(&umd, "/PSP_GAME/SND0.AT3", &info_->sndFileData, &info_->lock); info_->pic1DataLoaded = true; } break; } case FILETYPE_PSP_ISO: case FILETYPE_PSP_ISO_NP: { info_->fileType = FILETYPE_PSP_ISO; SequentialHandleAllocator handles; // Let's assume it's an ISO. // TODO: This will currently read in the whole directory tree. Not really necessary for just a // few files. BlockDevice *bd = constructBlockDevice(info_->GetFileLoader()); if (!bd) return; // nothing to do here.. ISOFileSystem umd(&handles, bd, "/PSP_GAME"); // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; if (ReadFileToString(&umd, "/PSP_GAME/PARAM.SFO", ¶mSFOcontents, nullptr)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->ParseParamSFO(); if (info_->wantFlags & GAMEINFO_WANTBG) { ReadFileToString(&umd, "/PSP_GAME/PIC0.PNG", &info_->pic0TextureData, &info_->lock); info_->pic0DataLoaded = true; ReadFileToString(&umd, "/PSP_GAME/PIC1.PNG", &info_->pic1TextureData, &info_->lock); info_->pic1DataLoaded = true; } if (info_->wantFlags & GAMEINFO_WANTSND) { ReadFileToString(&umd, "/PSP_GAME/SND0.AT3", &info_->sndFileData, &info_->lock); info_->pic1DataLoaded = true; } } // Fall back to unknown icon if ISO is broken/is a homebrew ISO, override is allowed though if (!ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->iconTextureData, &info_->lock)) { DEBUG_LOG(LOADER, "Loading unknown.png because no icon was found"); ReadVFSToString("unknown.png", &info_->iconTextureData, &info_->lock); } info_->iconDataLoaded = true; break; } case FILETYPE_ARCHIVE_ZIP: info_->paramSFOLoaded = true; { ReadVFSToString("zip.png", &info_->iconTextureData, &info_->lock); info_->iconDataLoaded = true; } break; case FILETYPE_ARCHIVE_RAR: info_->paramSFOLoaded = true; { ReadVFSToString("rargray.png", &info_->iconTextureData, &info_->lock); info_->iconDataLoaded = true; } break; case FILETYPE_ARCHIVE_7Z: info_->paramSFOLoaded = true; { ReadVFSToString("7z.png", &info_->iconTextureData, &info_->lock); info_->iconDataLoaded = true; } break; case FILETYPE_NORMAL_DIRECTORY: default: info_->paramSFOLoaded = true; break; } info_->hasConfig = g_Config.hasGameConfig(info_->id); if (info_->wantFlags & GAMEINFO_WANTSIZE) { lock_guard lock(info_->lock); info_->gameSize = info_->GetGameSizeInBytes(); info_->saveDataSize = info_->GetSaveDataSizeInBytes(); info_->installDataSize = info_->GetInstallDataSizeInBytes(); } info_->pending = false; info_->DisposeFileLoader(); }
// TODO : improve, look in the file more IdentifiedFileType Identify_File(std::string &filename) { if (filename.size() == 0) { ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); return FILETYPE_ERROR; } FileInfo info; if (!getFileInfo(filename.c_str(), &info)) { return FILETYPE_ERROR; } std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : ""; if (!strcasecmp(extension.c_str(),".iso")) { // may be a psx iso, they have 2352 byte sectors. You never know what some people try to open if ((info.size % 2352) == 0) { FILE *f = File::OpenCFile(filename.c_str(), "rb"); if (!f) { // File does not exists return FILETYPE_ERROR; } unsigned char sync[12]; fread(sync,1,12,f); fclose(f); // each sector in a mode2 image starts with these 12 bytes if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00",12) == 0) { return FILETYPE_ISO_MODE2; } // maybe it also just happened to have that size, } return FILETYPE_PSP_ISO; } else if (!strcasecmp(extension.c_str(),".cso")) { return FILETYPE_PSP_ISO; } // First, check if it's a directory with an EBOOT.PBP in it. if (info.isDirectory) { if (filename.size() > 4) { FileInfo ebootInfo; // Check for existence of EBOOT.PBP, as required for "Directory games". if (getFileInfo((filename + "/EBOOT.PBP").c_str(), &ebootInfo)) { if (ebootInfo.exists) { return FILETYPE_PSP_PBP_DIRECTORY; } } // check if it's a disc directory if (getFileInfo((filename + "/PSP_GAME").c_str(), &ebootInfo)) { if (ebootInfo.exists) { return FILETYPE_PSP_DISC_DIRECTORY; } } } return FILETYPE_NORMAL_DIRECTORY; } FILE *f = File::OpenCFile(filename.c_str(), "rb"); if (!f) { // File does not exists return FILETYPE_ERROR; } u32_le id; size_t readSize = fread(&id, 4, 1, f); if (readSize != 1) { fclose(f); return FILETYPE_ERROR; } u32 psar_offset = 0, psar_id = 0; u32 _id = id; switch (_id) { case 'PBP\x00': fseek(f, 0x24, SEEK_SET); fread(&psar_offset, 4, 1, f); fseek(f, psar_offset, SEEK_SET); fread(&psar_id, 4, 1, f); break; case '!raR': return FILETYPE_ARCHIVE_RAR; case '\x04\x03KP': case '\x06\x05KP': case '\x08\x07KP': return FILETYPE_ARCHIVE_ZIP; } fclose(f); if (id == 'FLE\x7F') { // There are a few elfs misnamed as pbp (like Trig Wars), accept that. if (!strcasecmp(extension.c_str(), ".plf") || strstr(filename.c_str(),"BOOT.BIN") || !strcasecmp(extension.c_str(), ".elf") || !strcasecmp(extension.c_str(), ".prx") || !strcasecmp(extension.c_str(), ".pbp")) { return FILETYPE_PSP_ELF; } return FILETYPE_UNKNOWN_ELF; } else if (id == 'PBP\x00') { // Do this PS1 eboot check FIRST before checking other eboot types. // It seems like some are malformed and slip through the PSAR check below. PBPReader pbp(filename.c_str()); if (pbp.IsValid()) { if (!pbp.IsELF()) { size_t sfoSize; u8 *sfoData = pbp.GetSubFile(PBP_PARAM_SFO, &sfoSize); { recursive_mutex _lock; lock_guard lock(_lock); ParamSFOData paramSFO; paramSFO.ReadSFO(sfoData, sfoSize); // PS1 Eboots are supposed to use "ME" as their PARAM SFO category. // If they don't, and they're still malformed (e.g. PSISOIMG0000 isn't found), there's nothing we can do. if (paramSFO.GetValueString("CATEGORY") == "ME") return FILETYPE_PSP_PS1_PBP; } delete[] sfoData; } } if (psar_id == 'MUPN') { return FILETYPE_PSP_ISO_NP; } // PS1 PSAR begins with "PSISOIMG0000" if (psar_id == 'SISP') { return FILETYPE_PSP_PS1_PBP; } // Let's check if we got pointed to a PBP within such a directory. // If so we just move up and return the directory itself as the game. std::string path = getDir(filename); // If loading from memstick... size_t pos = path.find("/PSP/GAME/"); if (pos != std::string::npos) { filename = path; return FILETYPE_PSP_PBP_DIRECTORY; } return FILETYPE_PSP_PBP; } else if (!strcasecmp(extension.c_str(),".pbp")) { ERROR_LOG(LOADER, "A PBP with the wrong magic number?"); return FILETYPE_PSP_PBP; } else if (!strcasecmp(extension.c_str(),".bin")) { return FILETYPE_UNKNOWN_BIN; } else if (!strcasecmp(extension.c_str(),".zip")) { return FILETYPE_ARCHIVE_ZIP; } else if (!strcasecmp(extension.c_str(),".rar")) { return FILETYPE_ARCHIVE_RAR; } else if (!strcasecmp(extension.c_str(),".r00")) { return FILETYPE_ARCHIVE_RAR; } else if (!strcasecmp(extension.c_str(),".r01")) { return FILETYPE_ARCHIVE_RAR; } return FILETYPE_UNKNOWN; }