mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
This new class uses the CCC library I added in the last commit and parses the symbol tables on a worker thread.
611 lines
12 KiB
C++
611 lines
12 KiB
C++
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#include "CDVD/CDVDcommon.h"
|
|
#include "CDVD/IsoReader.h"
|
|
#include "CDVD/IsoFileFormats.h"
|
|
#include "Config.h"
|
|
#include "Host.h"
|
|
#include "IconsFontAwesome5.h"
|
|
|
|
#include "common/Assertions.h"
|
|
#include "common/Console.h"
|
|
#include "common/EnumOps.h"
|
|
#include "common/Error.h"
|
|
#include "common/FileSystem.h"
|
|
#include "common/Path.h"
|
|
#include "common/ProgressCallback.h"
|
|
#include "common/StringUtil.h"
|
|
|
|
#include <ctype.h>
|
|
#include <exception>
|
|
#include <memory>
|
|
#include <time.h>
|
|
|
|
#include "fmt/core.h"
|
|
|
|
// TODO: FIXME! Should be platform specific.
|
|
#ifdef _WIN32
|
|
#include "common/RedtapeWindows.h"
|
|
#endif
|
|
|
|
#define ENABLE_TIMESTAMPS
|
|
|
|
const CDVD_API* CDVD = nullptr;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// diskTypeCached
|
|
// Internal disc type cache, to reduce the overhead of disc type checks, which are
|
|
// performed quite liberally by many games (perhaps intended to keep the PS2 DVD
|
|
// from spinning down due to idle activity?).
|
|
// Cache is set to -1 for init and when the disc is removed/changed, which invokes
|
|
// a new DiskTypeCheck. All subsequent checks use the non-negative value here.
|
|
//
|
|
static int diskTypeCached = -1;
|
|
|
|
// used to bridge the gap between the old getBuffer api and the new getBuffer2 api.
|
|
int lastReadSize;
|
|
u32 lastLSN; // needed for block dumping
|
|
|
|
// Records last read block length for block dumping
|
|
//static int plsn = 0;
|
|
|
|
static OutputIsoFile blockDumpFile;
|
|
|
|
// Assertion check for CDVD != NULL (in devel and debug builds), because its handier than
|
|
// relying on DEP exceptions -- and a little more reliable too.
|
|
static void CheckNullCDVD()
|
|
{
|
|
pxAssertMsg(CDVD, "Invalid CDVD object state (null pointer exception)");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Disk Type detection stuff (from cdvdGigaherz)
|
|
//
|
|
static int CheckDiskTypeFS(int baseType)
|
|
{
|
|
IsoReader isor;
|
|
if (isor.Open())
|
|
{
|
|
std::vector<u8> data;
|
|
if (isor.ReadFile("SYSTEM.CNF", &data))
|
|
{
|
|
if (StringUtil::ContainsSubString(data, "BOOT2"))
|
|
{
|
|
// PS2 DVD/CD.
|
|
return (baseType == CDVD_TYPE_DETCTCD) ? CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD;
|
|
}
|
|
|
|
if (StringUtil::ContainsSubString(data, "BOOT"))
|
|
{
|
|
// PSX CD.
|
|
return CDVD_TYPE_PSCD;
|
|
}
|
|
|
|
return CDVD_TYPE_ILLEGAL;
|
|
}
|
|
|
|
// PS2 Linux disc 2, doesn't have a System.CNF or a normal ELF
|
|
if (isor.FileExists("P2L_0100.02"))
|
|
return CDVD_TYPE_PS2DVD;
|
|
|
|
if (isor.FileExists("PSX.EXE"))
|
|
return CDVD_TYPE_PSCD;
|
|
|
|
if (isor.FileExists("VIDEO_TS/VIDEO_TS.IFO"))
|
|
return CDVD_TYPE_DVDV;
|
|
}
|
|
|
|
#ifdef PCSX2_DEVBUILD
|
|
return CDVD_TYPE_PS2DVD; // need this hack for some homebrew (SMS)
|
|
#endif
|
|
return CDVD_TYPE_ILLEGAL; // << Only for discs which aren't ps2 at all.
|
|
}
|
|
|
|
static int FindDiskType(int mType)
|
|
{
|
|
int dataTracks = 0;
|
|
int audioTracks = 0;
|
|
int iCDType = mType;
|
|
cdvdTN tn;
|
|
|
|
CDVD->getTN(&tn);
|
|
|
|
if (tn.strack != tn.etrack) // multitrack == CD.
|
|
{
|
|
iCDType = CDVD_TYPE_DETCTCD;
|
|
}
|
|
else if (mType < 0)
|
|
{
|
|
static u8 bleh[CD_FRAMESIZE_RAW];
|
|
cdvdTD td;
|
|
|
|
CDVD->getTD(0, &td);
|
|
if (td.lsn > 452849)
|
|
{
|
|
iCDType = CDVD_TYPE_DETCTDVDS;
|
|
}
|
|
else
|
|
{
|
|
if (DoCDVDreadSector(bleh, 16, CDVD_MODE_2048) == 0)
|
|
{
|
|
//const cdVolDesc& volDesc = (cdVolDesc&)bleh;
|
|
//if(volDesc.rootToc.tocSize == 2048)
|
|
|
|
//Horrible hack! in CD images position 166 and 171 have block size but not DVD's
|
|
//It's not always 2048 however (can be 4096)
|
|
//Test Impossible Mission if thia is changed.
|
|
if (*(u16*)(bleh + 166) == *(u16*)(bleh + 171))
|
|
iCDType = CDVD_TYPE_DETCTCD;
|
|
else
|
|
iCDType = CDVD_TYPE_DETCTDVDS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (iCDType == CDVD_TYPE_DETCTDVDS)
|
|
{
|
|
s32 dlt = 0;
|
|
u32 l1s = 0;
|
|
|
|
if (CDVD->getDualInfo(&dlt, &l1s) == 0)
|
|
{
|
|
if (dlt > 0)
|
|
iCDType = CDVD_TYPE_DETCTDVDD;
|
|
}
|
|
}
|
|
|
|
switch (iCDType)
|
|
{
|
|
case CDVD_TYPE_DETCTCD:
|
|
Console.WriteLn(" * CDVD Disk Open: CD, %d tracks (%d to %d):", tn.etrack - tn.strack + 1, tn.strack, tn.etrack);
|
|
break;
|
|
|
|
case CDVD_TYPE_DETCTDVDS:
|
|
Console.WriteLn(" * CDVD Disk Open: DVD, Single layer or unknown:");
|
|
break;
|
|
|
|
case CDVD_TYPE_DETCTDVDD:
|
|
Console.WriteLn(" * CDVD Disk Open: DVD, Double layer:");
|
|
break;
|
|
}
|
|
|
|
audioTracks = dataTracks = 0;
|
|
for (int i = tn.strack; i <= tn.etrack; i++)
|
|
{
|
|
cdvdTD td, td2;
|
|
|
|
CDVD->getTD(i, &td);
|
|
|
|
if (tn.etrack > i)
|
|
CDVD->getTD(i + 1, &td2);
|
|
else
|
|
CDVD->getTD(0, &td2);
|
|
|
|
int tlength = td2.lsn - td.lsn;
|
|
|
|
if (td.type == CDVD_AUDIO_TRACK)
|
|
{
|
|
audioTracks++;
|
|
Console.WriteLn(" * * Track %d: Audio (%d sectors)", i, tlength);
|
|
}
|
|
else
|
|
{
|
|
dataTracks++;
|
|
Console.WriteLn(" * * Track %d: Data (Mode %d) (%d sectors)", i, ((td.type == CDVD_MODE1_TRACK) ? 1 : 2), tlength);
|
|
}
|
|
}
|
|
|
|
if (dataTracks > 0)
|
|
{
|
|
iCDType = CheckDiskTypeFS(iCDType);
|
|
}
|
|
|
|
if (audioTracks > 0)
|
|
{
|
|
switch (iCDType)
|
|
{
|
|
case CDVD_TYPE_PS2CD:
|
|
iCDType = CDVD_TYPE_PS2CDDA;
|
|
break;
|
|
case CDVD_TYPE_PSCD:
|
|
iCDType = CDVD_TYPE_PSCDDA;
|
|
break;
|
|
default:
|
|
iCDType = CDVD_TYPE_CDDA;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return iCDType;
|
|
}
|
|
|
|
static void DetectDiskType()
|
|
{
|
|
if (CDVD->getTrayStatus() == CDVD_TRAY_OPEN)
|
|
{
|
|
diskTypeCached = CDVD_TYPE_NODISC;
|
|
return;
|
|
}
|
|
|
|
int baseMediaType = CDVD->getDiskType();
|
|
int mType = -1;
|
|
|
|
switch (baseMediaType)
|
|
{
|
|
#if 0
|
|
case CDVD_TYPE_CDDA:
|
|
case CDVD_TYPE_PSCD:
|
|
case CDVD_TYPE_PS2CD:
|
|
case CDVD_TYPE_PSCDDA:
|
|
case CDVD_TYPE_PS2CDDA:
|
|
mType = CDVD_TYPE_DETCTCD;
|
|
break;
|
|
|
|
case CDVD_TYPE_DVDV:
|
|
case CDVD_TYPE_PS2DVD:
|
|
mType = CDVD_TYPE_DETCTDVDS;
|
|
break;
|
|
|
|
case CDVD_TYPE_DETCTDVDS:
|
|
case CDVD_TYPE_DETCTDVDD:
|
|
case CDVD_TYPE_DETCTCD:
|
|
mType = baseMediaType;
|
|
break;
|
|
#endif
|
|
|
|
case CDVD_TYPE_NODISC:
|
|
diskTypeCached = CDVD_TYPE_NODISC;
|
|
return;
|
|
}
|
|
|
|
diskTypeCached = FindDiskType(mType);
|
|
}
|
|
|
|
static std::string m_SourceFilename[3];
|
|
static CDVD_SourceType m_CurrentSourceType = CDVD_SourceType::NoDisc;
|
|
|
|
void CDVDsys_SetFile(CDVD_SourceType srctype, std::string newfile)
|
|
{
|
|
#ifdef WIN32
|
|
if (Path::IsAbsolute(newfile))
|
|
{
|
|
const auto splitPath = Path::SplitNativePath(newfile);
|
|
// GetDriveType() Requires trailing backslashes
|
|
const auto root = fmt::format("{}\\", splitPath.at(0));
|
|
|
|
const auto driveType = GetDriveType(StringUtil::UTF8StringToWideString(root).c_str());
|
|
if (driveType == DRIVE_REMOVABLE)
|
|
{
|
|
Host::AddIconOSDMessage("RemovableDriveWarning", ICON_FA_EXCLAMATION_TRIANGLE,
|
|
TRANSLATE_SV("CDVD", "Game disc location is on a removable drive, performance issues such as jittering "
|
|
"and freezing may occur."),
|
|
Host::OSD_WARNING_DURATION);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
m_SourceFilename[enum_cast(srctype)] = std::move(newfile);
|
|
}
|
|
|
|
const std::string& CDVDsys_GetFile(CDVD_SourceType srctype)
|
|
{
|
|
return m_SourceFilename[enum_cast(srctype)];
|
|
}
|
|
|
|
CDVD_SourceType CDVDsys_GetSourceType()
|
|
{
|
|
return m_CurrentSourceType;
|
|
}
|
|
|
|
void CDVDsys_ClearFiles()
|
|
{
|
|
for (u32 i = 0; i < std::size(m_SourceFilename); i++)
|
|
m_SourceFilename[i] = {};
|
|
}
|
|
|
|
void CDVDsys_ChangeSource(CDVD_SourceType type)
|
|
{
|
|
if (CDVD)
|
|
DoCDVDclose();
|
|
|
|
switch (m_CurrentSourceType = type)
|
|
{
|
|
case CDVD_SourceType::Iso:
|
|
CDVD = &CDVDapi_Iso;
|
|
break;
|
|
|
|
case CDVD_SourceType::Disc:
|
|
CDVD = &CDVDapi_Disc;
|
|
break;
|
|
|
|
case CDVD_SourceType::NoDisc:
|
|
CDVD = &CDVDapi_NoDisc;
|
|
break;
|
|
|
|
jNO_DEFAULT;
|
|
}
|
|
}
|
|
|
|
bool DoCDVDopen(Error* error)
|
|
{
|
|
CheckNullCDVD();
|
|
|
|
CDVD->newDiskCB(cdvdNewDiskCB);
|
|
|
|
auto CurrentSourceType = enum_cast(m_CurrentSourceType);
|
|
if (!CDVD->open(m_SourceFilename[CurrentSourceType], error))
|
|
return false; // error! (handled by caller)
|
|
|
|
int cdtype = DoCDVDdetectDiskType();
|
|
|
|
if (!EmuConfig.CdvdDumpBlocks || (cdtype == CDVD_TYPE_NODISC))
|
|
{
|
|
blockDumpFile.Close();
|
|
return true;
|
|
}
|
|
|
|
std::string dump_name(Path::GetFileTitle(m_SourceFilename[CurrentSourceType]));
|
|
if (dump_name.empty())
|
|
dump_name = "Untitled";
|
|
|
|
if (EmuConfig.CurrentBlockdump.empty())
|
|
EmuConfig.CurrentBlockdump = FileSystem::GetWorkingDirectory();
|
|
|
|
std::string temp(Path::Combine(EmuConfig.CurrentBlockdump, dump_name));
|
|
|
|
#ifdef ENABLE_TIMESTAMPS
|
|
std::time_t curtime_t = std::time(nullptr);
|
|
struct tm curtime = {};
|
|
#ifdef _MSC_VER
|
|
localtime_s(&curtime, &curtime_t);
|
|
#else
|
|
localtime_r(&curtime_t, &curtime);
|
|
#endif
|
|
|
|
temp += StringUtil::StdStringFromFormat(" (%04d-%02d-%02d %02d-%02d-%02d)",
|
|
curtime.tm_year + 1900, curtime.tm_mon + 1, curtime.tm_mday,
|
|
curtime.tm_hour, curtime.tm_min, curtime.tm_sec);
|
|
#endif
|
|
temp += ".dump";
|
|
|
|
cdvdTD td;
|
|
CDVD->getTD(0, &td);
|
|
|
|
Host::AddKeyedOSDMessage("BlockDumpCreate",
|
|
fmt::format(TRANSLATE_FS("CDVD", "Saving CDVD block dump to '{}'."), temp), Host::OSD_INFO_DURATION);
|
|
|
|
if (blockDumpFile.Create(std::move(temp), 2))
|
|
{
|
|
int blockofs = 0;
|
|
uint blocksize = CD_FRAMESIZE_RAW;
|
|
uint blocks = td.lsn;
|
|
|
|
// hack: Because of limitations of the current cdvd design, we can't query the blocksize
|
|
// of the underlying media. So lets make a best guess:
|
|
|
|
switch (cdtype)
|
|
{
|
|
case CDVD_TYPE_PS2DVD:
|
|
case CDVD_TYPE_DVDV:
|
|
case CDVD_TYPE_DETCTDVDS:
|
|
case CDVD_TYPE_DETCTDVDD:
|
|
blocksize = 2048;
|
|
break;
|
|
}
|
|
blockDumpFile.WriteHeader(blockofs, blocksize, blocks);
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DoCDVDprecache(ProgressCallback* progress, Error* error)
|
|
{
|
|
CheckNullCDVD();
|
|
progress->SetTitle(TRANSLATE("CDVD", "Precaching CDVD"));
|
|
return CDVD->precache(progress, error);
|
|
}
|
|
|
|
void DoCDVDclose()
|
|
{
|
|
CheckNullCDVD();
|
|
|
|
blockDumpFile.Close();
|
|
|
|
CDVD->close();
|
|
|
|
DoCDVDresetDiskTypeCache();
|
|
}
|
|
|
|
s32 DoCDVDreadSector(u8* buffer, u32 lsn, int mode)
|
|
{
|
|
CheckNullCDVD();
|
|
int ret = CDVD->readSector(buffer, lsn, mode);
|
|
|
|
if (ret == 0 && blockDumpFile.IsOpened())
|
|
{
|
|
if (blockDumpFile.GetBlockSize() == CD_FRAMESIZE_RAW && mode != CDVD_MODE_2352)
|
|
{
|
|
u8 blockDumpBuffer[CD_FRAMESIZE_RAW];
|
|
if (CDVD->readSector(blockDumpBuffer, lsn, CDVD_MODE_2352) == 0)
|
|
blockDumpFile.WriteSector(blockDumpBuffer, lsn);
|
|
}
|
|
else
|
|
{
|
|
blockDumpFile.WriteSector(buffer, lsn);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
s32 DoCDVDreadTrack(u32 lsn, int mode)
|
|
{
|
|
CheckNullCDVD();
|
|
|
|
// TODO: The CDVD api only uses the new getBuffer style. Why is this temp?
|
|
// lastReadSize is needed for block dumps
|
|
switch (mode)
|
|
{
|
|
case CDVD_MODE_2352:
|
|
lastReadSize = 2352;
|
|
break;
|
|
case CDVD_MODE_2340:
|
|
lastReadSize = 2340;
|
|
break;
|
|
case CDVD_MODE_2328:
|
|
lastReadSize = 2328;
|
|
break;
|
|
case CDVD_MODE_2048:
|
|
lastReadSize = 2048;
|
|
break;
|
|
}
|
|
|
|
//DevCon.Warning("CDVD readTrack(lsn=%d,mode=%d)",params lsn, lastReadSize);
|
|
lastLSN = lsn;
|
|
return CDVD->readTrack(lsn, mode);
|
|
}
|
|
|
|
s32 DoCDVDgetBuffer(u8* buffer)
|
|
{
|
|
CheckNullCDVD();
|
|
const int ret = CDVD->getBuffer(buffer);
|
|
|
|
if (ret == 0 && blockDumpFile.IsOpened())
|
|
{
|
|
cdvdTD td;
|
|
CDVD->getTD(0, &td);
|
|
|
|
if (lastLSN >= td.lsn)
|
|
return 0;
|
|
|
|
if (blockDumpFile.GetBlockSize() == CD_FRAMESIZE_RAW && lastReadSize != 2352)
|
|
{
|
|
u8 blockDumpBuffer[CD_FRAMESIZE_RAW];
|
|
if (CDVD->readSector(blockDumpBuffer, lastLSN, CDVD_MODE_2352) == 0)
|
|
blockDumpFile.WriteSector(blockDumpBuffer, lastLSN);
|
|
}
|
|
else
|
|
{
|
|
blockDumpFile.WriteSector(buffer, lastLSN);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
s32 DoCDVDdetectDiskType()
|
|
{
|
|
CheckNullCDVD();
|
|
if (diskTypeCached < 0)
|
|
DetectDiskType();
|
|
return diskTypeCached;
|
|
}
|
|
|
|
void DoCDVDresetDiskTypeCache()
|
|
{
|
|
diskTypeCached = -1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// CDVD null interface for Run BIOS menu
|
|
|
|
|
|
|
|
static bool NODISCopen(std::string filename, Error* error)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
static bool NODISCprecache(ProgressCallback* progress, Error* error)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
static void NODISCclose()
|
|
{
|
|
}
|
|
|
|
static s32 NODISCreadTrack(u32 lsn, int mode)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static s32 NODISCgetBuffer(u8* buffer)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static s32 NODISCreadSubQ(u32 lsn, cdvdSubQ* subq)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static s32 NODISCgetTN(cdvdTN* Buffer)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static s32 NODISCgetTD(u8 Track, cdvdTD* Buffer)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static s32 NODISCgetTOC(void* toc)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static s32 NODISCgetDiskType()
|
|
{
|
|
return CDVD_TYPE_NODISC;
|
|
}
|
|
|
|
static s32 NODISCgetTrayStatus()
|
|
{
|
|
return CDVD_TRAY_CLOSE;
|
|
}
|
|
|
|
static s32 NODISCdummyS32()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void NODISCnewDiskCB(void (*/* callback */)())
|
|
{
|
|
}
|
|
|
|
static s32 NODISCreadSector(u8* tempbuffer, u32 lsn, int mode)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static s32 NODISCgetDualInfo(s32* dualType, u32* _layer1start)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
const CDVD_API CDVDapi_NoDisc =
|
|
{
|
|
NODISCclose,
|
|
NODISCopen,
|
|
NODISCprecache,
|
|
NODISCreadTrack,
|
|
NODISCgetBuffer,
|
|
NODISCreadSubQ,
|
|
NODISCgetTN,
|
|
NODISCgetTD,
|
|
NODISCgetTOC,
|
|
NODISCgetDiskType,
|
|
NODISCgetTrayStatus,
|
|
NODISCdummyS32,
|
|
NODISCdummyS32,
|
|
|
|
NODISCnewDiskCB,
|
|
|
|
NODISCreadSector,
|
|
NODISCgetDualInfo,
|
|
};
|