mirror of https://github.com/PCSX2/pcsx2.git
CDVD: Rewrite ISO parser
This commit is contained in:
parent
51aeaeb508
commit
db1e1bcc1f
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Pcsx2Types.h"
|
#include "Pcsx2Types.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
@ -340,4 +341,15 @@ namespace StringUtil
|
||||||
/// Converts unsigned 128-bit data to string.
|
/// Converts unsigned 128-bit data to string.
|
||||||
std::string U128ToString(const u128& u);
|
std::string U128ToString(const u128& u);
|
||||||
std::string& AppendU128ToString(const u128& u, std::string& s);
|
std::string& AppendU128ToString(const u128& u, std::string& s);
|
||||||
|
|
||||||
|
template <typename ContainerType>
|
||||||
|
static inline bool ContainsSubString(const ContainerType& haystack, const std::string_view& needle)
|
||||||
|
{
|
||||||
|
using ValueType = typename ContainerType::value_type;
|
||||||
|
if (needle.empty())
|
||||||
|
return std::empty(haystack);
|
||||||
|
|
||||||
|
return std::search(std::begin(haystack), std::end(haystack), reinterpret_cast<const ValueType*>(needle.data()),
|
||||||
|
reinterpret_cast<const ValueType*>(needle.data() + needle.length())) != std::end(haystack);
|
||||||
|
}
|
||||||
} // namespace StringUtil
|
} // namespace StringUtil
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
#include "Achievements.h"
|
#include "Achievements.h"
|
||||||
#include "CDVD/CDVD.h"
|
#include "CDVD/CDVD.h"
|
||||||
#include "CDVD/IsoFS/IsoFS.h"
|
|
||||||
#include "CDVD/IsoFS/IsoFSCDVD.h"
|
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
#include "Host.h"
|
#include "Host.h"
|
||||||
#include "ImGui/FullscreenUI.h"
|
#include "ImGui/FullscreenUI.h"
|
||||||
|
@ -37,6 +35,7 @@
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
#include "common/Console.h"
|
#include "common/Console.h"
|
||||||
#include "common/FileSystem.h"
|
#include "common/FileSystem.h"
|
||||||
|
#include "common/Error.h"
|
||||||
#include "common/General.h"
|
#include "common/General.h"
|
||||||
#include "common/HTTPDownloader.h"
|
#include "common/HTTPDownloader.h"
|
||||||
#include "common/MD5Digest.h"
|
#include "common/MD5Digest.h"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
* Copyright (C) 2002-2021 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
|
* 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-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
@ -14,6 +14,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
|
#include "CDVD/CDVD.h"
|
||||||
|
#include "CDVD/Ps1CD.h"
|
||||||
|
#include "CDVD/CDVD_internal.h"
|
||||||
|
#include "CDVD/IsoReader.h"
|
||||||
|
#include "CDVD/IsoFileFormats.h"
|
||||||
|
#include "GS.h"
|
||||||
|
#include "Elfheader.h"
|
||||||
|
#include "ps2/BiosTools.h"
|
||||||
|
#include "Recording/InputRecording.h"
|
||||||
|
#include "Host.h"
|
||||||
#include "R3000A.h"
|
#include "R3000A.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "IopHw.h"
|
#include "IopHw.h"
|
||||||
|
@ -21,25 +32,15 @@
|
||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
#include "Sio.h"
|
#include "Sio.h"
|
||||||
|
|
||||||
#include <cctype>
|
#include "common/Error.h"
|
||||||
#include <ctime>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "common/FileSystem.h"
|
#include "common/FileSystem.h"
|
||||||
#include "common/Path.h"
|
#include "common/Path.h"
|
||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
#include "common/Threading.h"
|
#include "common/Threading.h"
|
||||||
|
|
||||||
#include "Ps1CD.h"
|
#include <cctype>
|
||||||
#include "CDVD.h"
|
#include <ctime>
|
||||||
#include "CDVD_internal.h"
|
#include <memory>
|
||||||
#include "IsoFileFormats.h"
|
|
||||||
|
|
||||||
#include "GS.h" // for gsVideoMode
|
|
||||||
#include "Elfheader.h"
|
|
||||||
#include "ps2/BiosTools.h"
|
|
||||||
#include "Recording/InputRecording.h"
|
|
||||||
#include "Host.h"
|
|
||||||
|
|
||||||
cdvdStruct cdvd;
|
cdvdStruct cdvd;
|
||||||
|
|
||||||
|
@ -383,6 +384,44 @@ s32 cdvdWriteConfig(const u8* config)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cdvdUncheckedLoadDiscElf(ElfObject* elfo, IsoReader& isor, const std::string_view& elfpath, bool isPSXElf, Error* error)
|
||||||
|
{
|
||||||
|
// Strip out cdrom: prefix, and any leading slashes.
|
||||||
|
size_t start_pos = (elfpath[5] == '0') ? 7 : 6;
|
||||||
|
while (start_pos < elfpath.size() && (elfpath[start_pos] == '\\' || elfpath[start_pos] == '/'))
|
||||||
|
start_pos++;
|
||||||
|
|
||||||
|
// Strip out any version information. Some games use ;2 (MLB2k6), others put multiple versions in
|
||||||
|
// (Syphon Filter Omega Strain). The PS2 BIOS appears to ignore the suffix entirely, so we'll do
|
||||||
|
// the same, and hope that no games actually have multiple ELFs with different versions.
|
||||||
|
// Previous notes:
|
||||||
|
// 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).
|
||||||
|
//
|
||||||
|
size_t length = elfpath.length() - start_pos;
|
||||||
|
const size_t semi_pos = elfpath.find(';', start_pos);
|
||||||
|
if (semi_pos != std::string::npos)
|
||||||
|
length = semi_pos - start_pos;
|
||||||
|
|
||||||
|
std::string iso_filename(elfpath.substr(start_pos, length));
|
||||||
|
DevCon.WriteLn(fmt::format("cvdLoadElf(): '{}' -> '{}' in ISO.", elfpath, iso_filename));
|
||||||
|
if (iso_filename.empty())
|
||||||
|
{
|
||||||
|
Error::SetString(error, "ISO filename is empty.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elfo->OpenIsoFile(std::move(iso_filename), isor, isPSXElf, error);
|
||||||
|
}
|
||||||
|
|
||||||
bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf, Error* error)
|
bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf, Error* error)
|
||||||
{
|
{
|
||||||
if (StringUtil::StartsWith(elfpath, "host:"))
|
if (StringUtil::StartsWith(elfpath, "host:"))
|
||||||
|
@ -392,52 +431,25 @@ bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf
|
||||||
}
|
}
|
||||||
else if (StringUtil::StartsWith(elfpath, "cdrom:") || StringUtil::StartsWith(elfpath, "cdrom0:"))
|
else if (StringUtil::StartsWith(elfpath, "cdrom:") || StringUtil::StartsWith(elfpath, "cdrom0:"))
|
||||||
{
|
{
|
||||||
// Strip out cdrom: prefix, and any leading slashes.
|
IsoReader isor;
|
||||||
size_t start_pos = (elfpath[5] == '0') ? 7 : 6;
|
if (!isor.Open(error))
|
||||||
while (start_pos < elfpath.size() && (elfpath[start_pos] == '\\' || elfpath[start_pos] == '/'))
|
|
||||||
start_pos++;
|
|
||||||
|
|
||||||
// Strip out any version information. Some games use ;2 (MLB2k6), others put multiple versions in
|
|
||||||
// (Syphon Filter Omega Strain). The PS2 BIOS appears to ignore the suffix entirely, so we'll do
|
|
||||||
// the same, and hope that no games actually have multiple ELFs with different versions.
|
|
||||||
// Previous notes:
|
|
||||||
// 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).
|
|
||||||
//
|
|
||||||
size_t length = elfpath.length() - start_pos;
|
|
||||||
const size_t semi_pos = elfpath.find(';', start_pos);
|
|
||||||
if (semi_pos != std::string::npos)
|
|
||||||
length = semi_pos - start_pos;
|
|
||||||
|
|
||||||
std::string iso_filename(elfpath.substr(start_pos, length));
|
|
||||||
DevCon.WriteLn(fmt::format("cvdLoadElf(): '{}' -> '{}' in ISO.", elfpath, iso_filename));
|
|
||||||
if (iso_filename.empty())
|
|
||||||
{
|
|
||||||
Error::SetString(error, "ISO filename is empty.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsoFSCDVD isofs;
|
|
||||||
IsoFile file(isofs);
|
|
||||||
if (!file.open(iso_filename, error))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return elfo->OpenIsoFile(std::move(iso_filename), file, isPSXElf, error);
|
return cdvdLoadDiscElf(elfo, isor, elfpath, isPSXElf, error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.Error(fmt::format("cdvdLoadElf(): Unknown device in ELF path '{}'", elfpath));
|
Console.Error(fmt::format("cdvdLoadElf(): Unknown device in ELF path '{}'", elfpath));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
bool cdvdLoadDiscElf(ElfObject* elfo, IsoReader& isor, const std::string_view& elfpath, bool isPSXElf, Error* error)
|
||||||
|
{
|
||||||
|
if (!StringUtil::StartsWith(elfpath, "cdrom:") && !StringUtil::StartsWith(elfpath, "cdrom0:"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return cdvdUncheckedLoadDiscElf(elfo, isor, elfpath, isPSXElf, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 cdvdGetElfCRC(const std::string& path)
|
u32 cdvdGetElfCRC(const std::string& path)
|
||||||
|
@ -449,65 +461,57 @@ u32 cdvdGetElfCRC(const std::string& path)
|
||||||
return elfo.GetCRC();
|
return elfo.GetCRC();
|
||||||
}
|
}
|
||||||
|
|
||||||
static CDVDDiscType GetPS2ElfName(std::string* name, std::string* version)
|
static CDVDDiscType GetPS2ElfName(IsoReader& isor, std::string* name, std::string* version, Error* error)
|
||||||
{
|
{
|
||||||
CDVDDiscType retype = CDVDDiscType::Other;
|
CDVDDiscType retype = CDVDDiscType::Other;
|
||||||
name->clear();
|
name->clear();
|
||||||
version->clear();
|
version->clear();
|
||||||
|
|
||||||
Error error;
|
std::vector<u8> data;
|
||||||
IsoFSCDVD isofs;
|
if (!isor.ReadFile("SYSTEM.CNF", &data, error))
|
||||||
IsoFile file(isofs);
|
|
||||||
if (!file.open("SYSTEM.CNF", &error))
|
|
||||||
{
|
|
||||||
Console.Error(fmt::format("(GetElfName) Failed to open SYSTEM.CNF: {}", error.GetDescription()));
|
|
||||||
return CDVDDiscType::Other;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int size = file.getLength();
|
|
||||||
if (size == 0)
|
|
||||||
return CDVDDiscType::Other;
|
return CDVDDiscType::Other;
|
||||||
|
|
||||||
while (!file.eof())
|
const std::vector<std::string_view> lines =
|
||||||
|
StringUtil::SplitString(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()), '\n');
|
||||||
|
for (size_t lineno = 0; lineno < lines.size(); lineno++)
|
||||||
{
|
{
|
||||||
const std::string line(file.readLine());
|
const std::string_view line = StringUtil::StripWhitespace(lines[lineno]);
|
||||||
std::string_view key, value;
|
std::string_view key, value;
|
||||||
if (!StringUtil::ParseAssignmentString(line, &key, &value))
|
if (!StringUtil::ParseAssignmentString(line, &key, &value))
|
||||||
continue;
|
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.
|
||||||
{ // Some games have a character on the last line of the file, don't print the error in those cases.
|
if (value.empty() && (lineno == (lines.size() - 1)))
|
||||||
|
{
|
||||||
Console.Warning("(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:");
|
Console.Warning("(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:");
|
||||||
Console.Indent().WriteLn(line);
|
Console.Indent().WriteLn(std::string(line));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == "BOOT2")
|
if (key == "BOOT2")
|
||||||
{
|
{
|
||||||
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PS2 Disc = {}", value));
|
DevCon.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PS2 Disc = {}", value));
|
||||||
*name = value;
|
*name = value;
|
||||||
retype = CDVDDiscType::PS2Disc;
|
retype = CDVDDiscType::PS2Disc;
|
||||||
}
|
}
|
||||||
else if (key == "BOOT")
|
else if (key == "BOOT")
|
||||||
{
|
{
|
||||||
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PSX/PSone Disc = {}", value));
|
DevCon.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PSX/PSone Disc = {}", value));
|
||||||
*name = value;
|
*name = value;
|
||||||
retype = CDVDDiscType::PS1Disc;
|
retype = CDVDDiscType::PS1Disc;
|
||||||
}
|
}
|
||||||
else if (key == "VMODE")
|
else if (key == "VMODE")
|
||||||
{
|
{
|
||||||
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Disc region type = {}", value));
|
DevCon.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Disc region type = {}", value));
|
||||||
}
|
}
|
||||||
else if (key == "VER")
|
else if (key == "VER")
|
||||||
{
|
{
|
||||||
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Software version = {}", value));
|
DevCon.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Software version = {}", value));
|
||||||
*version = value;
|
*version = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retype == CDVDDiscType::Other)
|
Error::SetString(error, "Disc image is *not* a PlayStation or PS2 game");
|
||||||
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
|
|
||||||
|
|
||||||
return retype;
|
return retype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,8 +570,13 @@ static std::string ExecutablePathToSerial(const std::string& path)
|
||||||
void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
|
void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
|
||||||
CDVDDiscType* out_disc_type)
|
CDVDDiscType* out_disc_type)
|
||||||
{
|
{
|
||||||
|
Error error;
|
||||||
|
IsoReader isor;
|
||||||
|
|
||||||
std::string elfpath, version;
|
std::string elfpath, version;
|
||||||
const CDVDDiscType disc_type = GetPS2ElfName(&elfpath, &version);
|
CDVDDiscType disc_type = CDVDDiscType::Other;
|
||||||
|
if (!isor.Open(&error) || (disc_type = GetPS2ElfName(isor, &elfpath, &version, &error)) == CDVDDiscType::Other)
|
||||||
|
Console.Error(fmt::format("Failed to get ELF name: {}", error.GetDescription()));
|
||||||
|
|
||||||
// Don't bother parsing it if we don't need the CRC.
|
// Don't bother parsing it if we don't need the CRC.
|
||||||
if (out_crc)
|
if (out_crc)
|
||||||
|
@ -576,10 +585,9 @@ void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::st
|
||||||
|
|
||||||
if (disc_type == CDVDDiscType::PS2Disc || disc_type == CDVDDiscType::PS1Disc)
|
if (disc_type == CDVDDiscType::PS2Disc || disc_type == CDVDDiscType::PS1Disc)
|
||||||
{
|
{
|
||||||
Error error;
|
|
||||||
ElfObject elfo;
|
ElfObject elfo;
|
||||||
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
|
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
|
||||||
if (!cdvdLoadElf(&elfo, elfpath, isPSXElf, &error))
|
if (!cdvdLoadDiscElf(&elfo, isor, elfpath, isPSXElf, &error))
|
||||||
Console.Error(fmt::format("Failed to load ELF info for {}: {}", elfpath, error.GetDescription()));
|
Console.Error(fmt::format("Failed to load ELF info for {}: {}", elfpath, error.GetDescription()));
|
||||||
else
|
else
|
||||||
crc = elfo.GetCRC();
|
crc = elfo.GetCRC();
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
class Error;
|
class Error;
|
||||||
class ElfObject;
|
class ElfObject;
|
||||||
|
class IsoReader;
|
||||||
|
|
||||||
#define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */
|
#define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */
|
||||||
#define itob(i) ((i) / 10 * 16 + (i) % 10) /* u_char to BCD */
|
#define itob(i) ((i) / 10 * 16 + (i) % 10) /* u_char to BCD */
|
||||||
|
@ -190,7 +191,8 @@ 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,
|
extern void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
|
||||||
CDVDDiscType* out_disc_type);
|
CDVDDiscType* out_disc_type);
|
||||||
extern u32 cdvdGetElfCRC(const std::string& path);
|
extern u32 cdvdGetElfCRC(const std::string& path);
|
||||||
extern bool cdvdLoadElf(ElfObject* elfo, const std::string_view& filename, bool isPSXElf, Error* error);
|
extern bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf, Error* error);
|
||||||
|
extern bool cdvdLoadDiscElf(ElfObject* elfo, IsoReader& isor, const std::string_view& elfpath, bool isPSXElf, Error* error);
|
||||||
|
|
||||||
extern s32 cdvdCtrlTrayOpen();
|
extern s32 cdvdCtrlTrayOpen();
|
||||||
extern s32 cdvdCtrlTrayClose();
|
extern s32 cdvdCtrlTrayClose();
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Interrupts - values are flag bits.
|
Interrupts - values are flag bits.
|
||||||
|
|
||||||
|
|
|
@ -16,29 +16,29 @@
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
#define ENABLE_TIMESTAMPS
|
#include "CDVD/CDVDcommon.h"
|
||||||
|
#include "CDVD/IsoReader.h"
|
||||||
#include <ctype.h>
|
#include "CDVD/IsoFileFormats.h"
|
||||||
#include <time.h>
|
|
||||||
#include <exception>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "fmt/core.h"
|
|
||||||
|
|
||||||
#include "IsoFS/IsoFS.h"
|
|
||||||
#include "IsoFS/IsoFSCDVD.h"
|
|
||||||
#include "IsoFileFormats.h"
|
|
||||||
|
|
||||||
#include "common/Assertions.h"
|
|
||||||
#include "common/FileSystem.h"
|
|
||||||
#include "common/Path.h"
|
|
||||||
#include "common/StringUtil.h"
|
|
||||||
#include "DebugTools/SymbolMap.h"
|
#include "DebugTools/SymbolMap.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Host.h"
|
#include "Host.h"
|
||||||
#include "IconsFontAwesome5.h"
|
#include "IconsFontAwesome5.h"
|
||||||
|
|
||||||
CDVD_API* CDVD = NULL;
|
#include "common/Assertions.h"
|
||||||
|
#include "common/FileSystem.h"
|
||||||
|
#include "common/Path.h"
|
||||||
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <memory>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "fmt/core.h"
|
||||||
|
|
||||||
|
#define ENABLE_TIMESTAMPS
|
||||||
|
|
||||||
|
CDVD_API* CDVD = nullptr;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// diskTypeCached
|
// diskTypeCached
|
||||||
|
@ -71,37 +71,35 @@ static void CheckNullCDVD()
|
||||||
//
|
//
|
||||||
static int CheckDiskTypeFS(int baseType)
|
static int CheckDiskTypeFS(int baseType)
|
||||||
{
|
{
|
||||||
IsoFSCDVD isofs;
|
IsoReader isor;
|
||||||
IsoDirectory rootdir(isofs);
|
if (isor.Open())
|
||||||
if (rootdir.OpenRootDirectory())
|
|
||||||
{
|
{
|
||||||
if (IsoFile file(isofs); file.open(rootdir, "SYSTEM.CNF"))
|
std::vector<u8> data;
|
||||||
|
if (isor.ReadFile("SYSTEM.CNF", &data))
|
||||||
{
|
{
|
||||||
const int size = file.getLength();
|
if (StringUtil::ContainsSubString(data, "BOOT2"))
|
||||||
const std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size + 1);
|
|
||||||
file.read(buffer.get(), size);
|
|
||||||
buffer[size] = '\0';
|
|
||||||
|
|
||||||
char* pos = strstr(buffer.get(), "BOOT2");
|
|
||||||
if (pos == NULL)
|
|
||||||
{
|
{
|
||||||
pos = strstr(buffer.get(), "BOOT");
|
// PS2 DVD/CD.
|
||||||
if (pos == NULL)
|
return (baseType == CDVD_TYPE_DETCTCD) ? CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD;
|
||||||
return CDVD_TYPE_ILLEGAL;
|
}
|
||||||
|
|
||||||
|
if (StringUtil::ContainsSubString(data, "BOOT"))
|
||||||
|
{
|
||||||
|
// PSX CD.
|
||||||
return CDVD_TYPE_PSCD;
|
return CDVD_TYPE_PSCD;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (baseType == CDVD_TYPE_DETCTCD) ? CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD;
|
return CDVD_TYPE_ILLEGAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PS2 Linux disc 2, doesn't have a System.CNF or a normal ELF
|
// PS2 Linux disc 2, doesn't have a System.CNF or a normal ELF
|
||||||
if (rootdir.Exists("P2L_0100.02"))
|
if (isor.FileExists("P2L_0100.02"))
|
||||||
return CDVD_TYPE_PS2DVD;
|
return CDVD_TYPE_PS2DVD;
|
||||||
|
|
||||||
if (rootdir.Exists("PSX.EXE"))
|
if (isor.FileExists("PSX.EXE"))
|
||||||
return CDVD_TYPE_PSCD;
|
return CDVD_TYPE_PSCD;
|
||||||
|
|
||||||
if (rootdir.Exists("VIDEO_TS/VIDEO_TS.IFO"))
|
if (isor.FileExists("VIDEO_TS/VIDEO_TS.IFO"))
|
||||||
return CDVD_TYPE_DVDV;
|
return CDVD_TYPE_DVDV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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 final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SectorSource& internalReader;
|
|
||||||
std::vector<IsoFileDescriptor> files;
|
|
||||||
IsoFS_Type m_fstype = FStype_ISO9660;
|
|
||||||
|
|
||||||
public:
|
|
||||||
IsoDirectory(SectorSource& r);
|
|
||||||
~IsoDirectory();
|
|
||||||
|
|
||||||
bool OpenRootDirectory(Error* error = nullptr);
|
|
||||||
bool Open(const IsoFileDescriptor& directoryEntry, Error* error = nullptr);
|
|
||||||
|
|
||||||
std::string FStype_ToString() const;
|
|
||||||
SectorSource& GetReader() const { return internalReader; }
|
|
||||||
|
|
||||||
bool Exists(const std::string_view& filePath) const;
|
|
||||||
bool IsFile(const std::string_view& filePath) const;
|
|
||||||
bool IsDir(const std::string_view& filePath) const;
|
|
||||||
|
|
||||||
u32 GetFileSize(const std::string_view& filePath) const;
|
|
||||||
|
|
||||||
std::optional<IsoFileDescriptor> FindFile(const std::string_view& filePath) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const IsoFileDescriptor& GetEntry(size_t index) const;
|
|
||||||
|
|
||||||
int GetIndexOf(const std::string_view& fileName) const;
|
|
||||||
};
|
|
|
@ -1,310 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
|
||||||
|
|
||||||
#include "IsoFS.h"
|
|
||||||
#include "IsoFile.h"
|
|
||||||
|
|
||||||
#include "common/Assertions.h"
|
|
||||||
#include "common/Error.h"
|
|
||||||
#include "common/FileSystem.h"
|
|
||||||
#include "common/Path.h"
|
|
||||||
#include "common/StringUtil.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// IsoDirectory
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL
|
|
||||||
//u8 volID[5]; // "CD001"
|
|
||||||
|
|
||||||
|
|
||||||
std::string IsoDirectory::FStype_ToString() const
|
|
||||||
{
|
|
||||||
switch (m_fstype)
|
|
||||||
{
|
|
||||||
case FStype_ISO9660:
|
|
||||||
return "ISO9660";
|
|
||||||
case FStype_Joliet:
|
|
||||||
return "Joliet";
|
|
||||||
}
|
|
||||||
|
|
||||||
return StringUtil::StdStringFromFormat("Unrecognized Code (0x%x)", m_fstype);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
bool done = false;
|
|
||||||
uint i = 16;
|
|
||||||
|
|
||||||
m_fstype = FStype_ISO9660;
|
|
||||||
|
|
||||||
while (!done)
|
|
||||||
{
|
|
||||||
u8 sector[2048];
|
|
||||||
// If this fails, we're not reading an iso, or it's bad.
|
|
||||||
if (!internalReader.readSector(sector, i))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (memcmp(§or[1], "CD001", 5) == 0)
|
|
||||||
{
|
|
||||||
switch (sector[0])
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
DevCon.WriteLn(Color_Green, "(IsoFS) Block 0x%x: Boot partition info.", i);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
DevCon.WriteLn("(IsoFS) Block 0x%x: Primary partition info.", i);
|
|
||||||
rootDirEntry.Load(sector + 156, 38);
|
|
||||||
isValid = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
// Probably means Joliet (long filenames support), which PCSX2 doesn't care about.
|
|
||||||
DevCon.WriteLn(Color_Green, "(IsoFS) Block 0x%x: Extended partition info.", i);
|
|
||||||
m_fstype = FStype_Joliet;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xff:
|
|
||||||
// Null terminator. End of partition information.
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Console.Error("(IsoFS) Unknown partition type ID=%d, encountered at block 0x%x", sector[0], i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sector[9] = 0;
|
|
||||||
Console.Error("(IsoFS) Invalid partition descriptor encountered at block 0x%x: '%s'", i, §or[1]);
|
|
||||||
break; // if no valid root partition was found, an exception will be thrown below.
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isValid)
|
|
||||||
{
|
|
||||||
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());
|
|
||||||
return Open(rootDirEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to load a specific directory from a file descriptor
|
|
||||||
bool IsoDirectory::Open(const IsoFileDescriptor& directoryEntry, Error* error /* = nullptr */)
|
|
||||||
{
|
|
||||||
// parse directory sector
|
|
||||||
IsoFile dataStream(internalReader, directoryEntry);
|
|
||||||
|
|
||||||
files.clear();
|
|
||||||
|
|
||||||
u32 remainingSize = directoryEntry.size;
|
|
||||||
|
|
||||||
u8 b[257];
|
|
||||||
|
|
||||||
while (remainingSize >= 4) // hm hack :P
|
|
||||||
{
|
|
||||||
b[0] = dataStream.read<u8>();
|
|
||||||
|
|
||||||
if (b[0] == 0)
|
|
||||||
{
|
|
||||||
break; // or continue?
|
|
||||||
}
|
|
||||||
|
|
||||||
remainingSize -= b[0];
|
|
||||||
|
|
||||||
if (dataStream.read(b + 1, static_cast<s32>(b[0] - 1)) != static_cast<s32>(b[0] - 1))
|
|
||||||
break;
|
|
||||||
|
|
||||||
files.emplace_back(b, b[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IsoFileDescriptor& IsoDirectory::GetEntry(size_t index) const
|
|
||||||
{
|
|
||||||
return files[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
int IsoDirectory::GetIndexOf(const std::string_view& fileName) const
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < files.size(); i++)
|
|
||||||
{
|
|
||||||
if (files[i].name == fileName)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<IsoFileDescriptor> IsoDirectory::FindFile(const std::string_view& filePath) const
|
|
||||||
{
|
|
||||||
if (filePath.empty())
|
|
||||||
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));
|
|
||||||
const IsoDirectory* dir = this;
|
|
||||||
IsoDirectory subdir(internalReader);
|
|
||||||
|
|
||||||
for (size_t index = 0; index < (parts.size() - 1); index++)
|
|
||||||
{
|
|
||||||
const int subdir_index = dir->GetIndexOf(parts[index]);
|
|
||||||
if (subdir_index < 0)
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
const IsoFileDescriptor& subdir_entry = GetEntry(static_cast<size_t>(subdir_index));
|
|
||||||
if (subdir_entry.IsFile() || !subdir.Open(subdir_entry, nullptr))
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
dir = &subdir;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int file_index = dir->GetIndexOf(parts.back());
|
|
||||||
if (file_index < 0)
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
return dir->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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
if (filePath.empty())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
|
|
||||||
if (fd.has_value())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return fd->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsoFileDescriptor::IsoFileDescriptor()
|
|
||||||
: lba(0)
|
|
||||||
, size(0)
|
|
||||||
, flags(0)
|
|
||||||
{
|
|
||||||
memset(&date, 0, sizeof(date));
|
|
||||||
}
|
|
||||||
|
|
||||||
IsoFileDescriptor::IsoFileDescriptor(const u8* data, int length)
|
|
||||||
{
|
|
||||||
Load(data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IsoFileDescriptor::Load(const u8* data, int length)
|
|
||||||
{
|
|
||||||
lba = (u32&)data[2];
|
|
||||||
size = (u32&)data[10];
|
|
||||||
|
|
||||||
date.year = data[18] + 1900;
|
|
||||||
date.month = data[19];
|
|
||||||
date.day = data[20];
|
|
||||||
date.hour = data[21];
|
|
||||||
date.minute = data[22];
|
|
||||||
date.second = data[23];
|
|
||||||
date.gmtOffset = data[24];
|
|
||||||
|
|
||||||
flags = data[25];
|
|
||||||
|
|
||||||
int file_name_length = data[32];
|
|
||||||
|
|
||||||
if (file_name_length == 1)
|
|
||||||
{
|
|
||||||
u8 c = data[33];
|
|
||||||
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
name = ".";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
name = "..";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = static_cast<char>(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const u8* fnsrc = data + 33;
|
|
||||||
|
|
||||||
// Strip any version information like the PS2 BIOS does.
|
|
||||||
int length_without_version = 0;
|
|
||||||
for (; length_without_version < file_name_length; length_without_version++)
|
|
||||||
{
|
|
||||||
if (fnsrc[length_without_version] == ';' || fnsrc[length_without_version] == '\0')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
name.assign(reinterpret_cast<const char*>(fnsrc), length_without_version);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class IsoFile;
|
|
||||||
class IsoDirectory;
|
|
||||||
struct IsoFileDescriptor;
|
|
||||||
|
|
||||||
#include "SectorSource.h"
|
|
||||||
#include "IsoFileDescriptor.h"
|
|
||||||
#include "IsoDirectory.h"
|
|
||||||
#include "IsoFile.h"
|
|
|
@ -1,37 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
|
||||||
|
|
||||||
#include "IsoFSCDVD.h"
|
|
||||||
#include "CDVD/CDVDcommon.h"
|
|
||||||
|
|
||||||
IsoFSCDVD::IsoFSCDVD()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsoFSCDVD::readSector(unsigned char* buffer, int lba)
|
|
||||||
{
|
|
||||||
return DoCDVDreadSector(buffer, lba, CDVD_MODE_2048) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int IsoFSCDVD::getNumSectors()
|
|
||||||
{
|
|
||||||
cdvdTD td;
|
|
||||||
CDVD->getTD(0, &td);
|
|
||||||
|
|
||||||
return td.lsn;
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "SectorSource.h"
|
|
||||||
|
|
||||||
class IsoFSCDVD final : public SectorSource
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IsoFSCDVD();
|
|
||||||
virtual ~IsoFSCDVD() = default;
|
|
||||||
|
|
||||||
virtual bool readSector(unsigned char* buffer, int lba);
|
|
||||||
|
|
||||||
virtual int getNumSectors();
|
|
||||||
};
|
|
|
@ -1,262 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
|
||||||
#include "common/Assertions.h"
|
|
||||||
#include "common/Error.h"
|
|
||||||
|
|
||||||
#include "IsoFS.h"
|
|
||||||
#include "IsoFile.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
IsoFile::IsoFile(SectorSource& reader)
|
|
||||||
: internalReader(reader)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
IsoFile::~IsoFile() = default;
|
|
||||||
|
|
||||||
IsoFile::IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry)
|
|
||||||
: internalReader(reader)
|
|
||||||
, fileEntry(fileEntry)
|
|
||||||
{
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IsoFile::Init()
|
|
||||||
{
|
|
||||||
//pxAssertDev( fileEntry.IsFile(), "IsoFile Error: Filename points to a directory." );
|
|
||||||
|
|
||||||
currentSectorNumber = fileEntry.lba;
|
|
||||||
currentOffset = 0;
|
|
||||||
sectorOffset = 0;
|
|
||||||
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;
|
|
||||||
|
|
||||||
int oldSectorNumber = currentSectorNumber;
|
|
||||||
int newSectorNumber = fileEntry.lba + (int)(endOffset / sectorLength);
|
|
||||||
|
|
||||||
if (oldSectorNumber != newSectorNumber)
|
|
||||||
{
|
|
||||||
internalReader.readSector(currentSector, newSectorNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentOffset = endOffset;
|
|
||||||
currentSectorNumber = newSectorNumber;
|
|
||||||
sectorOffset = (int)(currentOffset % sectorLength);
|
|
||||||
|
|
||||||
return currentOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the new offset in the file. Out-of-bounds seeks are automatically truncated at 0
|
|
||||||
// and fileLength.
|
|
||||||
u32 IsoFile::seek(s64 offset, int mode)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case SEEK_SET:
|
|
||||||
pxAssertDev(offset >= 0 && offset <= (s64)ULONG_MAX, "Invalid seek position from start.");
|
|
||||||
return seek(offset);
|
|
||||||
|
|
||||||
case SEEK_CUR:
|
|
||||||
// truncate negative values to zero, and positive values to 4gb
|
|
||||||
return seek(std::min(std::max<s64>(0, (s64)currentOffset + offset), (s64)ULONG_MAX));
|
|
||||||
|
|
||||||
case SEEK_END:
|
|
||||||
// truncate negative values to zero, and positive values to 4gb
|
|
||||||
return seek(std::min(std::max<s64>(0, (s64)fileEntry.size + offset), (s64)ULONG_MAX));
|
|
||||||
|
|
||||||
jNO_DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0; // unreachable
|
|
||||||
}
|
|
||||||
|
|
||||||
void IsoFile::reset()
|
|
||||||
{
|
|
||||||
seek(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the number of bytes actually skipped.
|
|
||||||
s32 IsoFile::skip(s32 n)
|
|
||||||
{
|
|
||||||
s32 oldOffset = currentOffset;
|
|
||||||
|
|
||||||
if (n < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
seek(currentOffset + n);
|
|
||||||
|
|
||||||
return currentOffset - oldOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 IsoFile::getSeekPos() const
|
|
||||||
{
|
|
||||||
return currentOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsoFile::eof() const
|
|
||||||
{
|
|
||||||
return (currentOffset == maxOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// loads the current sector index into the CurrentSector buffer.
|
|
||||||
void IsoFile::makeDataAvailable()
|
|
||||||
{
|
|
||||||
if (sectorOffset >= sectorLength)
|
|
||||||
{
|
|
||||||
currentSectorNumber++;
|
|
||||||
internalReader.readSector(currentSector, currentSectorNumber);
|
|
||||||
sectorOffset -= sectorLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 IsoFile::readByte()
|
|
||||||
{
|
|
||||||
if (currentOffset >= maxOffset)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
makeDataAvailable();
|
|
||||||
|
|
||||||
currentOffset++;
|
|
||||||
|
|
||||||
return currentSector[sectorOffset++];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads data from a single sector at a time. Reads cannot cross sector boundaries.
|
|
||||||
int IsoFile::internalRead(void* dest, int off, int len)
|
|
||||||
{
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
size_t slen = len;
|
|
||||||
if (slen > (maxOffset - currentOffset))
|
|
||||||
{
|
|
||||||
slen = (int)(maxOffset - currentOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy((u8*)dest + off, currentSector + sectorOffset, slen);
|
|
||||||
|
|
||||||
sectorOffset += slen;
|
|
||||||
currentOffset += slen;
|
|
||||||
return slen;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the number of bytes actually read.
|
|
||||||
s32 IsoFile::read(void* dest, s32 len)
|
|
||||||
{
|
|
||||||
pxAssert(dest != NULL);
|
|
||||||
pxAssert(len >= 0); // should we silent-fail on negative length reads? prolly not...
|
|
||||||
|
|
||||||
if (len <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int off = 0;
|
|
||||||
|
|
||||||
int totalLength = 0;
|
|
||||||
|
|
||||||
int firstSector = internalRead(dest, off, std::min(len, sectorLength - sectorOffset));
|
|
||||||
off += firstSector;
|
|
||||||
len -= firstSector;
|
|
||||||
totalLength += firstSector;
|
|
||||||
|
|
||||||
// Read whole sectors
|
|
||||||
while ((len >= sectorLength) && (currentOffset < maxOffset))
|
|
||||||
{
|
|
||||||
makeDataAvailable();
|
|
||||||
int n = internalRead(dest, off, sectorLength);
|
|
||||||
off += n;
|
|
||||||
len -= n;
|
|
||||||
totalLength += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read remaining, if any
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
makeDataAvailable();
|
|
||||||
int lastSector = internalRead(dest, off, len);
|
|
||||||
totalLength += lastSector;
|
|
||||||
}
|
|
||||||
|
|
||||||
return totalLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads data until it reaches a newline character (either \n, \r, or ASCII-Z). The caller is
|
|
||||||
// responsible for handling files with DOS-style newlines (CR/LF pairs), if needed. The resulting
|
|
||||||
// string has no newlines.
|
|
||||||
//
|
|
||||||
// Read data is unformatted 8 bit / Ascii. If the source file is known to be UTF8, use the fromUTF8()
|
|
||||||
// conversion helper provided by PCSX2 utility classes.
|
|
||||||
//
|
|
||||||
std::string IsoFile::readLine()
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
s.reserve(512);
|
|
||||||
|
|
||||||
while (!eof())
|
|
||||||
{
|
|
||||||
u8 c = read<u8>();
|
|
||||||
|
|
||||||
if ((c == '\n') || (c == '\r') || (c == 0))
|
|
||||||
break;
|
|
||||||
|
|
||||||
s += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 IsoFile::getLength()
|
|
||||||
{
|
|
||||||
return maxOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IsoFileDescriptor& IsoFile::getEntry()
|
|
||||||
{
|
|
||||||
return fileEntry;
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IsoFileDescriptor.h"
|
|
||||||
#include "SectorSource.h"
|
|
||||||
|
|
||||||
#include "common/Pcsx2Defs.h"
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
class Error;
|
|
||||||
|
|
||||||
class IsoFile final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const int sectorLength = 2048;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
SectorSource& internalReader;
|
|
||||||
IsoFileDescriptor fileEntry = {};
|
|
||||||
|
|
||||||
u32 currentOffset = 0;
|
|
||||||
u32 maxOffset = 0;
|
|
||||||
|
|
||||||
int currentSectorNumber = 0;
|
|
||||||
int sectorOffset = 0;
|
|
||||||
u8 currentSector[sectorLength];
|
|
||||||
|
|
||||||
public:
|
|
||||||
IsoFile(SectorSource& reader);
|
|
||||||
IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry);
|
|
||||||
~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);
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
s32 skip(s32 n);
|
|
||||||
u32 getSeekPos() const;
|
|
||||||
u32 getLength();
|
|
||||||
bool eof() const;
|
|
||||||
|
|
||||||
const IsoFileDescriptor& getEntry();
|
|
||||||
|
|
||||||
u8 readByte();
|
|
||||||
s32 read(void* dest, s32 len);
|
|
||||||
std::string readLine();
|
|
||||||
|
|
||||||
// Tool to read a specific value type, including structs.
|
|
||||||
template <class T>
|
|
||||||
T read()
|
|
||||||
{
|
|
||||||
if (sizeof(T) == 1)
|
|
||||||
return (T)readByte();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
T t;
|
|
||||||
read((u8*)&t, sizeof(t));
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void makeDataAvailable();
|
|
||||||
int internalRead(void* dest, int off, int len);
|
|
||||||
void Init();
|
|
||||||
};
|
|
|
@ -1,47 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/Pcsx2Defs.h"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
struct IsoFileDescriptor
|
|
||||||
{
|
|
||||||
struct FileDate // not 1:1 with iso9660 date struct
|
|
||||||
{
|
|
||||||
s32 year;
|
|
||||||
u8 month;
|
|
||||||
u8 day;
|
|
||||||
u8 hour;
|
|
||||||
u8 minute;
|
|
||||||
u8 second;
|
|
||||||
u8 gmtOffset; // Offset from Greenwich Mean Time in number of 15 min intervals from -48 (West) to + 52 (East)
|
|
||||||
|
|
||||||
} date;
|
|
||||||
|
|
||||||
u32 lba;
|
|
||||||
u32 size;
|
|
||||||
int flags;
|
|
||||||
std::string name;
|
|
||||||
|
|
||||||
IsoFileDescriptor();
|
|
||||||
IsoFileDescriptor(const u8* data, int length);
|
|
||||||
|
|
||||||
void Load(const u8* data, int length);
|
|
||||||
|
|
||||||
bool IsFile() const { return !(flags & 2); }
|
|
||||||
bool IsDir() const { return !IsFile(); }
|
|
||||||
};
|
|
|
@ -1,24 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 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-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class SectorSource
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual int getNumSectors() = 0;
|
|
||||||
virtual bool readSector(unsigned char* buffer, int lba) = 0;
|
|
||||||
virtual ~SectorSource() = default;
|
|
||||||
};
|
|
|
@ -0,0 +1,315 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* 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-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
|
#include "CDVD/CDVDcommon.h"
|
||||||
|
#include "CDVD/IsoReader.h"
|
||||||
|
|
||||||
|
#include "common/Assertions.h"
|
||||||
|
#include "common/Error.h"
|
||||||
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
IsoReader::IsoReader() = default;
|
||||||
|
|
||||||
|
IsoReader::~IsoReader() = default;
|
||||||
|
|
||||||
|
bool IsoReader::Open(Error* error)
|
||||||
|
{
|
||||||
|
if (!ReadPVD(error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsoReader::ReadSector(u8* buf, u32 lsn, Error* error)
|
||||||
|
{
|
||||||
|
if (DoCDVDreadSector(buf, lsn, CDVD_MODE_2048) != 0)
|
||||||
|
{
|
||||||
|
Error::SetString(error, fmt::format("Failed to read sector LSN #{}", lsn));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsoReader::ReadPVD(Error* error)
|
||||||
|
{
|
||||||
|
// volume descriptor start at sector 16
|
||||||
|
static constexpr u32 START_SECTOR = 16;
|
||||||
|
|
||||||
|
// try only a maximum of 256 volume descriptors
|
||||||
|
for (u32 i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
u8 buffer[SECTOR_SIZE];
|
||||||
|
if (!ReadSector(buffer, START_SECTOR + i, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const ISOVolumeDescriptorHeader* header = reinterpret_cast<ISOVolumeDescriptorHeader*>(buffer);
|
||||||
|
if (std::memcmp(header->standard_identifier, "CD001", 5) != 0)
|
||||||
|
continue;
|
||||||
|
else if (header->type_code != 1)
|
||||||
|
continue;
|
||||||
|
else if (header->type_code == 255)
|
||||||
|
break;
|
||||||
|
|
||||||
|
std::memcpy(&m_pvd, buffer, sizeof(ISOPrimaryVolumeDescriptor));
|
||||||
|
DevCon.WriteLn(fmt::format("ISOReader: PVD found at index {}", i));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error::SetString(error, "Failed to find the Primary Volume Descriptor.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IsoReader::ISODirectoryEntry> IsoReader::LocateFile(const std::string_view& path, Error* error)
|
||||||
|
{
|
||||||
|
const ISODirectoryEntry* root_de = reinterpret_cast<const ISODirectoryEntry*>(m_pvd.root_directory_entry);
|
||||||
|
if (path.empty() || path == "/" || path == "\\")
|
||||||
|
{
|
||||||
|
// locating the root directory
|
||||||
|
return *root_de;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start at the root directory
|
||||||
|
u8 sector_buffer[SECTOR_SIZE];
|
||||||
|
return LocateFile(path, sector_buffer, root_de->location_le, root_de->length_le, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view IsoReader::GetDirectoryEntryFileName(const u8* sector, u32 de_sector_offset)
|
||||||
|
{
|
||||||
|
const ISODirectoryEntry* de = reinterpret_cast<const ISODirectoryEntry*>(sector + de_sector_offset);
|
||||||
|
if ((sizeof(ISODirectoryEntry) + de->filename_length) > de->entry_length ||
|
||||||
|
(sizeof(ISODirectoryEntry) + de->filename_length + de_sector_offset) > SECTOR_SIZE)
|
||||||
|
{
|
||||||
|
return std::string_view();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* str = reinterpret_cast<const char*>(sector + de_sector_offset + sizeof(ISODirectoryEntry));
|
||||||
|
if (de->filename_length == 1)
|
||||||
|
{
|
||||||
|
if (str[0] == '\0')
|
||||||
|
return ".";
|
||||||
|
else if (str[0] == '\1')
|
||||||
|
return "..";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip any version information like the PS2 BIOS does.
|
||||||
|
u32 length_without_version = 0;
|
||||||
|
for (; length_without_version < de->filename_length; length_without_version++)
|
||||||
|
{
|
||||||
|
if (str[length_without_version] == ';' || str[length_without_version] == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string_view(str, length_without_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IsoReader::ISODirectoryEntry> IsoReader::LocateFile(
|
||||||
|
const std::string_view& path, u8* sector_buffer, u32 directory_record_lba, u32 directory_record_size, Error* error)
|
||||||
|
{
|
||||||
|
if (directory_record_size == 0)
|
||||||
|
{
|
||||||
|
Error::SetString(error, fmt::format("Directory entry record size 0 while looking for '{}'", path));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip any leading slashes
|
||||||
|
size_t path_component_start = 0;
|
||||||
|
while (path_component_start < path.length() &&
|
||||||
|
(path[path_component_start] == '/' || path[path_component_start] == '\\'))
|
||||||
|
{
|
||||||
|
path_component_start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t path_component_length = 0;
|
||||||
|
while ((path_component_start + path_component_length) < path.length() &&
|
||||||
|
path[path_component_start + path_component_length] != '/' &&
|
||||||
|
path[path_component_start + path_component_length] != '\\')
|
||||||
|
{
|
||||||
|
path_component_length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string_view path_component = path.substr(path_component_start, path_component_length);
|
||||||
|
if (path_component.empty())
|
||||||
|
{
|
||||||
|
Error::SetString(error, fmt::format("Empty path component in {}", path));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start reading directory entries
|
||||||
|
const u32 num_sectors = (directory_record_size + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
|
||||||
|
for (u32 i = 0; i < num_sectors; i++)
|
||||||
|
{
|
||||||
|
if (!ReadSector(sector_buffer, directory_record_lba + i, error))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
u32 sector_offset = 0;
|
||||||
|
while ((sector_offset + sizeof(ISODirectoryEntry)) < SECTOR_SIZE)
|
||||||
|
{
|
||||||
|
const ISODirectoryEntry* de = reinterpret_cast<const ISODirectoryEntry*>(§or_buffer[sector_offset]);
|
||||||
|
if (de->entry_length < sizeof(ISODirectoryEntry))
|
||||||
|
break;
|
||||||
|
|
||||||
|
const std::string_view de_filename = GetDirectoryEntryFileName(sector_buffer, sector_offset);
|
||||||
|
sector_offset += de->entry_length;
|
||||||
|
|
||||||
|
// Empty file would be pretty strange..
|
||||||
|
if (de_filename.empty() || de_filename == "." || de_filename == "..")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!StringUtil::compareNoCase(de_filename, path_component))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// found it. is this the file we're looking for?
|
||||||
|
if ((path_component_start + path_component_length) == path.length())
|
||||||
|
return *de;
|
||||||
|
|
||||||
|
// if it is a directory, recurse into it
|
||||||
|
if (de->flags & ISODirectoryEntryFlag_Directory)
|
||||||
|
{
|
||||||
|
return LocateFile(path.substr(path_component_start + path_component_length), sector_buffer,
|
||||||
|
de->location_le, de->length_le, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're looking for a directory but got a file
|
||||||
|
Error::SetString(error, fmt::format("Looking for directory '{}' but got file", path_component));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error::SetString(error, fmt::format("Path component '{}' not found", path_component));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> IsoReader::GetFilesInDirectory(const std::string_view& path, Error* error)
|
||||||
|
{
|
||||||
|
std::string base_path(path);
|
||||||
|
u32 directory_record_lsn;
|
||||||
|
u32 directory_record_length;
|
||||||
|
if (base_path.empty())
|
||||||
|
{
|
||||||
|
// root directory
|
||||||
|
const ISODirectoryEntry* root_de = reinterpret_cast<const ISODirectoryEntry*>(m_pvd.root_directory_entry);
|
||||||
|
directory_record_lsn = root_de->location_le;
|
||||||
|
directory_record_length = root_de->length_le;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto directory_de = LocateFile(base_path, error);
|
||||||
|
if (!directory_de.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if ((directory_de->flags & ISODirectoryEntryFlag_Directory) == 0)
|
||||||
|
{
|
||||||
|
Error::SetString(error, fmt::format("Path '{}' is not a directory, can't list", path));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_record_lsn = directory_de->location_le;
|
||||||
|
directory_record_length = directory_de->length_le;
|
||||||
|
|
||||||
|
if (base_path[base_path.size() - 1] != '/')
|
||||||
|
base_path += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// start reading directory entries
|
||||||
|
const u32 num_sectors = (directory_record_length + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
|
||||||
|
std::vector<std::string> files;
|
||||||
|
u8 sector_buffer[SECTOR_SIZE];
|
||||||
|
for (u32 i = 0; i < num_sectors; i++)
|
||||||
|
{
|
||||||
|
if (!ReadSector(sector_buffer, directory_record_lsn + i, error))
|
||||||
|
break;
|
||||||
|
|
||||||
|
u32 sector_offset = 0;
|
||||||
|
while ((sector_offset + sizeof(ISODirectoryEntry)) < SECTOR_SIZE)
|
||||||
|
{
|
||||||
|
const ISODirectoryEntry* de = reinterpret_cast<const ISODirectoryEntry*>(§or_buffer[sector_offset]);
|
||||||
|
if (de->entry_length < sizeof(ISODirectoryEntry))
|
||||||
|
break;
|
||||||
|
|
||||||
|
const std::string_view de_filename = GetDirectoryEntryFileName(sector_buffer, sector_offset);
|
||||||
|
sector_offset += de->entry_length;
|
||||||
|
|
||||||
|
// Empty file would be pretty strange..
|
||||||
|
if (de_filename.empty() || de_filename == "." || de_filename == "..")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
files.push_back(fmt::format("{}/{}", base_path, de_filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsoReader::FileExists(const std::string_view& path, Error* error)
|
||||||
|
{
|
||||||
|
auto de = LocateFile(path, error);
|
||||||
|
if (!de)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (de->flags & ISODirectoryEntryFlag_Directory) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsoReader::DirectoryExists(const std::string_view& path, Error* error)
|
||||||
|
{
|
||||||
|
auto de = LocateFile(path, error);
|
||||||
|
if (!de)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (de->flags & ISODirectoryEntryFlag_Directory) == ISODirectoryEntryFlag_Directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsoReader::ReadFile(const std::string_view& path, std::vector<u8>* data, Error* error)
|
||||||
|
{
|
||||||
|
auto de = LocateFile(path, error);
|
||||||
|
if (!de)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ReadFile(de.value(), data, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsoReader::ReadFile(const ISODirectoryEntry& de, std::vector<u8>* data, Error* error /*= nullptr*/)
|
||||||
|
{
|
||||||
|
if (de.flags & ISODirectoryEntryFlag_Directory)
|
||||||
|
{
|
||||||
|
Error::SetString(error, "File is a directory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (de.length_le == 0)
|
||||||
|
{
|
||||||
|
data->clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(sizeof(size_t) == sizeof(u64));
|
||||||
|
const u32 num_sectors = (de.length_le + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
|
||||||
|
data->resize(num_sectors * static_cast<u64>(SECTOR_SIZE));
|
||||||
|
for (u32 i = 0, lsn = de.location_le; i < num_sectors; i++, lsn++)
|
||||||
|
{
|
||||||
|
if (!ReadSector(data->data() + (i * SECTOR_SIZE), lsn, error))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Might not be sector aligned, so reduce it back.
|
||||||
|
data->resize(de.length_le);
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* 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-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Pcsx2Defs.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Error;
|
||||||
|
|
||||||
|
class IsoReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum : u32
|
||||||
|
{
|
||||||
|
SECTOR_SIZE = 2048
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
struct ISOVolumeDescriptorHeader
|
||||||
|
{
|
||||||
|
u8 type_code;
|
||||||
|
char standard_identifier[5];
|
||||||
|
u8 version;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ISOVolumeDescriptorHeader) == 7);
|
||||||
|
|
||||||
|
struct ISOBootRecord
|
||||||
|
{
|
||||||
|
ISOVolumeDescriptorHeader header;
|
||||||
|
char boot_system_identifier[32];
|
||||||
|
char boot_identifier[32];
|
||||||
|
u8 data[1977];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ISOBootRecord) == 2048);
|
||||||
|
|
||||||
|
struct ISOPVDDateTime
|
||||||
|
{
|
||||||
|
char year[4];
|
||||||
|
char month[2];
|
||||||
|
char day[2];
|
||||||
|
char hour[2];
|
||||||
|
char minute[2];
|
||||||
|
char second[2];
|
||||||
|
char milliseconds[2];
|
||||||
|
s8 gmt_offset;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ISOPVDDateTime) == 17);
|
||||||
|
|
||||||
|
struct ISOPrimaryVolumeDescriptor
|
||||||
|
{
|
||||||
|
ISOVolumeDescriptorHeader header;
|
||||||
|
u8 unused;
|
||||||
|
char system_identifier[32];
|
||||||
|
char volume_identifier[32];
|
||||||
|
char unused2[8];
|
||||||
|
u32 total_sectors_le;
|
||||||
|
u32 total_sectors_be;
|
||||||
|
char unused3[32];
|
||||||
|
u16 volume_set_size_le;
|
||||||
|
u16 volume_set_size_be;
|
||||||
|
u16 volume_sequence_number_le;
|
||||||
|
u16 volume_sequence_number_be;
|
||||||
|
u16 block_size_le;
|
||||||
|
u16 block_size_be;
|
||||||
|
u32 path_table_size_le;
|
||||||
|
u32 path_table_size_be;
|
||||||
|
u32 path_table_location_le;
|
||||||
|
u32 optional_path_table_location_le;
|
||||||
|
u32 path_table_location_be;
|
||||||
|
u32 optional_path_table_location_be;
|
||||||
|
u8 root_directory_entry[34];
|
||||||
|
char volume_set_identifier[128];
|
||||||
|
char publisher_identifier[128];
|
||||||
|
char data_preparer_identifier[128];
|
||||||
|
char application_identifier[128];
|
||||||
|
char copyright_file_identifier[38];
|
||||||
|
char abstract_file_identifier[36];
|
||||||
|
char bibliographic_file_identifier[37];
|
||||||
|
ISOPVDDateTime volume_creation_time;
|
||||||
|
ISOPVDDateTime volume_modification_time;
|
||||||
|
ISOPVDDateTime volume_expiration_time;
|
||||||
|
ISOPVDDateTime volume_effective_time;
|
||||||
|
u8 structure_version;
|
||||||
|
u8 unused4;
|
||||||
|
u8 application_used[512];
|
||||||
|
u8 reserved[653];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ISOPrimaryVolumeDescriptor) == 2048);
|
||||||
|
|
||||||
|
struct ISODirectoryEntryDateTime
|
||||||
|
{
|
||||||
|
u8 years_since_1900;
|
||||||
|
u8 month;
|
||||||
|
u8 day;
|
||||||
|
u8 hour;
|
||||||
|
u8 minute;
|
||||||
|
u8 second;
|
||||||
|
s8 gmt_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ISODirectoryEntryFlags : u8
|
||||||
|
{
|
||||||
|
ISODirectoryEntryFlag_Hidden = (1 << 0),
|
||||||
|
ISODirectoryEntryFlag_Directory = (1 << 1),
|
||||||
|
ISODirectoryEntryFlag_AssociatedFile = (1 << 2),
|
||||||
|
ISODirectoryEntryFlag_ExtendedAttributePresent = (1 << 3),
|
||||||
|
ISODirectoryEntryFlag_OwnerGroupPermissions = (1 << 4),
|
||||||
|
ISODirectoryEntryFlag_MoreExtents = (1 << 7),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ISODirectoryEntry
|
||||||
|
{
|
||||||
|
u8 entry_length;
|
||||||
|
u8 extended_attribute_length;
|
||||||
|
u32 location_le;
|
||||||
|
u32 location_be;
|
||||||
|
u32 length_le;
|
||||||
|
u32 length_be;
|
||||||
|
ISODirectoryEntryDateTime recoding_time;
|
||||||
|
ISODirectoryEntryFlags flags;
|
||||||
|
u8 interleaved_unit_size;
|
||||||
|
u8 interleaved_gap_size;
|
||||||
|
u16 sequence_le;
|
||||||
|
u16 sequence_be;
|
||||||
|
u8 filename_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
IsoReader();
|
||||||
|
~IsoReader();
|
||||||
|
|
||||||
|
const ISOPrimaryVolumeDescriptor& GetPVD() const { return m_pvd; }
|
||||||
|
|
||||||
|
// TODO: Eventually we'll want to pass a handle to the currently-open file here.
|
||||||
|
// ... once I have the energy to make CDVD not depend on a global object.
|
||||||
|
bool Open(Error* error = nullptr);
|
||||||
|
|
||||||
|
std::vector<std::string> GetFilesInDirectory(const std::string_view& path, Error* error = nullptr);
|
||||||
|
|
||||||
|
std::optional<ISODirectoryEntry> LocateFile(const std::string_view& path, Error* error);
|
||||||
|
|
||||||
|
bool FileExists(const std::string_view& path, Error* error = nullptr);
|
||||||
|
bool DirectoryExists(const std::string_view& path, Error* error = nullptr);
|
||||||
|
bool ReadFile(const std::string_view& path, std::vector<u8>* data, Error* error = nullptr);
|
||||||
|
bool ReadFile(const ISODirectoryEntry& de, std::vector<u8>* data, Error* error = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string_view GetDirectoryEntryFileName(const u8* sector, u32 de_sector_offset);
|
||||||
|
|
||||||
|
bool ReadSector(u8* buf, u32 lsn, Error* error);
|
||||||
|
bool ReadPVD(Error* error);
|
||||||
|
|
||||||
|
std::optional<ISODirectoryEntry> LocateFile(const std::string_view& path, u8* sector_buffer,
|
||||||
|
u32 directory_record_lba, u32 directory_record_size, Error* error);
|
||||||
|
|
||||||
|
ISOPrimaryVolumeDescriptor m_pvd = {};
|
||||||
|
};
|
|
@ -247,6 +247,7 @@ set(pcsx2CDVDSources
|
||||||
CDVD/CDVDisoReader.cpp
|
CDVD/CDVDisoReader.cpp
|
||||||
CDVD/CDVDdiscThread.cpp
|
CDVD/CDVDdiscThread.cpp
|
||||||
CDVD/InputIsoFile.cpp
|
CDVD/InputIsoFile.cpp
|
||||||
|
CDVD/IsoReader.cpp
|
||||||
CDVD/OutputIsoFile.cpp
|
CDVD/OutputIsoFile.cpp
|
||||||
CDVD/ChunksCache.cpp
|
CDVD/ChunksCache.cpp
|
||||||
CDVD/CompressedFileReader.cpp
|
CDVD/CompressedFileReader.cpp
|
||||||
|
@ -254,9 +255,6 @@ set(pcsx2CDVDSources
|
||||||
CDVD/CsoFileReader.cpp
|
CDVD/CsoFileReader.cpp
|
||||||
CDVD/GzippedFileReader.cpp
|
CDVD/GzippedFileReader.cpp
|
||||||
CDVD/ThreadedFileReader.cpp
|
CDVD/ThreadedFileReader.cpp
|
||||||
CDVD/IsoFS/IsoFile.cpp
|
|
||||||
CDVD/IsoFS/IsoFSCDVD.cpp
|
|
||||||
CDVD/IsoFS/IsoFS.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# CDVD headers
|
# CDVD headers
|
||||||
|
@ -273,12 +271,7 @@ set(pcsx2CDVDHeaders
|
||||||
CDVD/GzippedFileReader.h
|
CDVD/GzippedFileReader.h
|
||||||
CDVD/ThreadedFileReader.h
|
CDVD/ThreadedFileReader.h
|
||||||
CDVD/IsoFileFormats.h
|
CDVD/IsoFileFormats.h
|
||||||
CDVD/IsoFS/IsoDirectory.h
|
CDVD/IsoReader.h
|
||||||
CDVD/IsoFS/IsoFileDescriptor.h
|
|
||||||
CDVD/IsoFS/IsoFile.h
|
|
||||||
CDVD/IsoFS/IsoFSCDVD.h
|
|
||||||
CDVD/IsoFS/IsoFS.h
|
|
||||||
CDVD/IsoFS/SectorSource.h
|
|
||||||
CDVD/zlib_indexed.h
|
CDVD/zlib_indexed.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "Common.h"
|
|
||||||
|
#include "Elfheader.h"
|
||||||
|
#include "CDVD/IsoReader.h"
|
||||||
|
#include "DebugTools/Debug.h"
|
||||||
|
#include "DebugTools/SymbolMap.h"
|
||||||
|
|
||||||
|
#include "common/Error.h"
|
||||||
#include "common/FileSystem.h"
|
#include "common/FileSystem.h"
|
||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
#include "GS.h" // for sending game crc to mtgs
|
|
||||||
#include "Elfheader.h"
|
|
||||||
#include "DebugTools/SymbolMap.h"
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct PSXEXEHeader
|
struct PSXEXEHeader
|
||||||
{
|
{
|
||||||
|
@ -47,20 +49,17 @@ ElfObject::ElfObject() = default;
|
||||||
|
|
||||||
ElfObject::~ElfObject() = default;
|
ElfObject::~ElfObject() = default;
|
||||||
|
|
||||||
bool ElfObject::OpenIsoFile(std::string srcfile, IsoFile& isofile, bool isPSXElf_, Error* error)
|
bool ElfObject::OpenIsoFile(std::string srcfile, IsoReader& isor, bool isPSXElf_, Error* error)
|
||||||
{
|
{
|
||||||
const u32 length = isofile.getLength();
|
const auto de = isor.LocateFile(srcfile, error);
|
||||||
if (!CheckElfSize(length, error))
|
if (!de)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
data.resize(length);
|
if (!CheckElfSize(de->length_le, error))
|
||||||
|
return false;
|
||||||
const s32 rsize = isofile.read(data.data(), static_cast<s32>(length));
|
|
||||||
if (rsize < static_cast<s32>(length))
|
if (!isor.ReadFile(de.value(), &data, error))
|
||||||
{
|
|
||||||
Error::SetString(error, "Failed to read ELF from ISO");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
filename = std::move(srcfile);
|
filename = std::move(srcfile);
|
||||||
isPSXElf = isPSXElf_;
|
isPSXElf = isPSXElf_;
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/Error.h"
|
|
||||||
#include "CDVD/IsoFS/IsoFSCDVD.h"
|
|
||||||
#include "CDVD/IsoFS/IsoFS.h"
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class Error;
|
||||||
|
class IsoReader;
|
||||||
|
|
||||||
struct ELF_HEADER {
|
struct ELF_HEADER {
|
||||||
u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier)
|
u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier)
|
||||||
u16 e_type; //ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE
|
u16 e_type; //ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE
|
||||||
|
@ -130,7 +130,7 @@ public:
|
||||||
__fi u32 GetSize() const { return static_cast<u32>(data.size()); }
|
__fi u32 GetSize() const { return static_cast<u32>(data.size()); }
|
||||||
|
|
||||||
bool OpenFile(std::string srcfile, bool isPSXElf_, Error* error);
|
bool OpenFile(std::string srcfile, bool isPSXElf_, Error* error);
|
||||||
bool OpenIsoFile(std::string srcfile, IsoFile& isofile, bool isPSXElf_, Error* error);
|
bool OpenIsoFile(std::string srcfile, IsoReader& isor, bool isPSXElf_, Error* error);
|
||||||
|
|
||||||
void LoadHeaders();
|
void LoadHeaders();
|
||||||
|
|
||||||
|
|
|
@ -949,9 +949,11 @@ void VMManager::UpdateELFInfo(std::string elf_path)
|
||||||
{
|
{
|
||||||
Error error;
|
Error error;
|
||||||
ElfObject elfo;
|
ElfObject elfo;
|
||||||
if (!cdvdLoadElf(&elfo, elf_path, false, &error))
|
if (elf_path.empty() || !cdvdLoadElf(&elfo, elf_path, false, &error))
|
||||||
{
|
{
|
||||||
Console.Error(fmt::format("Failed to read ELF being loaded: {}: {}", elf_path, error.GetDescription()));
|
if (!elf_path.empty())
|
||||||
|
Console.Error(fmt::format("Failed to read ELF being loaded: {}: {}", elf_path, error.GetDescription()));
|
||||||
|
|
||||||
s_elf_path = {};
|
s_elf_path = {};
|
||||||
s_elf_text_range = {};
|
s_elf_text_range = {};
|
||||||
s_elf_entry_point = 0xFFFFFFFFu;
|
s_elf_entry_point = 0xFFFFFFFFu;
|
||||||
|
@ -1039,7 +1041,6 @@ bool VMManager::AutoDetectSource(const std::string& filename)
|
||||||
{
|
{
|
||||||
// make sure we're not fast booting when we have no filename
|
// make sure we're not fast booting when we have no filename
|
||||||
CDVDsys_ChangeSource(CDVD_SourceType::NoDisc);
|
CDVDsys_ChangeSource(CDVD_SourceType::NoDisc);
|
||||||
s_fast_boot_requested = false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1157,6 +1158,7 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||||
// ELFs must be fast booted, and GS dumps are never fast booted.
|
// ELFs must be fast booted, and GS dumps are never fast booted.
|
||||||
s_fast_boot_requested =
|
s_fast_boot_requested =
|
||||||
(boot_params.fast_boot.value_or(static_cast<bool>(EmuConfig.EnableFastBoot)) || !s_elf_override.empty()) &&
|
(boot_params.fast_boot.value_or(static_cast<bool>(EmuConfig.EnableFastBoot)) || !s_elf_override.empty()) &&
|
||||||
|
(CDVDsys_GetSourceType() != CDVD_SourceType::NoDisc || !s_elf_override.empty()) &&
|
||||||
!GSDumpReplayer::IsReplayingDump();
|
!GSDumpReplayer::IsReplayingDump();
|
||||||
|
|
||||||
if (!s_elf_override.empty())
|
if (!s_elf_override.empty())
|
||||||
|
@ -1169,7 +1171,6 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||||
}
|
}
|
||||||
|
|
||||||
Hle_SetElfPath(s_elf_override.c_str());
|
Hle_SetElfPath(s_elf_override.c_str());
|
||||||
s_fast_boot_requested = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -114,6 +114,7 @@
|
||||||
<ClCompile Include="CDVD\CompressedFileReader.cpp" />
|
<ClCompile Include="CDVD\CompressedFileReader.cpp" />
|
||||||
<ClCompile Include="CDVD\CsoFileReader.cpp" />
|
<ClCompile Include="CDVD\CsoFileReader.cpp" />
|
||||||
<ClCompile Include="CDVD\GzippedFileReader.cpp" />
|
<ClCompile Include="CDVD\GzippedFileReader.cpp" />
|
||||||
|
<ClCompile Include="CDVD\IsoReader.cpp" />
|
||||||
<ClCompile Include="CDVD\OutputIsoFile.cpp" />
|
<ClCompile Include="CDVD\OutputIsoFile.cpp" />
|
||||||
<ClCompile Include="CDVD\ThreadedFileReader.cpp" />
|
<ClCompile Include="CDVD\ThreadedFileReader.cpp" />
|
||||||
<ClCompile Include="CDVD\Linux\DriveUtility.cpp">
|
<ClCompile Include="CDVD\Linux\DriveUtility.cpp">
|
||||||
|
@ -466,9 +467,6 @@
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="x86\ix86-32\iCore-32.cpp" />
|
<ClCompile Include="x86\ix86-32\iCore-32.cpp" />
|
||||||
<ClCompile Include="x86\iCore.cpp" />
|
<ClCompile Include="x86\iCore.cpp" />
|
||||||
<ClCompile Include="CDVD\IsoFS\IsoFile.cpp" />
|
|
||||||
<ClCompile Include="CDVD\IsoFS\IsoFS.cpp" />
|
|
||||||
<ClCompile Include="CDVD\IsoFS\IsoFSCDVD.cpp" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Achievements.h" />
|
<ClInclude Include="Achievements.h" />
|
||||||
|
@ -480,6 +478,7 @@
|
||||||
<ClInclude Include="CDVD\CsoFileReader.h" />
|
<ClInclude Include="CDVD\CsoFileReader.h" />
|
||||||
<ClInclude Include="CDVD\ChdFileReader.h" />
|
<ClInclude Include="CDVD\ChdFileReader.h" />
|
||||||
<ClInclude Include="CDVD\GzippedFileReader.h" />
|
<ClInclude Include="CDVD\GzippedFileReader.h" />
|
||||||
|
<ClInclude Include="CDVD\IsoReader.h" />
|
||||||
<ClInclude Include="CDVD\ThreadedFileReader.h" />
|
<ClInclude Include="CDVD\ThreadedFileReader.h" />
|
||||||
<ClInclude Include="CDVD\zlib_indexed.h" />
|
<ClInclude Include="CDVD\zlib_indexed.h" />
|
||||||
<ClInclude Include="DebugTools\Breakpoints.h" />
|
<ClInclude Include="DebugTools\Breakpoints.h" />
|
||||||
|
@ -802,12 +801,6 @@
|
||||||
<ClInclude Include="ps2\BiosTools.h" />
|
<ClInclude Include="ps2\BiosTools.h" />
|
||||||
<ClInclude Include="MemoryTypes.h" />
|
<ClInclude Include="MemoryTypes.h" />
|
||||||
<ClInclude Include="x86\iCore.h" />
|
<ClInclude Include="x86\iCore.h" />
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoDirectory.h" />
|
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoFile.h" />
|
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoFileDescriptor.h" />
|
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoFS.h" />
|
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoFSCDVD.h" />
|
|
||||||
<ClInclude Include="CDVD\IsoFS\SectorSource.h" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="$(SolutionDir)3rdparty\fmt\fmt.vcxproj">
|
<ProjectReference Include="$(SolutionDir)3rdparty\fmt\fmt.vcxproj">
|
||||||
|
|
|
@ -680,15 +680,6 @@
|
||||||
<ClCompile Include="x86\iCore.cpp">
|
<ClCompile Include="x86\iCore.cpp">
|
||||||
<Filter>System\Ps2\iCore</Filter>
|
<Filter>System\Ps2\iCore</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="CDVD\IsoFS\IsoFile.cpp">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="CDVD\IsoFS\IsoFS.cpp">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="CDVD\IsoFS\IsoFSCDVD.cpp">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="GameDatabase.cpp">
|
<ClCompile Include="GameDatabase.cpp">
|
||||||
<Filter>Misc</Filter>
|
<Filter>Misc</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -1406,6 +1397,7 @@
|
||||||
<ClCompile Include="ImGui\ImGuiFullscreen.cpp">
|
<ClCompile Include="ImGui\ImGuiFullscreen.cpp">
|
||||||
<Filter>Misc\ImGui</Filter>
|
<Filter>Misc\ImGui</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="CDVD\IsoReader.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Patch.h">
|
<ClInclude Include="Patch.h">
|
||||||
|
@ -1636,24 +1628,6 @@
|
||||||
<ClInclude Include="x86\iCore.h">
|
<ClInclude Include="x86\iCore.h">
|
||||||
<Filter>System\Ps2\iCore</Filter>
|
<Filter>System\Ps2\iCore</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoDirectory.h">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoFile.h">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoFileDescriptor.h">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoFS.h">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="CDVD\IsoFS\IsoFSCDVD.h">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="CDVD\IsoFS\SectorSource.h">
|
|
||||||
<Filter>System\IsoFS</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="GameDatabase.h">
|
<ClInclude Include="GameDatabase.h">
|
||||||
<Filter>Misc</Filter>
|
<Filter>Misc</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -2354,6 +2328,7 @@
|
||||||
<ClInclude Include="ImGui\ImGuiFullscreen.h">
|
<ClInclude Include="ImGui\ImGuiFullscreen.h">
|
||||||
<Filter>Misc\ImGui</Filter>
|
<Filter>Misc\ImGui</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="CDVD\IsoReader.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuildStep Include="rdebug\deci2.h">
|
<CustomBuildStep Include="rdebug\deci2.h">
|
||||||
|
|
Loading…
Reference in New Issue