rpcs3/rpcs3/Loader/disc.cpp
2023-02-15 08:58:02 +01:00

150 lines
3.7 KiB
C++

#include "stdafx.h"
#include "disc.h"
#include "PSF.h"
#include "util/logs.hpp"
#include "Utilities/StrUtil.h"
#include "Emu/System.h"
#include "Emu/system_utils.hpp"
LOG_CHANNEL(disc_log, "DISC");
namespace disc
{
disc_type get_disc_type(std::string path, std::string& disc_root, std::string& ps3_game_dir)
{
disc_type type = disc_type::unknown;
disc_root.clear();
ps3_game_dir.clear();
if (path.empty())
{
disc_log.error("Can not determine disc type. Path is empty.");
return disc_type::invalid;
}
if (!fs::is_dir(path))
{
disc_log.error("Can not determine disc type. Path not a directory: '%s'", path);
return disc_type::invalid;
}
// Check for PS3 game first.
std::string elf_path;
if (const game_boot_result result = Emulator::GetElfPathFromDir(elf_path, path);
result == game_boot_result::no_errors)
{
// Every error past this point is considered a corrupt disc.
std::string sfb_dir;
const std::string elf_dir = fs::get_parent_dir(elf_path);
Emulator::GetBdvdDir(disc_root, sfb_dir, ps3_game_dir, elf_dir);
if (!fs::is_dir(disc_root) || !fs::is_dir(sfb_dir) || ps3_game_dir.empty())
{
disc_log.error("Not a PS3 disc: invalid folder (bdvd_dir='%s', sfb_dir='%s', game_dir='%s')", disc_root, sfb_dir, ps3_game_dir);
return disc_type::invalid;
}
// Load PARAM.SFO
const std::string sfo_dir = rpcs3::utils::get_sfo_dir_from_game_path(elf_dir + "/../", "");
const psf::registry _psf = psf::load_object(sfo_dir + "/PARAM.SFO");
if (_psf.empty())
{
disc_log.error("Not a PS3 disc: Corrupted PARAM.SFO found! (path='%s/PARAM.SFO')", sfo_dir);
return disc_type::invalid;
}
const std::string cat = std::string(psf::get_string(_psf, "CATEGORY"));
if (cat != "DG")
{
disc_log.error("Not a PS3 disc: Wrong category '%s'.", cat);
return disc_type::invalid;
}
return disc_type::ps3;
}
disc_log.notice("Not a PS3 disc: Elf not found. Looking for SYSTEM.CNF... (path='%s')", path);
std::vector<std::string> lines;
// Try to find SYSTEM.CNF
for (std::string search_dir = path;;)
{
if (fs::file file(search_dir + "/SYSTEM.CNF"); file)
{
disc_root = search_dir + "/";
lines = fmt::split(file.to_string(), {"\n"});
break;
}
std::string parent_dir = fs::get_parent_dir(search_dir);
if (parent_dir.size() == search_dir.size())
{
// Keep looking until root directory is reached
disc_log.error("SYSTEM.CNF not found in path: '%s'", path);
return disc_type::invalid;
}
search_dir = std::move(parent_dir);
}
for (usz i = 0; i < lines.size(); i++)
{
const std::string& line = lines[i];
const usz pos = line.find('=');
if (pos == umax)
{
continue;
}
const std::string key = fmt::trim(line.substr(0, pos));
std::string value;
if (pos != (line.size() - 1))
{
value = fmt::trim(line.substr(pos + 1));
}
if (value.empty() && i != (lines.size() - 1) && line.size() != 1)
{
// Some games have a character on the last line of the file, don't print the error in those cases.
disc_log.warning("Unusual or malformed entry in SYSTEM.CNF ignored: %s", line);
continue;
}
if (key == "BOOT2")
{
disc_log.notice("SYSTEM.CNF - Detected PS2 Disc = %s", value);
type = disc_type::ps2;
}
else if (key == "BOOT")
{
disc_log.notice("SYSTEM.CNF - Detected PSX/PSone Disc = %s", value);
type = disc_type::ps1;
}
else if (key == "VMODE")
{
disc_log.notice("SYSTEM.CNF - Disc region type = %s", value);
}
else if (key == "VER")
{
disc_log.notice("SYSTEM.CNF - Software version = %s", value);
}
}
if (type == disc_type::unknown)
{
disc_log.error("SYSTEM.CNF - Disc is not a PSX/PSone or PS2 game!");
}
return type;
}
}