flycast/core/imgread/common.cpp

318 lines
6.5 KiB
C++
Raw Normal View History

2013-12-19 17:10:14 +00:00
#include "common.h"
#include "hw/gdrom/gdromv3.h"
#include "cfg/option.h"
#include "stdclass.h"
2013-12-19 17:10:14 +00:00
Disc* chd_parse(const char* file, std::vector<u8> *digest);
Disc* gdi_parse(const char* file, std::vector<u8> *digest);
Disc* cdi_parse(const char* file, std::vector<u8> *digest);
Disc* cue_parse(const char* file, std::vector<u8> *digest);
Disc* ioctl_parse(const char* file, std::vector<u8> *digest);
2013-12-19 17:10:14 +00:00
u32 NullDriveDiscType;
Disc* disc;
constexpr Disc* (*drivers[])(const char* path, std::vector<u8> *digest)
2013-12-19 17:10:14 +00:00
{
chd_parse,
gdi_parse,
cdi_parse,
2019-01-30 17:28:49 +00:00
cue_parse,
2021-11-19 22:18:45 +00:00
#if defined(_WIN32) && !defined(TARGET_UWP)
2013-12-19 17:10:14 +00:00
ioctl_parse,
#endif
};
u8 q_subchannel[96];
static bool convertSector(u8* in_buff , u8* out_buff , int from , int to,int sector)
2013-12-19 17:10:14 +00:00
{
//get subchannel data, if any
2019-08-31 15:36:34 +00:00
if (from == 2448)
2013-12-19 17:10:14 +00:00
{
2019-08-31 15:36:34 +00:00
memcpy(q_subchannel, in_buff + 2352, 96);
from -= 96;
2013-12-19 17:10:14 +00:00
}
else
memset(q_subchannel, 0, sizeof(q_subchannel));
//if no conversion
2019-08-31 15:36:34 +00:00
if (to == from)
2013-12-19 17:10:14 +00:00
{
2019-08-31 15:36:34 +00:00
memcpy(out_buff, in_buff, to);
2013-12-19 17:10:14 +00:00
return true;
}
switch (to)
{
case 2340:
2019-08-31 15:36:34 +00:00
verify(from == 2352);
memcpy(out_buff, &in_buff[12], 2340);
2013-12-19 17:10:14 +00:00
break;
case 2328:
2019-08-31 15:36:34 +00:00
verify(from == 2352);
memcpy(out_buff, &in_buff[24], 2328);
2013-12-19 17:10:14 +00:00
break;
case 2336:
2019-08-31 15:36:34 +00:00
verify(from == 2352);
memcpy(out_buff, &in_buff[0x10], 2336);
2013-12-19 17:10:14 +00:00
break;
case 2048:
2019-08-31 15:36:34 +00:00
verify(from == 2448 || from == 2352 || from == 2336);
if (from == 2352 || from == 2448)
2013-12-19 17:10:14 +00:00
{
2019-08-31 15:36:34 +00:00
if (in_buff[15] == 1)
memcpy(out_buff, &in_buff[0x10], 2048); //0x10 -> mode1
2013-12-19 17:10:14 +00:00
else
2019-08-31 15:36:34 +00:00
memcpy(out_buff, &in_buff[0x18], 2048); //0x18 -> mode2 (all forms ?)
2013-12-19 17:10:14 +00:00
}
2019-08-31 15:36:34 +00:00
else
memcpy(out_buff, &in_buff[0x8], 2048); //hmm only possible on mode2.Skip the mode2 header
2013-12-19 17:10:14 +00:00
break;
case 2352:
//if (from >= 2352)
2019-08-31 15:36:34 +00:00
memcpy(out_buff, &in_buff[0], 2352);
2013-12-19 17:10:14 +00:00
break;
default :
2019-07-01 14:10:28 +00:00
INFO_LOG(GDROM, "Sector conversion from %d to %d not supported \n", from , to);
2013-12-19 17:10:14 +00:00
break;
}
return true;
}
Disc* OpenDisc(const std::string& path, std::vector<u8> *digest)
2014-05-26 12:32:07 +00:00
{
for (auto driver : drivers)
{
Disc *disc = driver(path.c_str(), digest);
if (disc != nullptr)
return disc;
}
2014-05-26 12:32:07 +00:00
return nullptr;
2014-05-26 12:32:07 +00:00
}
static bool loadDisk(const std::string& path)
2013-12-19 17:10:14 +00:00
{
TermDrive();
2013-12-19 17:10:14 +00:00
//try all drivers
std::vector<u8> digest;
disc = OpenDisc(path, config::GGPOEnable ? &digest : nullptr);
2013-12-19 17:10:14 +00:00
2019-08-31 15:36:34 +00:00
if (disc != NULL)
{
if (config::GGPOEnable)
MD5Sum().add(digest)
.getDigest(settings.network.md5.game);
INFO_LOG(GDROM, "gdrom: Opened image \"%s\"", path.c_str());
}
else
{
INFO_LOG(GDROM, "gdrom: Failed to open image \"%s\"", path.c_str());
NullDriveDiscType = NoDisk;
}
2019-08-31 15:36:34 +00:00
libCore_gdrom_disc_change();
return disc != NULL;
2013-12-19 17:10:14 +00:00
}
bool InitDrive(const std::string& path)
2013-12-19 17:10:14 +00:00
{
bool rc = DiscSwap(path);
// not needed at startup and confuses some games
sns_asc = 0;
sns_ascq = 0;
sns_key = 0;
return rc;
}
void DiscOpenLid()
{
TermDrive();
NullDriveDiscType = Open;
gd_setdisc();
sns_asc = 0x29;
sns_ascq = 0x00;
sns_key = 0x6;
}
bool DiscSwap(const std::string& path)
{
// These Additional Sense Codes mean "The lid was closed"
sns_asc = 0x28;
sns_ascq = 0x00;
sns_key = 0x6;
if (path.empty())
{
2021-11-04 07:57:15 +00:00
TermDrive();
NullDriveDiscType = NoDisk;
gd_setdisc();
return true;
}
if (loadDisk(path))
return true;
NullDriveDiscType = NoDisk;
gd_setdisc();
return false;
2013-12-19 17:10:14 +00:00
}
void TermDrive()
{
2019-09-07 12:37:39 +00:00
delete disc;
2019-07-08 16:10:43 +00:00
disc = NULL;
2013-12-19 17:10:14 +00:00
}
//
//convert our nice toc struct to dc's native one :)
static u32 createTrackInfo(const Track& track, u32 fad)
2013-12-19 17:10:14 +00:00
{
const u32 adr = 1; // force sub-q channel
2013-12-19 17:10:14 +00:00
u8 p[4];
p[0] = (track.CTRL << 4) | adr;
p[1] = fad >> 16;
p[2] = fad >> 8;
p[3] = fad >> 0;
2013-12-19 17:10:14 +00:00
return *(u32 *)p;
2013-12-19 17:10:14 +00:00
}
2019-08-31 15:36:34 +00:00
static u32 createTrackInfoFirstLast(const Track& track, u32 tracknum)
2013-12-19 17:10:14 +00:00
{
return createTrackInfo(track, tracknum << 16);
2013-12-19 17:10:14 +00:00
}
void libGDR_ReadSector(u8 *buff, u32 startSector, u32 sectorCount, u32 sectorSize)
2013-12-19 17:10:14 +00:00
{
if (disc != nullptr)
disc->ReadSectors(startSector, sectorCount, buff, sectorSize);
2013-12-19 17:10:14 +00:00
}
void libGDR_GetToc(u32* to, DiskArea area)
2013-12-19 17:10:14 +00:00
{
memset(to, 0xFF, 102 * 4);
2013-12-19 17:10:14 +00:00
if (!disc)
return;
//can't get toc on the second area on discs that don't have it
if (area == DoubleDensity && disc->type != GdRom)
return;
2013-12-19 17:10:14 +00:00
//normal CDs: 1 .. tc
//GDROM: area0 is 1 .. 2, area1 is 3 ... tc
u32 first_track = 1;
u32 last_track = disc->tracks.size();
if (area == DoubleDensity)
first_track = 3;
else if (disc->type == GdRom)
last_track = 2;
2013-12-19 17:10:14 +00:00
//Generate the TOC info
2013-12-19 17:10:14 +00:00
//-1 for 1..99 0 ..98
to[99] = createTrackInfoFirstLast(disc->tracks[first_track - 1], first_track);
to[100] = createTrackInfoFirstLast(disc->tracks[last_track - 1], last_track);
if (disc->type == GdRom && area == SingleDensity)
// use smaller LEADOUT
to[101] = createTrackInfo(disc->LeadOut, 13085);
2013-12-19 17:10:14 +00:00
else
to[101] = createTrackInfo(disc->LeadOut, disc->LeadOut.StartFAD);
2013-12-19 17:10:14 +00:00
for (u32 i = first_track - 1; i < last_track; i++)
to[i] = createTrackInfo(disc->tracks[i], disc->tracks[i].StartFAD);
2013-12-19 17:10:14 +00:00
}
void libGDR_GetSessionInfo(u8* to, u8 session)
2013-12-19 17:10:14 +00:00
{
2022-06-15 19:22:12 +00:00
if (disc != nullptr)
disc->GetSessionInfo(to, session);
2013-12-19 17:10:14 +00:00
}
DiscType GuessDiscType(bool m1, bool m2, bool da)
{
if ((m1==true) && (da==false) && (m2==false))
return CdRom;
else if (m2)
return CdRom_XA;
else if (da && m1)
2013-12-19 17:10:14 +00:00
return CdRom_Extra;
else
return CdRom;
}
void Disc::ReadSectors(u32 FAD, u32 count, u8* dst, u32 fmt, LoadProgress *progress)
{
u8 temp[2448];
SectorFormat secfmt;
SubcodeFormat subfmt;
for (u32 i = 1; i <= count; i++)
{
if (progress != nullptr)
{
if (progress->cancelled)
throw LoadCancelledException();
progress->label = "Loading...";
progress->progress = (float)i / count;
}
if (ReadSector(FAD,temp,&secfmt,q_subchannel,&subfmt))
{
//TODO: Proper sector conversions
if (secfmt==SECFMT_2352)
{
convertSector(temp,dst,2352,fmt,FAD);
}
else if (fmt == 2048 && secfmt==SECFMT_2336_MODE2)
memcpy(dst,temp+8,2048);
else if (fmt==2048 && (secfmt==SECFMT_2048_MODE1 || secfmt==SECFMT_2048_MODE2_FORM1 ))
{
memcpy(dst,temp,2048);
}
else if (fmt==2352 && (secfmt==SECFMT_2048_MODE1 || secfmt==SECFMT_2048_MODE2_FORM1 ))
{
INFO_LOG(GDROM, "GDR:fmt=2352;secfmt=2048");
memcpy(dst,temp,2048);
}
else if (fmt==2048 && secfmt==SECFMT_2448_MODE2)
{
// Pier Solar and the Great Architects
convertSector(temp, dst, 2448, fmt, FAD);
}
else
{
WARN_LOG(GDROM, "ERROR: UNABLE TO CONVERT SECTOR. THIS IS FATAL. Format: %d Sector format: %d", fmt, secfmt);
//verify(false);
}
}
else
{
WARN_LOG(GDROM, "Sector Read miss FAD: %d", FAD);
}
dst+=fmt;
FAD++;
}
}
void libGDR_ReadSubChannel(u8 * buff, u32 len)
{
memcpy(buff, q_subchannel, len);
}
u32 libGDR_GetDiscType()
{
if (disc)
return disc->type;
else
return NullDriveDiscType;
}