mirror of https://github.com/PCSX2/pcsx2.git
CDVD: Remove exceptions (completely this time)
The actual reads are still missing error checking...
This commit is contained in:
parent
ab4592b8e9
commit
52266d7ac0
|
@ -1357,42 +1357,40 @@ std::string_view Achievements::GetELFNameForHash(const std::string& elf_path)
|
|||
|
||||
std::optional<std::vector<u8>> Achievements::ReadELFFromCurrentDisc(const std::string& elf_path)
|
||||
{
|
||||
// This CDVD stuff is super nasty and full of exceptions..
|
||||
std::optional<std::vector<u8>> ret;
|
||||
try
|
||||
|
||||
// ELF suffix hack. Taken from CDVD::loadElf
|
||||
// MLB2k6 has an elf whose suffix is actually ;2
|
||||
std::string filepath(elf_path);
|
||||
const std::string::size_type semi_pos = filepath.rfind(';');
|
||||
if (semi_pos != std::string::npos && std::string_view(filepath).substr(semi_pos) != ";1")
|
||||
{
|
||||
// ELF suffix hack. Taken from CDVD::loadElf
|
||||
// MLB2k6 has an elf whose suffix is actually ;2
|
||||
std::string filepath(elf_path);
|
||||
const std::string::size_type semi_pos = filepath.rfind(';');
|
||||
if (semi_pos != std::string::npos && std::string_view(filepath).substr(semi_pos) != ";1")
|
||||
{
|
||||
Console.Warning("(Achievements) Non-conforming version suffix (%s) detected and replaced.", elf_path.c_str());
|
||||
filepath.erase(semi_pos);
|
||||
filepath += ";1";
|
||||
}
|
||||
|
||||
IsoFSCDVD isofs;
|
||||
IsoFile file(isofs, filepath);
|
||||
const u32 size = file.getLength();
|
||||
|
||||
ret = std::vector<u8>();
|
||||
ret->resize(size);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
const s32 bytes_read = file.read(ret->data(), static_cast<s32>(size));
|
||||
if (bytes_read != static_cast<s32>(size))
|
||||
{
|
||||
Console.Error("(Achievements) Only read %d of %u bytes of ELF '%s'", bytes_read, size, elf_path.c_str());
|
||||
ret.reset();
|
||||
}
|
||||
}
|
||||
Console.Warning(fmt::format("(Achievements) Non-conforming version suffix ({}) detected and replaced.", elf_path));
|
||||
filepath.erase(semi_pos);
|
||||
filepath += ";1";
|
||||
}
|
||||
catch (...)
|
||||
|
||||
IsoFSCDVD isofs;
|
||||
IsoFile file(isofs);
|
||||
Error error;
|
||||
if (!file.open(filepath, &error))
|
||||
{
|
||||
Console.Error("(Achievements) Caught exception while trying to read ELF '%s'.", elf_path.c_str());
|
||||
ret.reset();
|
||||
Console.Error(fmt::format("(Achievements) Failed to open ELF '{}' on disc: {}", elf_path, error.GetDescription()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
const u32 size = file.getLength();
|
||||
ret = std::vector<u8>();
|
||||
ret->resize(size);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
const s32 bytes_read = file.read(ret->data(), static_cast<s32>(size));
|
||||
if (bytes_read != static_cast<s32>(size))
|
||||
{
|
||||
Console.Error(fmt::format("(Achievements) Only read {} of {} bytes of ELF '{}'", bytes_read, size, elf_path));
|
||||
ret.reset();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -383,140 +383,118 @@ s32 cdvdWriteConfig(const u8* config)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Sets ElfCRC to the CRC of the game bound to the CDVD source.
|
||||
std::unique_ptr<ElfObject> cdvdLoadElf(std::string filename, bool isPSXElf)
|
||||
bool cdvdLoadElf(ElfObject* elfo, std::string elfpath, bool isPSXElf, Error* error)
|
||||
{
|
||||
if (StringUtil::StartsWith(filename, "host:"))
|
||||
if (StringUtil::StartsWith(elfpath, "host:"))
|
||||
{
|
||||
std::string host_filename(filename.substr(5));
|
||||
s64 host_size = FileSystem::GetPathFileSize(host_filename.c_str());
|
||||
return std::make_unique<ElfObject>(std::move(host_filename), static_cast<u32>(std::max<s64>(host_size, 0)), isPSXElf);
|
||||
std::string host_filename(elfpath.substr(5));
|
||||
if (!elfo->OpenFile(host_filename, isPSXElf, error))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mimic PS2 behavior!
|
||||
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
|
||||
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
|
||||
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
|
||||
//
|
||||
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
|
||||
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
|
||||
// or anything else. Its all ignored.
|
||||
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
|
||||
// or lower level filesystem APIs (fortunately that doesn't affect us).
|
||||
//
|
||||
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
|
||||
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
|
||||
// be sufficient (no known games have their ELF binary as anything but version ;1)
|
||||
const std::string::size_type semi_pos = elfpath.rfind(';');
|
||||
if (semi_pos != std::string::npos && std::string_view(elfpath).substr(semi_pos) != ";1")
|
||||
{
|
||||
Console.WriteLn(Color_Blue, "(LoadELF) Non-conforming version suffix (%s) detected and replaced.", elfpath.c_str());
|
||||
elfpath.erase(semi_pos);
|
||||
elfpath += ";1";
|
||||
}
|
||||
|
||||
// Fix cdrom:path, the iso reader doesn't like it.
|
||||
if (StringUtil::StartsWith(elfpath, "cdrom:") && elfpath[6] != '\\' && elfpath[6] != '/')
|
||||
elfpath.insert(6, 1, '\\');
|
||||
|
||||
IsoFSCDVD isofs;
|
||||
IsoFile file(isofs);
|
||||
if (!file.open(elfpath, error) || !elfo->OpenIsoFile(elfpath, file, isPSXElf, error))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mimic PS2 behavior!
|
||||
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
|
||||
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
|
||||
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
|
||||
//
|
||||
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
|
||||
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
|
||||
// or anything else. Its all ignored.
|
||||
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
|
||||
// or lower level filesystem APIs (fortunately that doesn't affect us).
|
||||
//
|
||||
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
|
||||
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
|
||||
// be sufficient (no known games have their ELF binary as anything but version ;1)
|
||||
const std::string::size_type semi_pos = filename.rfind(';');
|
||||
if (semi_pos != std::string::npos && std::string_view(filename).substr(semi_pos) != ";1")
|
||||
{
|
||||
Console.WriteLn(Color_Blue, "(LoadELF) Non-conforming version suffix (%s) detected and replaced.", filename.c_str());
|
||||
filename.erase(semi_pos);
|
||||
filename += ";1";
|
||||
}
|
||||
|
||||
// Fix cdrom:path, the iso reader doesn't like it.
|
||||
if (StringUtil::StartsWith(filename, "cdrom:") && filename[6] != '\\' && filename[6] != '/')
|
||||
filename.insert(6, 1, '\\');
|
||||
|
||||
IsoFSCDVD isofs;
|
||||
IsoFile file(isofs, filename);
|
||||
return std::make_unique<ElfObject>(std::move(filename), file, isPSXElf);
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 cdvdGetElfCRC(const std::string& path)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Yay for write-after-read here. Isn't our ELF parser great....
|
||||
const s64 host_size = FileSystem::GetPathFileSize(path.c_str());
|
||||
if (host_size <= 0)
|
||||
return 0;
|
||||
|
||||
std::unique_ptr<ElfObject> elfptr(std::make_unique<ElfObject>(path, static_cast<u32>(std::max<s64>(host_size, 0)), false));
|
||||
elfptr->loadHeaders();
|
||||
return elfptr->getCRC();
|
||||
}
|
||||
catch ([[maybe_unused]] Exception::FileNotFound& e)
|
||||
{
|
||||
ElfObject elfo;
|
||||
if (!elfo.OpenFile(path, false, nullptr))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return elfo.GetCRC();
|
||||
}
|
||||
|
||||
// return value:
|
||||
// 0 - Invalid or unknown disc.
|
||||
// 1 - PS1 CD
|
||||
// 2 - PS2 CD
|
||||
static CDVDDiscType GetPS2ElfName(std::string* name, std::string* version)
|
||||
{
|
||||
CDVDDiscType retype = CDVDDiscType::Other;
|
||||
name->clear();
|
||||
version->clear();
|
||||
|
||||
try {
|
||||
IsoFSCDVD isofs;
|
||||
IsoFile file( isofs, "SYSTEM.CNF;1");
|
||||
Error error;
|
||||
IsoFSCDVD isofs;
|
||||
IsoFile file(isofs);
|
||||
if (!file.open("SYSTEM.CNF;1", &error))
|
||||
{
|
||||
Console.Error(fmt::format("(GetElfName) Failed to open SYSTEM.CNF: {}", error.GetDescription()));
|
||||
return CDVDDiscType::Other;
|
||||
}
|
||||
|
||||
int size = file.getLength();
|
||||
if( size == 0 ) return CDVDDiscType::Other;
|
||||
const int size = file.getLength();
|
||||
if (size == 0)
|
||||
return CDVDDiscType::Other;
|
||||
|
||||
while( !file.eof() )
|
||||
{
|
||||
const std::string line(file.readLine());
|
||||
std::string_view key, value;
|
||||
if (!StringUtil::ParseAssignmentString(line, &key, &value))
|
||||
continue;
|
||||
while (!file.eof())
|
||||
{
|
||||
const std::string line(file.readLine());
|
||||
std::string_view key, value;
|
||||
if (!StringUtil::ParseAssignmentString(line, &key, &value))
|
||||
continue;
|
||||
|
||||
if( value.empty() && file.getLength() != file.getSeekPos() )
|
||||
{ // Some games have a character on the last line of the file, don't print the error in those cases.
|
||||
Console.Warning( "(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:" );
|
||||
Console.Indent().WriteLn(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if( key == "BOOT2" )
|
||||
{
|
||||
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PS2 Disc = %.*s",
|
||||
static_cast<int>(value.size()), value.data());
|
||||
*name = value;
|
||||
retype = CDVDDiscType::PS2Disc;
|
||||
}
|
||||
else if( key == "BOOT" )
|
||||
{
|
||||
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PSX/PSone Disc = %.*s",
|
||||
static_cast<int>(value.size()), value.data());
|
||||
*name = value;
|
||||
retype = CDVDDiscType::PS1Disc;
|
||||
}
|
||||
else if( key == "VMODE" )
|
||||
{
|
||||
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Disc region type = %.*s",
|
||||
static_cast<int>(value.size()), value.data());
|
||||
}
|
||||
else if( key == "VER" )
|
||||
{
|
||||
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Software version = %.*s",
|
||||
static_cast<int>(value.size()), value.data());
|
||||
*version = value;
|
||||
}
|
||||
if (value.empty() && file.getLength() != file.getSeekPos())
|
||||
{ // Some games have a character on the last line of the file, don't print the error in those cases.
|
||||
Console.Warning("(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:");
|
||||
Console.Indent().WriteLn(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if( retype == CDVDDiscType::Other )
|
||||
if (key == "BOOT2")
|
||||
{
|
||||
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
|
||||
return CDVDDiscType::Other;
|
||||
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PS2 Disc = {}", value));
|
||||
*name = value;
|
||||
retype = CDVDDiscType::PS2Disc;
|
||||
}
|
||||
else if (key == "BOOT")
|
||||
{
|
||||
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PSX/PSone Disc = {}", value));
|
||||
*name = value;
|
||||
retype = CDVDDiscType::PS1Disc;
|
||||
}
|
||||
else if (key == "VMODE")
|
||||
{
|
||||
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Disc region type = {}", value));
|
||||
}
|
||||
else if (key == "VER")
|
||||
{
|
||||
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Software version = {}", value));
|
||||
*version = value;
|
||||
}
|
||||
}
|
||||
catch( Exception::FileNotFound& )
|
||||
{
|
||||
//Console.Warning(ex.FormatDiagnosticMessage());
|
||||
return CDVDDiscType::Other; // no SYSTEM.CNF, not a PS1/PS2 disc.
|
||||
}
|
||||
catch (Exception::BadStream& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
return CDVDDiscType::Other; // ISO error
|
||||
}
|
||||
|
||||
if (retype == CDVDDiscType::Other)
|
||||
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
|
||||
|
||||
return retype;
|
||||
}
|
||||
|
@ -586,21 +564,13 @@ void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::st
|
|||
|
||||
if (disc_type == CDVDDiscType::PS2Disc || disc_type == CDVDDiscType::PS1Disc)
|
||||
{
|
||||
try
|
||||
{
|
||||
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
|
||||
std::unique_ptr<ElfObject> elfptr(cdvdLoadElf(elfpath, isPSXElf));
|
||||
elfptr->loadHeaders();
|
||||
crc = elfptr->getCRC();
|
||||
}
|
||||
catch ([[maybe_unused]] Exception::FileNotFound& e)
|
||||
{
|
||||
Console.Error(fmt::format("Failed to load ELF info for {}", elfpath));
|
||||
}
|
||||
catch (Exception::BadStream& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
}
|
||||
Error error;
|
||||
ElfObject elfo;
|
||||
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
|
||||
if (!cdvdLoadElf(&elfo, elfpath, isPSXElf, &error))
|
||||
Console.Error(fmt::format("Failed to load ELF info for {}: {}", elfpath, error.GetDescription()));
|
||||
else
|
||||
crc = elfo.GetCRC();
|
||||
}
|
||||
|
||||
*out_crc = crc;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
class Error;
|
||||
class ElfObject;
|
||||
|
||||
#define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */
|
||||
|
@ -189,7 +190,7 @@ extern void cdvdWrite(u8 key, u8 rt);
|
|||
extern void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
|
||||
CDVDDiscType* out_disc_type);
|
||||
extern u32 cdvdGetElfCRC(const std::string& path);
|
||||
extern std::unique_ptr<ElfObject> cdvdLoadElf(std::string filename, bool isPSXElf);
|
||||
extern bool cdvdLoadElf(ElfObject* elfo, std::string filename, bool isPSXElf, Error* error);
|
||||
|
||||
extern s32 cdvdCtrlTrayOpen();
|
||||
extern s32 cdvdCtrlTrayClose();
|
||||
|
|
|
@ -73,14 +73,11 @@ static void CheckNullCDVD()
|
|||
static int CheckDiskTypeFS(int baseType)
|
||||
{
|
||||
IsoFSCDVD isofs;
|
||||
try
|
||||
IsoDirectory rootdir(isofs);
|
||||
if (rootdir.OpenRootDirectory())
|
||||
{
|
||||
IsoDirectory rootdir(isofs);
|
||||
|
||||
try
|
||||
if (IsoFile file(isofs); file.open(rootdir, "SYSTEM.CNF;1"))
|
||||
{
|
||||
IsoFile file(rootdir, "SYSTEM.CNF;1");
|
||||
|
||||
const int size = file.getLength();
|
||||
const std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size + 1);
|
||||
file.read(buffer.get(), size);
|
||||
|
@ -97,40 +94,16 @@ static int CheckDiskTypeFS(int baseType)
|
|||
|
||||
return (baseType == CDVD_TYPE_DETCTCD) ? CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD;
|
||||
}
|
||||
catch (Exception::FileNotFound&)
|
||||
{
|
||||
}
|
||||
|
||||
// PS2 Linux disc 2, doesn't have a System.CNF or a normal ELF
|
||||
try
|
||||
{
|
||||
IsoFile file(rootdir, "P2L_0100.02;1");
|
||||
if (rootdir.Exists("P2L_0100.02;1"))
|
||||
return CDVD_TYPE_PS2DVD;
|
||||
}
|
||||
catch (Exception::FileNotFound&)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IsoFile file(rootdir, "PSX.EXE;1");
|
||||
if (rootdir.Exists("PSX.EXE;1"))
|
||||
return CDVD_TYPE_PSCD;
|
||||
}
|
||||
catch (Exception::FileNotFound&)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IsoFile file(rootdir, "VIDEO_TS/VIDEO_TS.IFO;1");
|
||||
if (rootdir.Exists("VIDEO_TS/VIDEO_TS.IFO;1"))
|
||||
return CDVD_TYPE_DVDV;
|
||||
}
|
||||
catch (Exception::FileNotFound&)
|
||||
{
|
||||
}
|
||||
}
|
||||
catch (Exception::FileNotFound&)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
|
|
|
@ -16,26 +16,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class Error;
|
||||
|
||||
enum IsoFS_Type
|
||||
{
|
||||
FStype_ISO9660 = 1,
|
||||
FStype_Joliet = 2,
|
||||
};
|
||||
|
||||
class IsoDirectory
|
||||
class IsoDirectory final
|
||||
{
|
||||
public:
|
||||
SectorSource& internalReader;
|
||||
std::vector<IsoFileDescriptor> files;
|
||||
IsoFS_Type m_fstype;
|
||||
IsoFS_Type m_fstype = FStype_ISO9660;
|
||||
|
||||
public:
|
||||
IsoDirectory(SectorSource& r);
|
||||
IsoDirectory(SectorSource& r, const IsoFileDescriptor& directoryEntry);
|
||||
virtual ~IsoDirectory() = default;
|
||||
~IsoDirectory();
|
||||
|
||||
bool OpenRootDirectory(Error* error = nullptr);
|
||||
bool Open(const IsoFileDescriptor& directoryEntry, Error* error = nullptr);
|
||||
|
||||
std::string FStype_ToString() const;
|
||||
SectorSource& GetReader() const { return internalReader; }
|
||||
|
@ -46,12 +51,10 @@ public:
|
|||
|
||||
u32 GetFileSize(const std::string_view& filePath) const;
|
||||
|
||||
IsoFileDescriptor FindFile(const std::string_view& filePath) const;
|
||||
std::optional<IsoFileDescriptor> FindFile(const std::string_view& filePath) const;
|
||||
|
||||
protected:
|
||||
const IsoFileDescriptor& GetEntry(const std::string_view& fileName) const;
|
||||
const IsoFileDescriptor& GetEntry(int index) const;
|
||||
const IsoFileDescriptor& GetEntry(size_t index) const;
|
||||
|
||||
void Init(const IsoFileDescriptor& directoryEntry);
|
||||
int GetIndexOf(const std::string_view& fileName) const;
|
||||
};
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "IsoFile.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/Error.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
@ -51,6 +51,12 @@ std::string IsoDirectory::FStype_ToString() const
|
|||
// Used to load the Root directory from an image
|
||||
IsoDirectory::IsoDirectory(SectorSource& r)
|
||||
: internalReader(r)
|
||||
{
|
||||
}
|
||||
|
||||
IsoDirectory::~IsoDirectory() = default;
|
||||
|
||||
bool IsoDirectory::OpenRootDirectory(Error* error /* = nullptr */)
|
||||
{
|
||||
IsoFileDescriptor rootDirEntry;
|
||||
bool isValid = false;
|
||||
|
@ -107,22 +113,17 @@ IsoDirectory::IsoDirectory(SectorSource& r)
|
|||
}
|
||||
|
||||
if (!isValid)
|
||||
throw Exception::FileNotFound("IsoFileSystem") // FIXME: Should report the name of the ISO here...
|
||||
.SetDiagMsg("IsoFS could not find the root directory on the ISO image.");
|
||||
{
|
||||
Error::SetString(error, "IsoFS could not find the root directory on the ISO image.");
|
||||
return false;
|
||||
}
|
||||
|
||||
DevCon.WriteLn("(IsoFS) Filesystem is %s", FStype_ToString().c_str());
|
||||
Init(rootDirEntry);
|
||||
return Open(rootDirEntry);
|
||||
}
|
||||
|
||||
// Used to load a specific directory from a file descriptor
|
||||
IsoDirectory::IsoDirectory(SectorSource& r, const IsoFileDescriptor& directoryEntry)
|
||||
: internalReader(r)
|
||||
{
|
||||
m_fstype = FStype_ISO9660;
|
||||
Init(directoryEntry);
|
||||
}
|
||||
|
||||
void IsoDirectory::Init(const IsoFileDescriptor& directoryEntry)
|
||||
bool IsoDirectory::Open(const IsoFileDescriptor& directoryEntry, Error* error /* = nullptr */)
|
||||
{
|
||||
// parse directory sector
|
||||
IsoFile dataStream(internalReader, directoryEntry);
|
||||
|
@ -163,9 +164,10 @@ void IsoDirectory::Init(const IsoFileDescriptor& directoryEntry)
|
|||
}
|
||||
|
||||
b[0] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const IsoFileDescriptor& IsoDirectory::GetEntry(int index) const
|
||||
const IsoFileDescriptor& IsoDirectory::GetEntry(size_t index) const
|
||||
{
|
||||
return files[index];
|
||||
}
|
||||
|
@ -178,25 +180,19 @@ int IsoDirectory::GetIndexOf(const std::string_view& fileName) const
|
|||
return i;
|
||||
}
|
||||
|
||||
throw Exception::FileNotFound(std::string(fileName));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const IsoFileDescriptor& IsoDirectory::GetEntry(const std::string_view& fileName) const
|
||||
{
|
||||
return GetEntry(GetIndexOf(fileName));
|
||||
}
|
||||
|
||||
IsoFileDescriptor IsoDirectory::FindFile(const std::string_view& filePath) const
|
||||
std::optional<IsoFileDescriptor> IsoDirectory::FindFile(const std::string_view& filePath) const
|
||||
{
|
||||
if (filePath.empty())
|
||||
throw Exception::FileNotFound();
|
||||
return std::nullopt;
|
||||
|
||||
// DOS-style parser should work fine for ISO 9660 path names. Only practical difference
|
||||
// is case sensitivity, and that won't matter for path splitting.
|
||||
std::vector<std::string_view> parts(Path::SplitWindowsPath(filePath));
|
||||
IsoFileDescriptor info;
|
||||
const IsoDirectory* dir = this;
|
||||
std::unique_ptr<IsoDirectory> deleteme;
|
||||
IsoDirectory subdir(internalReader);
|
||||
|
||||
// walk through path ("." and ".." entries are in the directories themselves, so even if the
|
||||
// path included . and/or .., it still works)
|
||||
|
@ -206,35 +202,67 @@ IsoFileDescriptor IsoDirectory::FindFile(const std::string_view& filePath) const
|
|||
|
||||
for (size_t index = has_device ? 1 : 0; index < (parts.size() - 1); index++)
|
||||
{
|
||||
info = dir->GetEntry(parts[index]);
|
||||
if (info.IsFile())
|
||||
throw Exception::FileNotFound(std::string(filePath));
|
||||
const int subdir_index = GetIndexOf(parts[index]);
|
||||
if (subdir_index < 0)
|
||||
return std::nullopt;
|
||||
|
||||
deleteme.reset(new IsoDirectory(internalReader, info));
|
||||
dir = deleteme.get();
|
||||
const IsoFileDescriptor& subdir_entry = GetEntry(static_cast<size_t>(index));
|
||||
if (subdir_entry.IsFile() || !subdir.Open(subdir_entry, nullptr))
|
||||
return std::nullopt;
|
||||
|
||||
dir = &subdir;
|
||||
}
|
||||
|
||||
info = dir->GetEntry(parts.back());
|
||||
return info;
|
||||
const int file_index = dir->GetIndexOf(parts.back());
|
||||
if (file_index < 0)
|
||||
return std::nullopt;
|
||||
|
||||
return GetEntry(static_cast<size_t>(file_index));
|
||||
}
|
||||
|
||||
bool IsoDirectory::Exists(const std::string_view& filePath) const
|
||||
{
|
||||
if (filePath.empty())
|
||||
return false;
|
||||
|
||||
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
|
||||
return fd.has_value();
|
||||
}
|
||||
|
||||
bool IsoDirectory::IsFile(const std::string_view& filePath) const
|
||||
{
|
||||
if (filePath.empty())
|
||||
return false;
|
||||
return (FindFile(filePath).flags & 2) != 2;
|
||||
|
||||
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
|
||||
if (fd.has_value())
|
||||
return false;
|
||||
|
||||
return ((fd->flags & 2) != 2);
|
||||
}
|
||||
|
||||
bool IsoDirectory::IsDir(const std::string_view& filePath) const
|
||||
{
|
||||
if (filePath.empty())
|
||||
return false;
|
||||
return (FindFile(filePath).flags & 2) == 2;
|
||||
|
||||
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
|
||||
if (fd.has_value())
|
||||
return false;
|
||||
|
||||
return ((fd->flags & 2) == 2);
|
||||
}
|
||||
|
||||
u32 IsoDirectory::GetFileSize(const std::string_view& filePath) const
|
||||
{
|
||||
return FindFile(filePath).size;
|
||||
if (filePath.empty())
|
||||
return 0;
|
||||
|
||||
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
|
||||
if (fd.has_value())
|
||||
return 0;
|
||||
|
||||
return fd->size;
|
||||
}
|
||||
|
||||
IsoFileDescriptor::IsoFileDescriptor()
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
class IsoFile;
|
||||
class IsoDirectory;
|
||||
struct ISoFileDescriptor;
|
||||
struct IsoFileDescriptor;
|
||||
|
||||
#include "SectorSource.h"
|
||||
#include "IsoFileDescriptor.h"
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "SectorSource.h"
|
||||
|
||||
class IsoFSCDVD : public SectorSource
|
||||
class IsoFSCDVD final : public SectorSource
|
||||
{
|
||||
public:
|
||||
IsoFSCDVD();
|
||||
|
|
|
@ -16,26 +16,19 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/Error.h"
|
||||
|
||||
#include "IsoFS.h"
|
||||
#include "IsoFile.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
IsoFile::IsoFile(SectorSource& reader, const std::string_view& filename)
|
||||
IsoFile::IsoFile(SectorSource& reader)
|
||||
: internalReader(reader)
|
||||
, fileEntry(IsoDirectory(reader).FindFile(filename))
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
IsoFile::IsoFile(const IsoDirectory& dir, const std::string_view& filename)
|
||||
: internalReader(dir.GetReader())
|
||||
, fileEntry(dir.FindFile(filename))
|
||||
{
|
||||
Init();
|
||||
}
|
||||
IsoFile::~IsoFile() = default;
|
||||
|
||||
IsoFile::IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry)
|
||||
: internalReader(reader)
|
||||
|
@ -51,12 +44,35 @@ void IsoFile::Init()
|
|||
currentSectorNumber = fileEntry.lba;
|
||||
currentOffset = 0;
|
||||
sectorOffset = 0;
|
||||
maxOffset = std::max<u32>(0, fileEntry.size);
|
||||
maxOffset = fileEntry.size;
|
||||
|
||||
if (maxOffset > 0)
|
||||
internalReader.readSector(currentSector, currentSectorNumber);
|
||||
}
|
||||
|
||||
bool IsoFile::open(const IsoDirectory& dir, const std::string_view& filename, Error* error /*= nullptr*/)
|
||||
{
|
||||
const std::optional<IsoFileDescriptor> fd(dir.FindFile(filename));
|
||||
if (!fd.has_value())
|
||||
{
|
||||
Error::SetString(error, fmt::format("Failed to find file '{}'", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
fileEntry = std::move(fd.value());
|
||||
Init();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsoFile::open(const std::string_view& filename, Error* error /*= nullptr*/)
|
||||
{
|
||||
IsoDirectory dir(internalReader);
|
||||
if (!dir.OpenRootDirectory(error))
|
||||
return false;
|
||||
|
||||
return open(dir, filename, error);
|
||||
}
|
||||
|
||||
u32 IsoFile::seek(u32 absoffset)
|
||||
{
|
||||
u32 endOffset = absoffset;
|
||||
|
@ -142,7 +158,7 @@ void IsoFile::makeDataAvailable()
|
|||
u8 IsoFile::readByte()
|
||||
{
|
||||
if (currentOffset >= maxOffset)
|
||||
throw Exception::EndOfStream();
|
||||
return 0;
|
||||
|
||||
makeDataAvailable();
|
||||
|
||||
|
|
|
@ -21,27 +21,31 @@
|
|||
#include "common/Pcsx2Defs.h"
|
||||
#include <string_view>
|
||||
|
||||
class IsoFile
|
||||
class Error;
|
||||
|
||||
class IsoFile final
|
||||
{
|
||||
public:
|
||||
static const int sectorLength = 2048;
|
||||
|
||||
protected:
|
||||
SectorSource& internalReader;
|
||||
IsoFileDescriptor fileEntry;
|
||||
IsoFileDescriptor fileEntry = {};
|
||||
|
||||
u32 currentOffset;
|
||||
u32 maxOffset;
|
||||
u32 currentOffset = 0;
|
||||
u32 maxOffset = 0;
|
||||
|
||||
int currentSectorNumber;
|
||||
int currentSectorNumber = 0;
|
||||
int sectorOffset = 0;
|
||||
u8 currentSector[sectorLength];
|
||||
int sectorOffset;
|
||||
|
||||
public:
|
||||
IsoFile(const IsoDirectory& dir, const std::string_view& filename);
|
||||
IsoFile(SectorSource& reader, const std::string_view& filename);
|
||||
IsoFile(SectorSource& reader);
|
||||
IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry);
|
||||
virtual ~IsoFile() = default;
|
||||
~IsoFile();
|
||||
|
||||
bool open(const IsoDirectory& dir, const std::string_view& filename, Error* error = nullptr);
|
||||
bool open(const std::string_view& filename, Error* error = nullptr);
|
||||
|
||||
u32 seek(u32 absoffset);
|
||||
u32 seek(s64 offset, int mode);
|
||||
|
|
|
@ -43,50 +43,79 @@ struct PSXEXEHeader
|
|||
static_assert(sizeof(PSXEXEHeader) == 0x800);
|
||||
#pragma pack(pop)
|
||||
|
||||
// All of ElfObjects functions.
|
||||
ElfObject::ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf_)
|
||||
: data(isofile.getLength(), "ELF headers")
|
||||
, header(*(ELF_HEADER*)data.GetPtr())
|
||||
, filename(std::move(srcfile))
|
||||
, isPSXElf(isPSXElf_)
|
||||
ElfObject::ElfObject() = default;
|
||||
|
||||
ElfObject::~ElfObject() = default;
|
||||
|
||||
bool ElfObject::OpenIsoFile(std::string srcfile, IsoFile& isofile, bool isPSXElf_, Error* error)
|
||||
{
|
||||
checkElfSize(data.GetSizeInBytes());
|
||||
readIso(isofile);
|
||||
initElfHeaders();
|
||||
const u32 length = isofile.getLength();
|
||||
if (!CheckElfSize(length, error))
|
||||
return false;
|
||||
|
||||
data.resize(length);
|
||||
|
||||
const s32 rsize = isofile.read(data.data(), static_cast<s32>(length));
|
||||
if (rsize < static_cast<s32>(length))
|
||||
{
|
||||
Error::SetString(error, "Failed to read ELF from ISO");
|
||||
return false;
|
||||
}
|
||||
|
||||
filename = std::move(srcfile);
|
||||
isPSXElf = isPSXElf_;
|
||||
InitElfHeaders();
|
||||
return true;
|
||||
}
|
||||
|
||||
ElfObject::ElfObject(std::string srcfile, u32 hdrsize, bool isPSXElf_)
|
||||
: data(hdrsize, "ELF headers")
|
||||
, header(*(ELF_HEADER*)data.GetPtr())
|
||||
, filename(std::move(srcfile))
|
||||
, isPSXElf(isPSXElf_)
|
||||
bool ElfObject::OpenFile(std::string srcfile, bool isPSXElf_, Error* error)
|
||||
{
|
||||
checkElfSize(data.GetSizeInBytes());
|
||||
readFile();
|
||||
initElfHeaders();
|
||||
auto fp = FileSystem::OpenManagedCFile(srcfile.c_str(), "rb", error);
|
||||
FILESYSTEM_STAT_DATA sd;
|
||||
if (!fp || !FileSystem::StatFile(fp.get(), &sd))
|
||||
{
|
||||
Error::SetString(error, fmt::format("Failed to read ELF from '{}'", srcfile));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isPSXElf_ && !CheckElfSize(sd.Size, error))
|
||||
return false;
|
||||
|
||||
data.resize(static_cast<size_t>(sd.Size));
|
||||
if (std::fread(data.data(), data.size(), 1, fp.get()) != 1)
|
||||
{
|
||||
Error::SetString(error, fmt::format("Failed to read ELF from '{}'", srcfile));
|
||||
return false;
|
||||
}
|
||||
|
||||
filename = std::move(srcfile);
|
||||
isPSXElf = isPSXElf_;
|
||||
InitElfHeaders();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ElfObject::initElfHeaders()
|
||||
void ElfObject::InitElfHeaders()
|
||||
{
|
||||
if (isPSXElf)
|
||||
return;
|
||||
|
||||
DevCon.WriteLn("Initializing Elf: %d bytes", data.GetSizeInBytes());
|
||||
DevCon.WriteLn("Initializing Elf: %zu bytes", data.size());
|
||||
|
||||
const ELF_HEADER& header = GetHeader();
|
||||
if (header.e_phnum > 0)
|
||||
{
|
||||
if ((header.e_phoff + sizeof(ELF_PHR)) <= static_cast<u32>(data.GetSizeInBytes()))
|
||||
if ((header.e_phoff + sizeof(ELF_PHR)) <= data.size())
|
||||
proghead = reinterpret_cast<ELF_PHR*>(&data[header.e_phoff]);
|
||||
else
|
||||
Console.Error("(ELF) Program header offset %u is larger than file size %u", header.e_phoff, data.GetSizeInBytes());
|
||||
Console.Error("(ELF) Program header offset %u is larger than file size %zu", header.e_phoff, data.size());
|
||||
}
|
||||
|
||||
if (header.e_shnum > 0)
|
||||
{
|
||||
if ((header.e_shoff + sizeof(ELF_SHR)) <= static_cast<u32>(data.GetSizeInBytes()))
|
||||
if ((header.e_shoff + sizeof(ELF_SHR)) <= data.size())
|
||||
secthead = reinterpret_cast<ELF_SHR*>(&data[header.e_shoff]);
|
||||
else
|
||||
Console.Error("(ELF) Section header offset %u is larger than file size %u", header.e_shoff, data.GetSizeInBytes());
|
||||
Console.Error("(ELF) Section header offset %u is larger than file size %zu", header.e_shoff, data.size());
|
||||
}
|
||||
|
||||
if ((header.e_shnum > 0) && (header.e_shentsize != sizeof(ELF_SHR)))
|
||||
|
@ -147,49 +176,61 @@ void ElfObject::initElfHeaders()
|
|||
//applyPatches();
|
||||
}
|
||||
|
||||
bool ElfObject::hasValidPSXHeader()
|
||||
bool ElfObject::HasValidPSXHeader() const
|
||||
{
|
||||
if (data.GetSizeInBytes() < static_cast<s64>(sizeof(PSXEXEHeader)))
|
||||
if (data.size() < sizeof(PSXEXEHeader))
|
||||
return false;
|
||||
|
||||
const PSXEXEHeader* header = reinterpret_cast<const PSXEXEHeader*>(data.GetPtr());
|
||||
const PSXEXEHeader* header = reinterpret_cast<const PSXEXEHeader*>(data.data());
|
||||
|
||||
static constexpr char expected_id[] = {'P', 'S', '-', 'X', ' ', 'E', 'X', 'E'};
|
||||
if (std::memcmp(header->id, expected_id, sizeof(expected_id)) != 0)
|
||||
return false;
|
||||
|
||||
if (static_cast<s64>(header->file_size + sizeof(PSXEXEHeader)) > data.GetSizeInBytes())
|
||||
if ((header->file_size + sizeof(PSXEXEHeader)) > data.size())
|
||||
{
|
||||
Console.Warning("Incorrect file size in PS-EXE header: %u bytes should not be greater than %u bytes",
|
||||
header->file_size, static_cast<unsigned>(data.GetSizeInBytes() - sizeof(PSXEXEHeader)));
|
||||
header->file_size, static_cast<unsigned>(data.size() - sizeof(PSXEXEHeader)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElfObject::hasProgramHeaders() { return (proghead != NULL); }
|
||||
bool ElfObject::hasSectionHeaders() { return (secthead != NULL); }
|
||||
bool ElfObject::hasHeaders() { return (hasProgramHeaders() && hasSectionHeaders()); }
|
||||
bool ElfObject::HasProgramHeaders() const
|
||||
{
|
||||
return (proghead != nullptr);
|
||||
}
|
||||
|
||||
u32 ElfObject::getEntryPoint()
|
||||
bool ElfObject::HasSectionHeaders() const
|
||||
{
|
||||
return (secthead != nullptr);
|
||||
}
|
||||
|
||||
bool ElfObject::HasHeaders() const
|
||||
{
|
||||
return (HasProgramHeaders() && HasSectionHeaders());
|
||||
}
|
||||
|
||||
u32 ElfObject::GetEntryPoint() const
|
||||
{
|
||||
if (isPSXElf)
|
||||
{
|
||||
if (hasValidPSXHeader())
|
||||
return reinterpret_cast<const PSXEXEHeader*>(data.GetPtr())->initial_pc;
|
||||
if (HasValidPSXHeader())
|
||||
return reinterpret_cast<const PSXEXEHeader*>(data.data())->initial_pc;
|
||||
else
|
||||
return 0xFFFFFFFFu;
|
||||
}
|
||||
else
|
||||
{
|
||||
return header.e_entry;
|
||||
return GetHeader().e_entry;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<u32,u32> ElfObject::getTextRange()
|
||||
std::pair<u32,u32> ElfObject::GetTextRange() const
|
||||
{
|
||||
if (!isPSXElf && hasProgramHeaders())
|
||||
if (!isPSXElf && HasProgramHeaders())
|
||||
{
|
||||
const ELF_HEADER& header = GetHeader();
|
||||
for (int i = 0; i < header.e_phnum; i++)
|
||||
{
|
||||
const u32 start = proghead[i].p_vaddr;
|
||||
|
@ -203,62 +244,36 @@ std::pair<u32,u32> ElfObject::getTextRange()
|
|||
return std::make_pair(0,0);
|
||||
}
|
||||
|
||||
void ElfObject::readIso(IsoFile& file)
|
||||
bool ElfObject::CheckElfSize(s64 size, Error* error)
|
||||
{
|
||||
int rsize = file.read(data.GetPtr(), data.GetSizeInBytes());
|
||||
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
|
||||
if (size > 0xfffffff)
|
||||
Error::SetString(error, "Illegal ELF file size over 2GB!");
|
||||
else if (size == -1)
|
||||
Error::SetString(error, "ELF file does not exist!");
|
||||
else if (size <= static_cast<s64>(sizeof(ELF_HEADER)))
|
||||
Error::SetString(error, "Unexpected end of ELF file.");
|
||||
else
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ElfObject::readFile()
|
||||
{
|
||||
int rsize = 0;
|
||||
FILE *f = FileSystem::OpenCFile( filename.c_str(), "rb");
|
||||
if (f == NULL) throw Exception::FileNotFound(filename);
|
||||
|
||||
fseek(f, 0, SEEK_SET);
|
||||
rsize = fread(data.GetPtr(), 1, data.GetSizeInBytes(), f);
|
||||
fclose( f );
|
||||
|
||||
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
|
||||
}
|
||||
|
||||
static std::string GetMsg_InvalidELF()
|
||||
{
|
||||
return
|
||||
"Cannot load ELF binary image. The file may be corrupt or incomplete."
|
||||
"\n\n"
|
||||
"If loading from an ISO image, this error may be caused by an unsupported ISO image type or a bug in PCSX2 ISO image support.";
|
||||
}
|
||||
|
||||
|
||||
void ElfObject::checkElfSize(s64 elfsize)
|
||||
{
|
||||
const char* diagMsg = NULL;
|
||||
if (elfsize > 0xfffffff) diagMsg = "Illegal ELF file size over 2GB!";
|
||||
else if (elfsize == -1) diagMsg = "ELF file does not exist!";
|
||||
else if (elfsize == 0) diagMsg = "Unexpected end of ELF file.";
|
||||
|
||||
if (diagMsg)
|
||||
throw Exception::BadStream(filename)
|
||||
.SetDiagMsg(diagMsg)
|
||||
.SetUserMsg(GetMsg_InvalidELF());
|
||||
}
|
||||
|
||||
u32 ElfObject::getCRC()
|
||||
u32 ElfObject::GetCRC() const
|
||||
{
|
||||
u32 CRC = 0;
|
||||
|
||||
const u32* srcdata = (u32*)data.GetPtr();
|
||||
for(u32 i=data.GetSizeInBytes()/4; i; --i, ++srcdata)
|
||||
const u32* srcdata = reinterpret_cast<const u32*>(data.data());
|
||||
for (u32 i = static_cast<u32>(data.size()) / 4; i; --i, ++srcdata)
|
||||
CRC ^= *srcdata;
|
||||
|
||||
return CRC;
|
||||
}
|
||||
|
||||
void ElfObject::loadProgramHeaders()
|
||||
void ElfObject::LoadProgramHeaders()
|
||||
{
|
||||
if (proghead == NULL) return;
|
||||
|
||||
const ELF_HEADER& header = GetHeader();
|
||||
for( int i = 0 ; i < header.e_phnum ; i++ )
|
||||
{
|
||||
ELF_LOG( "Elf32 Program Header" );
|
||||
|
@ -289,11 +304,17 @@ void ElfObject::loadProgramHeaders()
|
|||
}
|
||||
}
|
||||
|
||||
void ElfObject::loadSectionHeaders()
|
||||
void ElfObject::LoadSectionHeaders()
|
||||
{
|
||||
if (secthead == NULL || header.e_shoff > (u32)data.GetLength()) return;
|
||||
const ELF_HEADER& header = GetHeader();
|
||||
if (!secthead || header.e_shoff > data.size())
|
||||
return;
|
||||
|
||||
const u8* sections_names = data.GetPtr( secthead[ (header.e_shstrndx == 0xffff ? 0 : header.e_shstrndx) ].sh_offset );
|
||||
// This function scares me a lot. There's a lot of potential for buffer overreads.
|
||||
// All the accesses should be wrapped in bounds checked read() calls.
|
||||
|
||||
const u32 section_names_offset = secthead[(header.e_shstrndx == 0xffff ? 0 : header.e_shstrndx)].sh_offset;
|
||||
const u8* sections_names = data.data() + section_names_offset;
|
||||
|
||||
int i_st = -1, i_dt = -1;
|
||||
|
||||
|
@ -343,28 +364,33 @@ void ElfObject::loadSectionHeaders()
|
|||
|
||||
if ((i_st >= 0) && (i_dt >= 0))
|
||||
{
|
||||
const char * SymNames;
|
||||
Elf32_Sym * eS;
|
||||
const char* SymNames;
|
||||
Elf32_Sym* eS;
|
||||
|
||||
SymNames = (char*)data.GetPtr(secthead[i_dt].sh_offset);
|
||||
eS = (Elf32_Sym*)data.GetPtr(secthead[i_st].sh_offset);
|
||||
Console.WriteLn("found %d symbols", secthead[i_st].sh_size / sizeof(Elf32_Sym));
|
||||
if (secthead[i_dt].sh_offset < data.size() &&
|
||||
secthead[i_st].sh_offset < data.size())
|
||||
{
|
||||
SymNames = (char*)(data.data() + secthead[i_dt].sh_offset);
|
||||
eS = (Elf32_Sym*)(data.data() + secthead[i_st].sh_offset);
|
||||
Console.WriteLn("found %d symbols", secthead[i_st].sh_size / sizeof(Elf32_Sym));
|
||||
|
||||
R5900SymbolMap.Clear();
|
||||
for(uint i = 1; i < (secthead[i_st].sh_size / sizeof(Elf32_Sym)); i++) {
|
||||
if ((eS[i].st_value != 0) && (ELF32_ST_TYPE(eS[i].st_info) == 2))
|
||||
R5900SymbolMap.Clear();
|
||||
for (uint i = 1; i < (secthead[i_st].sh_size / sizeof(Elf32_Sym)); i++)
|
||||
{
|
||||
R5900SymbolMap.AddLabel(&SymNames[eS[i].st_name],eS[i].st_value);
|
||||
if ((eS[i].st_value != 0) && (ELF32_ST_TYPE(eS[i].st_info) == 2))
|
||||
{
|
||||
R5900SymbolMap.AddLabel(&SymNames[eS[i].st_name], eS[i].st_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ElfObject::loadHeaders()
|
||||
void ElfObject::LoadHeaders()
|
||||
{
|
||||
if (isPSXElf)
|
||||
return;
|
||||
|
||||
loadProgramHeaders();
|
||||
loadSectionHeaders();
|
||||
LoadProgramHeaders();
|
||||
LoadSectionHeaders();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
|
@ -15,10 +15,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/SafeArray.h"
|
||||
#include "common/SafeArray.inl"
|
||||
#include "common/Error.h"
|
||||
#include "CDVD/IsoFS/IsoFSCDVD.h"
|
||||
#include "CDVD/IsoFS/IsoFS.h"
|
||||
#include <vector>
|
||||
|
||||
struct ELF_HEADER {
|
||||
u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier)
|
||||
|
@ -118,39 +118,43 @@ struct Elf32_Rel {
|
|||
u32 r_info;
|
||||
};
|
||||
|
||||
class ElfObject
|
||||
class ElfObject final
|
||||
{
|
||||
private:
|
||||
SafeArray<u8> data;
|
||||
ELF_HEADER& header;
|
||||
ELF_PHR* proghead = nullptr;
|
||||
ELF_SHR* secthead = nullptr;
|
||||
std::string filename;
|
||||
bool isPSXElf;
|
||||
public:
|
||||
ElfObject();
|
||||
ElfObject(const ElfObject&) = delete;
|
||||
~ElfObject();
|
||||
|
||||
void initElfHeaders();
|
||||
bool hasValidPSXHeader();
|
||||
void readIso(IsoFile& file);
|
||||
void readFile();
|
||||
void checkElfSize(s64 elfsize);
|
||||
__fi const ELF_HEADER& GetHeader() const { return *reinterpret_cast<const ELF_HEADER*>(data.data()); }
|
||||
__fi u32 GetSize() const { return static_cast<u32>(data.size()); }
|
||||
|
||||
public:
|
||||
ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf_);
|
||||
ElfObject(std::string srcfile, u32 hdrsize, bool isPSXElf_);
|
||||
bool OpenFile(std::string srcfile, bool isPSXElf_, Error* error);
|
||||
bool OpenIsoFile(std::string srcfile, IsoFile& isofile, bool isPSXElf_, Error* error);
|
||||
|
||||
bool IsPSXElf() const { return isPSXElf; }
|
||||
void LoadHeaders();
|
||||
|
||||
void loadProgramHeaders();
|
||||
void loadSectionHeaders();
|
||||
void loadHeaders();
|
||||
bool HasProgramHeaders() const;
|
||||
bool HasSectionHeaders() const;
|
||||
bool HasHeaders() const;
|
||||
|
||||
bool hasProgramHeaders();
|
||||
bool hasSectionHeaders();
|
||||
bool hasHeaders();
|
||||
std::pair<u32, u32> GetTextRange() const;
|
||||
u32 GetEntryPoint() const;
|
||||
u32 GetCRC() const;
|
||||
|
||||
std::pair<u32,u32> getTextRange();
|
||||
u32 getEntryPoint();
|
||||
u32 getCRC();
|
||||
private:
|
||||
std::vector<u8> data;
|
||||
ELF_PHR* proghead = nullptr;
|
||||
ELF_SHR* secthead = nullptr;
|
||||
std::string filename;
|
||||
bool isPSXElf;
|
||||
|
||||
bool CheckElfSize(s64 size, Error* error);
|
||||
|
||||
void InitElfHeaders();
|
||||
void LoadProgramHeaders();
|
||||
void LoadSectionHeaders();
|
||||
|
||||
bool HasValidPSXHeader() const;
|
||||
};
|
||||
|
||||
//-------------------
|
||||
|
|
|
@ -182,16 +182,8 @@ bool GameList::GetIsoSerialAndCRC(const std::string& path, s32* disc_type, std::
|
|||
|
||||
bool GameList::GetElfListEntry(const std::string& path, GameList::Entry* entry)
|
||||
{
|
||||
const s64 file_size = FileSystem::GetPathFileSize(path.c_str());
|
||||
if (file_size <= 0)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
ElfObject eo(path, static_cast<uint>(file_size), false);
|
||||
entry->crc = eo.getCRC();
|
||||
}
|
||||
catch (...)
|
||||
ElfObject eo;
|
||||
if (!eo.OpenFile(path, false, nullptr))
|
||||
{
|
||||
Console.Error("Failed to parse ELF '%s'", path.c_str());
|
||||
return false;
|
||||
|
@ -201,9 +193,10 @@ bool GameList::GetElfListEntry(const std::string& path, GameList::Entry* entry)
|
|||
entry->serial.clear();
|
||||
entry->title = Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path));
|
||||
entry->region = Region::Other;
|
||||
entry->total_size = static_cast<u64>(file_size);
|
||||
entry->type = EntryType::ELF;
|
||||
entry->compatibility_rating = CompatibilityRating::Unknown;
|
||||
entry->crc = eo.GetCRC();
|
||||
entry->total_size = eo.GetSize();
|
||||
|
||||
std::string disc_path(VMManager::GetDiscOverrideFromGameSettings(path));
|
||||
if (!disc_path.empty())
|
||||
|
|
|
@ -589,7 +589,12 @@ std::string VMManager::GetGameSettingsPath(const std::string_view& game_serial,
|
|||
std::string VMManager::GetDiscOverrideFromGameSettings(const std::string& elf_path)
|
||||
{
|
||||
std::string iso_path;
|
||||
if (const u32 crc = cdvdGetElfCRC(elf_path); crc != 0)
|
||||
ElfObject elfo;
|
||||
if (!elfo.OpenFile(elf_path, false, nullptr))
|
||||
return iso_path;
|
||||
|
||||
const u32 crc = elfo.GetCRC();
|
||||
if (crc != 0)
|
||||
{
|
||||
INISettingsInterface si(GetGameSettingsPath(std::string_view(), crc));
|
||||
if (si.Load())
|
||||
|
@ -941,29 +946,23 @@ void VMManager::HandleELFChange(bool verbose_patches_if_changed)
|
|||
|
||||
void VMManager::UpdateELFInfo(std::string elf_path)
|
||||
{
|
||||
try
|
||||
Error error;
|
||||
ElfObject elfo;
|
||||
if (!cdvdLoadElf(&elfo, elf_path, false, &error))
|
||||
{
|
||||
std::unique_ptr<ElfObject> elfptr = cdvdLoadElf(elf_path, false);
|
||||
elfptr->loadHeaders();
|
||||
s_current_crc = elfptr->getCRC();
|
||||
s_elf_entry_point = elfptr->getEntryPoint();
|
||||
s_elf_text_range = elfptr->getTextRange();
|
||||
s_elf_path = std::move(elf_path);
|
||||
Console.Error(fmt::format("Failed to read ELF being loaded: {}: {}", elf_path, error.GetDescription()));
|
||||
s_elf_path = {};
|
||||
s_elf_text_range = {};
|
||||
s_elf_entry_point = 0xFFFFFFFFu;
|
||||
s_current_crc = 0;
|
||||
return;
|
||||
}
|
||||
catch ([[maybe_unused]] Exception::FileNotFound& e)
|
||||
{
|
||||
}
|
||||
catch (Exception::BadStream& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
}
|
||||
|
||||
Console.Error(fmt::format("Failed to read ELF being loaded: {}", elf_path));
|
||||
s_elf_path = {};
|
||||
s_elf_text_range = {};
|
||||
s_elf_entry_point = 0xFFFFFFFFu;
|
||||
s_current_crc = 0;
|
||||
elfo.LoadHeaders();
|
||||
s_current_crc = elfo.GetCRC();
|
||||
s_elf_entry_point = elfo.GetEntryPoint();
|
||||
s_elf_text_range = elfo.GetTextRange();
|
||||
s_elf_path = std::move(elf_path);
|
||||
}
|
||||
|
||||
void VMManager::ClearELFInfo()
|
||||
|
|
Loading…
Reference in New Issue