mirror of
https://github.com/libretro/beetle-psx-libretro.git
synced 2025-02-11 12:05:58 +00:00
Take out CDUtility namespace and some other cleanups
This commit is contained in:
parent
1114032411
commit
5681b1a43a
14
libretro.cpp
14
libretro.cpp
@ -972,7 +972,7 @@ static bool TestMagic(const char *name, MDFNFILE *fp)
|
||||
static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
|
||||
{
|
||||
uint8_t buf[2048];
|
||||
CDUtility::TOC toc;
|
||||
TOC toc;
|
||||
int dt;
|
||||
|
||||
(*CDInterfaces)[0]->ReadTOC(&toc);
|
||||
@ -1012,7 +1012,7 @@ static const char *CalcDiscSCEx_BySYSTEMCNF(CDIF *c, unsigned *rr)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
Stream *fp = NULL;
|
||||
CDUtility::TOC toc;
|
||||
TOC toc;
|
||||
|
||||
//(*CDInterfaces)[disc]->ReadTOC(&toc);
|
||||
|
||||
@ -2329,7 +2329,7 @@ void retro_init(void)
|
||||
log_cb = NULL;
|
||||
|
||||
#ifdef NEED_CD
|
||||
CDUtility::CDUtility_Init();
|
||||
CDUtility_Init();
|
||||
#endif
|
||||
|
||||
eject_state = false;
|
||||
@ -2353,10 +2353,10 @@ void retro_init(void)
|
||||
log_cb(RETRO_LOG_WARN, "System directory is not defined. Fallback on using same dir as ROM for system directory later ...\n");
|
||||
failed_init = true;
|
||||
}
|
||||
|
||||
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &dir) && dir)
|
||||
{
|
||||
// If save directory is defined use it, otherwise use system directory
|
||||
// If save directory is defined use it, otherwise use system directory
|
||||
retro_save_directory = *dir ? dir : retro_base_directory;
|
||||
// Make sure that we don't have any lingering slashes, etc, as they break Windows.
|
||||
size_t last = retro_save_directory.find_last_not_of("/\\");
|
||||
@ -2370,7 +2370,7 @@ void retro_init(void)
|
||||
/* TODO: Add proper fallback */
|
||||
if (log_cb)
|
||||
log_cb(RETRO_LOG_WARN, "Save directory is not defined. Fallback on using SYSTEM directory ...\n");
|
||||
retro_save_directory = retro_base_directory;
|
||||
retro_save_directory = retro_base_directory;
|
||||
}
|
||||
|
||||
#if defined(WANT_16BPP) && defined(FRONTEND_SUPPORTS_RGB565)
|
||||
@ -2734,7 +2734,7 @@ MDFNGI *MDFNI_LoadCD(const char *force_module, const char *devicename)
|
||||
// Print out a track list for all discs. //
|
||||
for(unsigned i = 0; i < CDInterfaces.size(); i++)
|
||||
{
|
||||
CDUtility::TOC toc;
|
||||
TOC toc;
|
||||
|
||||
CDInterfaces[i]->ReadTOC(&toc);
|
||||
|
||||
|
@ -45,16 +45,16 @@ MemoryStream::MemoryStream(Stream *stream) : data_buffer(NULL), data_buffer_size
|
||||
delete stream;
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(const MemoryStream &zs)
|
||||
MemoryStream::MemoryStream(const MemoryStream *zs)
|
||||
{
|
||||
data_buffer_size = zs.data_buffer_size;
|
||||
data_buffer_alloced = zs.data_buffer_alloced;
|
||||
data_buffer_size = zs->data_buffer_size;
|
||||
data_buffer_alloced = zs->data_buffer_alloced;
|
||||
if(!(data_buffer = (uint8*)malloc((size_t)data_buffer_alloced)))
|
||||
throw MDFN_Error(ErrnoHolder(errno));
|
||||
|
||||
memcpy(data_buffer, zs.data_buffer, (size_t)data_buffer_size);
|
||||
memcpy(data_buffer, zs->data_buffer, (size_t)data_buffer_size);
|
||||
|
||||
position = zs.position;
|
||||
position = zs->position;
|
||||
}
|
||||
|
||||
MemoryStream::~MemoryStream()
|
||||
|
@ -32,8 +32,8 @@ class MemoryStream : public Stream
|
||||
// Will only work if stream->tell() == 0, or if "stream" is seekable.
|
||||
// stream will be deleted even if this constructor throws.
|
||||
|
||||
MemoryStream(const MemoryStream &zs);
|
||||
MemoryStream & operator=(const MemoryStream &zs);
|
||||
MemoryStream(const MemoryStream *zs);
|
||||
MemoryStream & operator=(const MemoryStream *zs);
|
||||
|
||||
virtual ~MemoryStream();
|
||||
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include "CDAccess_Image.h"
|
||||
#include "CDAccess_CCD.h"
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
CDAccess::CDAccess()
|
||||
{
|
||||
|
||||
|
@ -14,7 +14,7 @@ class CDAccess
|
||||
|
||||
virtual void Read_Raw_Sector(uint8 *buf, int32 lba) = 0;
|
||||
|
||||
virtual void Read_TOC(CDUtility::TOC *toc) = 0;
|
||||
virtual void Read_TOC(TOC *toc) = 0;
|
||||
|
||||
virtual void Eject(bool eject_status) = 0; // Eject a disc if it's physical, otherwise NOP. Returns true on success(or NOP), false on error
|
||||
|
||||
|
@ -25,358 +25,252 @@
|
||||
#include <limits.h>
|
||||
#include <map>
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
typedef std::map<std::string, std::string> CCD_Section;
|
||||
|
||||
template<typename T>
|
||||
static T CCD_ReadInt(CCD_Section &s, const std::string &propname, const bool have_defval = false, const int defval = 0)
|
||||
{
|
||||
CCD_Section::iterator zit = s.find(propname);
|
||||
CCD_Section::iterator zit = s.find(propname);
|
||||
|
||||
if(zit == s.end())
|
||||
{
|
||||
if(have_defval)
|
||||
return defval;
|
||||
else
|
||||
throw MDFN_Error(0, _("Missing property: %s"), propname.c_str());
|
||||
}
|
||||
if(zit == s.end())
|
||||
{
|
||||
if(have_defval)
|
||||
return defval;
|
||||
throw MDFN_Error(0, _("Missing property: %s"), propname.c_str());
|
||||
}
|
||||
|
||||
const std::string &v = zit->second;
|
||||
int scan_base = 10;
|
||||
size_t scan_offset = 0;
|
||||
long ret = 0;
|
||||
|
||||
if(v.length() >= 3 && v[0] == '0' && v[1] == 'x')
|
||||
{
|
||||
scan_base = 16;
|
||||
scan_offset = 2;
|
||||
}
|
||||
const std::string &v = zit->second;
|
||||
int scan_base = 10;
|
||||
size_t scan_offset = 0;
|
||||
long ret = 0;
|
||||
|
||||
const char *vp = v.c_str() + scan_offset;
|
||||
char *ep = NULL;
|
||||
if(v.length() >= 3 && v[0] == '0' && v[1] == 'x')
|
||||
{
|
||||
scan_base = 16;
|
||||
scan_offset = 2;
|
||||
}
|
||||
|
||||
if(std::numeric_limits<T>::is_signed)
|
||||
ret = strtol(vp, &ep, scan_base);
|
||||
else
|
||||
ret = strtoul(vp, &ep, scan_base);
|
||||
const char *vp = v.c_str() + scan_offset;
|
||||
char *ep = NULL;
|
||||
|
||||
if(!vp[0] || ep[0])
|
||||
{
|
||||
throw MDFN_Error(0, _("Property %s: Malformed integer: %s"), propname.c_str(), v.c_str());
|
||||
}
|
||||
if(std::numeric_limits<T>::is_signed)
|
||||
ret = strtol(vp, &ep, scan_base);
|
||||
else
|
||||
ret = strtoul(vp, &ep, scan_base);
|
||||
|
||||
//if(ret < minv || ret > maxv)
|
||||
//{
|
||||
// throw MDFN_Error(0, _("Property %s: Integer %ld out of range(accepted: %d through %d)."), propname.c_str(), ret, minv, maxv);
|
||||
//}
|
||||
if(!vp[0] || ep[0])
|
||||
throw MDFN_Error(0, _("Property %s: Malformed integer: %s"), propname.c_str(), v.c_str());
|
||||
|
||||
return ret;
|
||||
//if(ret < minv || ret > maxv)
|
||||
//{
|
||||
// throw MDFN_Error(0, _("Property %s: Integer %ld out of range(accepted: %d through %d)."), propname.c_str(), ret, minv, maxv);
|
||||
//}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
CDAccess_CCD::CDAccess_CCD(const char *path, bool image_memcache) : img_stream(NULL), sub_stream(NULL), img_numsectors(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
Load(path, image_memcache);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Cleanup();
|
||||
throw;
|
||||
}
|
||||
try
|
||||
{
|
||||
Load(path, image_memcache);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Cleanup();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void CDAccess_CCD::Load(const char *path, bool image_memcache)
|
||||
{
|
||||
FileStream cf(path, FileStream::MODE_READ);
|
||||
std::map<std::string, CCD_Section> Sections;
|
||||
std::string linebuf;
|
||||
std::string cur_section_name;
|
||||
std::string dir_path, file_base, file_ext;
|
||||
char img_extsd[4] = { 'i', 'm', 'g', 0 };
|
||||
char sub_extsd[4] = { 's', 'u', 'b', 0 };
|
||||
FileStream cf(path, FileStream::MODE_READ);
|
||||
std::map<std::string, CCD_Section> Sections;
|
||||
std::string linebuf;
|
||||
std::string cur_section_name;
|
||||
std::string dir_path, file_base, file_ext;
|
||||
char img_extsd[4] = { 'i', 'm', 'g', 0 };
|
||||
char sub_extsd[4] = { 's', 'u', 'b', 0 };
|
||||
|
||||
MDFN_GetFilePathComponents(path, &dir_path, &file_base, &file_ext);
|
||||
MDFN_GetFilePathComponents(path, &dir_path, &file_base, &file_ext);
|
||||
|
||||
if(file_ext.length() == 4 && file_ext[0] == '.')
|
||||
{
|
||||
signed char extupt[3] = { -1, -1, -1 };
|
||||
|
||||
for(int i = 1; i < 4; i++)
|
||||
{
|
||||
if(file_ext[i] >= 'A' && file_ext[i] <= 'Z')
|
||||
extupt[i - 1] = 'A' - 'a';
|
||||
else if(file_ext[i] >= 'a' && file_ext[i] <= 'z')
|
||||
extupt[i - 1] = 0;
|
||||
}
|
||||
|
||||
signed char av = -1;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(extupt[i] != -1)
|
||||
av = extupt[i];
|
||||
else
|
||||
extupt[i] = av;
|
||||
}
|
||||
|
||||
if(av == -1)
|
||||
av = 0;
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(extupt[i] == -1)
|
||||
extupt[i] = av;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
img_extsd[i] += extupt[i];
|
||||
sub_extsd[i] += extupt[i];
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%s %d %d %d\n", file_ext.c_str(), extupt[0], extupt[1], extupt[2]);
|
||||
|
||||
linebuf.reserve(256);
|
||||
|
||||
while(cf.get_line(linebuf) >= 0)
|
||||
{
|
||||
MDFN_trim(linebuf);
|
||||
|
||||
if(linebuf.length() == 0) // Skip blank lines.
|
||||
continue;
|
||||
|
||||
if(linebuf[0] == '[')
|
||||
{
|
||||
if(linebuf.length() < 3 || linebuf[linebuf.length() - 1] != ']')
|
||||
throw MDFN_Error(0, _("Malformed section specifier: %s"), linebuf.c_str());
|
||||
|
||||
cur_section_name = linebuf.substr(1, linebuf.length() - 2);
|
||||
MDFN_strtoupper(cur_section_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t feqpos = linebuf.find('=');
|
||||
const size_t leqpos = linebuf.rfind('=');
|
||||
std::string k, v;
|
||||
|
||||
if(feqpos == std::string::npos || feqpos != leqpos)
|
||||
throw MDFN_Error(0, _("Malformed value pair specifier: %s"), linebuf.c_str());
|
||||
|
||||
k = linebuf.substr(0, feqpos);
|
||||
v = linebuf.substr(feqpos + 1);
|
||||
|
||||
MDFN_trim(k);
|
||||
MDFN_trim(v);
|
||||
|
||||
MDFN_strtoupper(k);
|
||||
|
||||
Sections[cur_section_name][k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
CCD_Section& ds = Sections["DISC"];
|
||||
unsigned toc_entries = CCD_ReadInt<unsigned>(ds, "TOCENTRIES");
|
||||
unsigned num_sessions = CCD_ReadInt<unsigned>(ds, "SESSIONS");
|
||||
bool data_tracks_scrambled = CCD_ReadInt<unsigned>(ds, "DATATRACKSSCRAMBLED");
|
||||
|
||||
if(num_sessions != 1)
|
||||
throw MDFN_Error(0, _("Unsupported number of sessions: %u"), num_sessions);
|
||||
|
||||
if(data_tracks_scrambled)
|
||||
throw MDFN_Error(0, _("Scrambled CCD data tracks currently not supported."));
|
||||
|
||||
//printf("MOO: %d\n", toc_entries);
|
||||
|
||||
for(unsigned te = 0; te < toc_entries; te++)
|
||||
{
|
||||
char tmpbuf[64];
|
||||
snprintf(tmpbuf, sizeof(tmpbuf), "ENTRY %u", te);
|
||||
CCD_Section& ts = Sections[std::string(tmpbuf)];
|
||||
unsigned session = CCD_ReadInt<unsigned>(ts, "SESSION");
|
||||
uint8 point = CCD_ReadInt<uint8>(ts, "POINT");
|
||||
uint8 adr = CCD_ReadInt<uint8>(ts, "ADR");
|
||||
uint8 control = CCD_ReadInt<uint8>(ts, "CONTROL");
|
||||
uint8 pmin = CCD_ReadInt<uint8>(ts, "PMIN");
|
||||
uint8 psec = CCD_ReadInt<uint8>(ts, "PSEC");
|
||||
uint8 pframe = CCD_ReadInt<uint8>(ts, "PFRAME");
|
||||
signed plba = CCD_ReadInt<signed>(ts, "PLBA");
|
||||
|
||||
if(session != 1)
|
||||
throw MDFN_Error(0, "Unsupported TOC entry Session value: %u", session);
|
||||
|
||||
// Reference: ECMA-394, page 5-14
|
||||
switch(point)
|
||||
if(file_ext.length() == 4 && file_ext[0] == '.')
|
||||
{
|
||||
default:
|
||||
throw MDFN_Error(0, "Unsupported TOC entry Point value: %u", point);
|
||||
signed char extupt[3] = { -1, -1, -1 };
|
||||
|
||||
case 0xA0:
|
||||
tocd.first_track = pmin;
|
||||
tocd.disc_type = psec;
|
||||
break;
|
||||
for(int i = 1; i < 4; i++)
|
||||
{
|
||||
if(file_ext[i] >= 'A' && file_ext[i] <= 'Z')
|
||||
extupt[i - 1] = 'A' - 'a';
|
||||
else if(file_ext[i] >= 'a' && file_ext[i] <= 'z')
|
||||
extupt[i - 1] = 0;
|
||||
}
|
||||
|
||||
case 0xA1:
|
||||
tocd.last_track = pmin;
|
||||
break;
|
||||
signed char av = -1;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(extupt[i] != -1)
|
||||
av = extupt[i];
|
||||
else
|
||||
extupt[i] = av;
|
||||
}
|
||||
|
||||
case 0xA2:
|
||||
tocd.tracks[100].adr = adr;
|
||||
tocd.tracks[100].control = control;
|
||||
tocd.tracks[100].lba = plba;
|
||||
break;
|
||||
if(av == -1)
|
||||
av = 0;
|
||||
|
||||
case 99:
|
||||
case 98:
|
||||
case 97:
|
||||
case 96:
|
||||
case 95:
|
||||
case 94:
|
||||
case 93:
|
||||
case 92:
|
||||
case 91:
|
||||
case 90:
|
||||
case 89:
|
||||
case 88:
|
||||
case 87:
|
||||
case 86:
|
||||
case 85:
|
||||
case 84:
|
||||
case 83:
|
||||
case 82:
|
||||
case 81:
|
||||
case 80:
|
||||
case 79:
|
||||
case 78:
|
||||
case 77:
|
||||
case 76:
|
||||
case 75:
|
||||
case 74:
|
||||
case 73:
|
||||
case 72:
|
||||
case 71:
|
||||
case 70:
|
||||
case 69:
|
||||
case 68:
|
||||
case 67:
|
||||
case 66:
|
||||
case 65:
|
||||
case 64:
|
||||
case 63:
|
||||
case 62:
|
||||
case 61:
|
||||
case 60:
|
||||
case 59:
|
||||
case 58:
|
||||
case 57:
|
||||
case 56:
|
||||
case 55:
|
||||
case 54:
|
||||
case 53:
|
||||
case 52:
|
||||
case 51:
|
||||
case 50:
|
||||
case 49:
|
||||
case 48:
|
||||
case 47:
|
||||
case 46:
|
||||
case 45:
|
||||
case 44:
|
||||
case 43:
|
||||
case 42:
|
||||
case 41:
|
||||
case 40:
|
||||
case 39:
|
||||
case 38:
|
||||
case 37:
|
||||
case 36:
|
||||
case 35:
|
||||
case 34:
|
||||
case 33:
|
||||
case 32:
|
||||
case 31:
|
||||
case 30:
|
||||
case 29:
|
||||
case 28:
|
||||
case 27:
|
||||
case 26:
|
||||
case 25:
|
||||
case 24:
|
||||
case 23:
|
||||
case 22:
|
||||
case 21:
|
||||
case 20:
|
||||
case 19:
|
||||
case 18:
|
||||
case 17:
|
||||
case 16:
|
||||
case 15:
|
||||
case 14:
|
||||
case 13:
|
||||
case 12:
|
||||
case 11:
|
||||
case 10:
|
||||
case 9:
|
||||
case 8:
|
||||
case 7:
|
||||
case 6:
|
||||
case 5:
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
case 1:
|
||||
tocd.tracks[point].adr = adr;
|
||||
tocd.tracks[point].control = control;
|
||||
tocd.tracks[point].lba = plba;
|
||||
break;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(extupt[i] == -1)
|
||||
extupt[i] = av;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
img_extsd[i] += extupt[i];
|
||||
sub_extsd[i] += extupt[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience leadout track duplication.
|
||||
if(tocd.last_track < 99)
|
||||
tocd.tracks[tocd.last_track + 1] = tocd.tracks[100];
|
||||
//printf("%s %d %d %d\n", file_ext.c_str(), extupt[0], extupt[1], extupt[2]);
|
||||
|
||||
//
|
||||
// Open image stream.
|
||||
{
|
||||
std::string image_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(img_extsd), true);
|
||||
linebuf.reserve(256);
|
||||
|
||||
if(image_memcache)
|
||||
{
|
||||
img_stream = new MemoryStream(new FileStream(image_path.c_str(), FileStream::MODE_READ));
|
||||
}
|
||||
else
|
||||
{
|
||||
img_stream = new FileStream(image_path.c_str(), FileStream::MODE_READ);
|
||||
}
|
||||
while(cf.get_line(linebuf) >= 0)
|
||||
{
|
||||
MDFN_trim(linebuf);
|
||||
|
||||
int64 ss = img_stream->size();
|
||||
if(linebuf.length() == 0) // Skip blank lines.
|
||||
continue;
|
||||
|
||||
if(ss % 2352)
|
||||
throw MDFN_Error(0, _("CCD image size is not evenly divisible by 2352."));
|
||||
if(linebuf[0] == '[')
|
||||
{
|
||||
if(linebuf.length() < 3 || linebuf[linebuf.length() - 1] != ']')
|
||||
throw MDFN_Error(0, _("Malformed section specifier: %s"), linebuf.c_str());
|
||||
|
||||
img_numsectors = ss / 2352;
|
||||
}
|
||||
cur_section_name = linebuf.substr(1, linebuf.length() - 2);
|
||||
MDFN_strtoupper(cur_section_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t feqpos = linebuf.find('=');
|
||||
const size_t leqpos = linebuf.rfind('=');
|
||||
std::string k, v;
|
||||
|
||||
//
|
||||
// Open subchannel stream
|
||||
{
|
||||
std::string sub_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(sub_extsd), true);
|
||||
if(feqpos == std::string::npos || feqpos != leqpos)
|
||||
throw MDFN_Error(0, _("Malformed value pair specifier: %s"), linebuf.c_str());
|
||||
|
||||
if(image_memcache)
|
||||
sub_stream = new MemoryStream(new FileStream(sub_path.c_str(), FileStream::MODE_READ));
|
||||
else
|
||||
sub_stream = new FileStream(sub_path.c_str(), FileStream::MODE_READ);
|
||||
k = linebuf.substr(0, feqpos);
|
||||
v = linebuf.substr(feqpos + 1);
|
||||
|
||||
if(sub_stream->size() != (int64)img_numsectors * 96)
|
||||
throw MDFN_Error(0, _("CCD SUB file size mismatch."));
|
||||
}
|
||||
MDFN_trim(k);
|
||||
MDFN_trim(v);
|
||||
|
||||
CheckSubQSanity();
|
||||
MDFN_strtoupper(k);
|
||||
|
||||
Sections[cur_section_name][k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
CCD_Section& ds = Sections["DISC"];
|
||||
unsigned toc_entries = CCD_ReadInt<unsigned>(ds, "TOCENTRIES");
|
||||
unsigned num_sessions = CCD_ReadInt<unsigned>(ds, "SESSIONS");
|
||||
bool data_tracks_scrambled = CCD_ReadInt<unsigned>(ds, "DATATRACKSSCRAMBLED");
|
||||
|
||||
if(num_sessions != 1)
|
||||
throw MDFN_Error(0, _("Unsupported number of sessions: %u"), num_sessions);
|
||||
|
||||
if(data_tracks_scrambled)
|
||||
throw MDFN_Error(0, _("Scrambled CCD data tracks currently not supported."));
|
||||
|
||||
//printf("MOO: %d\n", toc_entries);
|
||||
|
||||
for(unsigned te = 0; te < toc_entries; te++)
|
||||
{
|
||||
char tmpbuf[64];
|
||||
snprintf(tmpbuf, sizeof(tmpbuf), "ENTRY %u", te);
|
||||
CCD_Section& ts = Sections[std::string(tmpbuf)];
|
||||
unsigned session = CCD_ReadInt<unsigned>(ts, "SESSION");
|
||||
uint8 point = CCD_ReadInt<uint8>(ts, "POINT");
|
||||
uint8 adr = CCD_ReadInt<uint8>(ts, "ADR");
|
||||
uint8 control = CCD_ReadInt<uint8>(ts, "CONTROL");
|
||||
uint8 pmin = CCD_ReadInt<uint8>(ts, "PMIN");
|
||||
uint8 psec = CCD_ReadInt<uint8>(ts, "PSEC");
|
||||
uint8 pframe = CCD_ReadInt<uint8>(ts, "PFRAME");
|
||||
signed plba = CCD_ReadInt<signed>(ts, "PLBA");
|
||||
|
||||
if(session != 1)
|
||||
throw MDFN_Error(0, "Unsupported TOC entry Session value: %u", session);
|
||||
|
||||
// Reference: ECMA-394, page 5-14
|
||||
if (point >= 1 && point <= 99)
|
||||
{
|
||||
tocd.tracks[point].adr = adr;
|
||||
tocd.tracks[point].control = control;
|
||||
tocd.tracks[point].lba = plba;
|
||||
}
|
||||
else
|
||||
switch(point)
|
||||
{
|
||||
default:
|
||||
throw MDFN_Error(0, "Unsupported TOC entry Point value: %u", point);
|
||||
|
||||
case 0xA0:
|
||||
tocd.first_track = pmin;
|
||||
tocd.disc_type = psec;
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
tocd.last_track = pmin;
|
||||
break;
|
||||
|
||||
case 0xA2:
|
||||
tocd.tracks[100].adr = adr;
|
||||
tocd.tracks[100].control = control;
|
||||
tocd.tracks[100].lba = plba;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience leadout track duplication.
|
||||
if(tocd.last_track < 99)
|
||||
tocd.tracks[tocd.last_track + 1] = tocd.tracks[100];
|
||||
|
||||
//
|
||||
// Open image stream.
|
||||
{
|
||||
std::string image_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(img_extsd), true);
|
||||
FileStream *str = new FileStream(image_path.c_str(), FileStream::MODE_READ);
|
||||
|
||||
if(image_memcache)
|
||||
img_stream = new MemoryStream(str);
|
||||
else
|
||||
img_stream = str;
|
||||
|
||||
int64 ss = img_stream->size();
|
||||
|
||||
if(ss % 2352)
|
||||
throw MDFN_Error(0, _("CCD image size is not evenly divisible by 2352."));
|
||||
|
||||
img_numsectors = ss / 2352;
|
||||
}
|
||||
|
||||
{
|
||||
// Open subchannel stream
|
||||
std::string sub_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(sub_extsd), true);
|
||||
|
||||
if(image_memcache)
|
||||
sub_stream = new MemoryStream(new FileStream(sub_path.c_str(), FileStream::MODE_READ));
|
||||
else
|
||||
sub_stream = new FileStream(sub_path.c_str(), FileStream::MODE_READ);
|
||||
|
||||
if(sub_stream->size() != (int64)img_numsectors * 96)
|
||||
throw MDFN_Error(0, _("CCD SUB file size mismatch."));
|
||||
}
|
||||
|
||||
CheckSubQSanity();
|
||||
}
|
||||
|
||||
//
|
||||
@ -389,113 +283,112 @@ case 1:
|
||||
//
|
||||
void CDAccess_CCD::CheckSubQSanity(void)
|
||||
{
|
||||
size_t checksum_pass_counter = 0;
|
||||
int prev_lba = INT_MAX;
|
||||
uint8 prev_track = 0;
|
||||
size_t checksum_pass_counter = 0;
|
||||
int prev_lba = INT_MAX;
|
||||
uint8 prev_track = 0;
|
||||
|
||||
for(size_t s = 0; s < img_numsectors; s++)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint8 full[96];
|
||||
struct
|
||||
for(size_t s = 0; s < img_numsectors; s++)
|
||||
{
|
||||
uint8 pbuf[12];
|
||||
uint8 qbuf[12];
|
||||
};
|
||||
} buf;
|
||||
union
|
||||
{
|
||||
uint8 full[96];
|
||||
struct
|
||||
{
|
||||
uint8 pbuf[12];
|
||||
uint8 qbuf[12];
|
||||
};
|
||||
} buf;
|
||||
|
||||
sub_stream->seek(s * 96, SEEK_SET);
|
||||
sub_stream->read(buf.full, 96);
|
||||
sub_stream->seek(s * 96, SEEK_SET);
|
||||
sub_stream->read(buf.full, 96);
|
||||
|
||||
if(subq_check_checksum(buf.qbuf))
|
||||
{
|
||||
uint8 adr = buf.qbuf[0] & 0xF;
|
||||
if(subq_check_checksum(buf.qbuf))
|
||||
{
|
||||
uint8 adr = buf.qbuf[0] & 0xF;
|
||||
|
||||
if(adr == 0x01)
|
||||
{
|
||||
uint8 track_bcd = buf.qbuf[1];
|
||||
uint8 index_bcd = buf.qbuf[2];
|
||||
uint8 rm_bcd = buf.qbuf[3];
|
||||
uint8 rs_bcd = buf.qbuf[4];
|
||||
uint8 rf_bcd = buf.qbuf[5];
|
||||
uint8 am_bcd = buf.qbuf[7];
|
||||
uint8 as_bcd = buf.qbuf[8];
|
||||
uint8 af_bcd = buf.qbuf[9];
|
||||
if(adr == 0x01)
|
||||
{
|
||||
uint8 track_bcd = buf.qbuf[1];
|
||||
uint8 index_bcd = buf.qbuf[2];
|
||||
uint8 rm_bcd = buf.qbuf[3];
|
||||
uint8 rs_bcd = buf.qbuf[4];
|
||||
uint8 rf_bcd = buf.qbuf[5];
|
||||
uint8 am_bcd = buf.qbuf[7];
|
||||
uint8 as_bcd = buf.qbuf[8];
|
||||
uint8 af_bcd = buf.qbuf[9];
|
||||
|
||||
//printf("%2x %2x %2x\n", am_bcd, as_bcd, af_bcd);
|
||||
//printf("%2x %2x %2x\n", am_bcd, as_bcd, af_bcd);
|
||||
|
||||
if(!BCD_is_valid(track_bcd) || !BCD_is_valid(index_bcd) || !BCD_is_valid(rm_bcd) || !BCD_is_valid(rs_bcd) || !BCD_is_valid(rf_bcd) ||
|
||||
!BCD_is_valid(am_bcd) || !BCD_is_valid(as_bcd) || !BCD_is_valid(af_bcd) ||
|
||||
rs_bcd > 0x59 || rf_bcd > 0x74 || as_bcd > 0x59 || af_bcd > 0x74)
|
||||
{
|
||||
throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad BCD/out of range): %02x:%02x:%02x %02x:%02x:%02x"), rm_bcd, rs_bcd, rf_bcd, am_bcd, as_bcd, af_bcd);
|
||||
}
|
||||
else
|
||||
{
|
||||
int lba = ((BCD_to_U8(am_bcd) * 60 + BCD_to_U8(as_bcd)) * 75 + BCD_to_U8(af_bcd)) - 150;
|
||||
uint8 track = BCD_to_U8(track_bcd);
|
||||
if(!BCD_is_valid(track_bcd) || !BCD_is_valid(index_bcd) || !BCD_is_valid(rm_bcd) || !BCD_is_valid(rs_bcd) || !BCD_is_valid(rf_bcd) ||
|
||||
!BCD_is_valid(am_bcd) || !BCD_is_valid(as_bcd) || !BCD_is_valid(af_bcd) ||
|
||||
rs_bcd > 0x59 || rf_bcd > 0x74 || as_bcd > 0x59 || af_bcd > 0x74)
|
||||
{
|
||||
throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad BCD/out of range): %02x:%02x:%02x %02x:%02x:%02x"), rm_bcd, rs_bcd, rf_bcd, am_bcd, as_bcd, af_bcd);
|
||||
}
|
||||
else
|
||||
{
|
||||
int lba = ((BCD_to_U8(am_bcd) * 60 + BCD_to_U8(as_bcd)) * 75 + BCD_to_U8(af_bcd)) - 150;
|
||||
uint8 track = BCD_to_U8(track_bcd);
|
||||
|
||||
prev_lba = lba;
|
||||
prev_lba = lba;
|
||||
|
||||
if(track < prev_track)
|
||||
throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad track number)"));
|
||||
//else if(prev_track && track - pre
|
||||
if(track < prev_track)
|
||||
throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad track number)"));
|
||||
//else if(prev_track && track - pre
|
||||
|
||||
prev_track = track;
|
||||
}
|
||||
checksum_pass_counter++;
|
||||
prev_track = track;
|
||||
}
|
||||
checksum_pass_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%u/%u\n", checksum_pass_counter, img_numsectors);
|
||||
//printf("%u/%u\n", checksum_pass_counter, img_numsectors);
|
||||
}
|
||||
|
||||
void CDAccess_CCD::Cleanup(void)
|
||||
{
|
||||
if(img_stream)
|
||||
{
|
||||
delete img_stream;
|
||||
img_stream = NULL;
|
||||
}
|
||||
if(img_stream)
|
||||
{
|
||||
delete img_stream;
|
||||
img_stream = NULL;
|
||||
}
|
||||
|
||||
if(sub_stream)
|
||||
{
|
||||
delete sub_stream;
|
||||
sub_stream = NULL;
|
||||
}
|
||||
if(sub_stream)
|
||||
{
|
||||
delete sub_stream;
|
||||
sub_stream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CDAccess_CCD::~CDAccess_CCD()
|
||||
{
|
||||
Cleanup();
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void CDAccess_CCD::Read_Raw_Sector(uint8 *buf, int32 lba)
|
||||
{
|
||||
if(lba < 0 || (size_t)lba >= img_numsectors)
|
||||
throw(MDFN_Error(0, _("LBA out of range.")));
|
||||
if(lba < 0 || (size_t)lba >= img_numsectors)
|
||||
throw(MDFN_Error(0, _("LBA out of range.")));
|
||||
|
||||
uint8 sub_buf[96];
|
||||
uint8 sub_buf[96];
|
||||
|
||||
img_stream->seek(lba * 2352, SEEK_SET);
|
||||
img_stream->read(buf, 2352);
|
||||
img_stream->seek(lba * 2352, SEEK_SET);
|
||||
img_stream->read(buf, 2352);
|
||||
|
||||
sub_stream->seek(lba * 96, SEEK_SET);
|
||||
sub_stream->read(sub_buf, 96);
|
||||
sub_stream->seek(lba * 96, SEEK_SET);
|
||||
sub_stream->read(sub_buf, 96);
|
||||
|
||||
subpw_interleave(sub_buf, buf + 2352);
|
||||
subpw_interleave(sub_buf, buf + 2352);
|
||||
}
|
||||
|
||||
|
||||
void CDAccess_CCD::Read_TOC(CDUtility::TOC *toc)
|
||||
void CDAccess_CCD::Read_TOC(TOC *toc)
|
||||
{
|
||||
*toc = tocd;
|
||||
*toc = tocd;
|
||||
}
|
||||
|
||||
void CDAccess_CCD::Eject(bool eject_status)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ class CDAccess_CCD : public CDAccess
|
||||
|
||||
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
|
||||
|
||||
virtual void Read_TOC(CDUtility::TOC *toc);
|
||||
virtual void Read_TOC(TOC *toc);
|
||||
|
||||
virtual void Eject(bool eject_status);
|
||||
|
||||
@ -47,7 +47,7 @@ class CDAccess_CCD : public CDAccess
|
||||
Stream* img_stream;
|
||||
Stream* sub_stream;
|
||||
size_t img_numsectors;
|
||||
CDUtility::TOC tocd;
|
||||
TOC tocd;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -54,8 +54,6 @@ extern retro_log_printf_t log_cb;
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
enum
|
||||
{
|
||||
CDRF_SUBM_NONE = 0,
|
||||
|
@ -31,33 +31,6 @@ struct CDRFILE_TRACK_INFO
|
||||
|
||||
AudioReader *AReader;
|
||||
};
|
||||
#if 0
|
||||
struct Medium_Chunk
|
||||
{
|
||||
int64 Offset; // Offset in [..TODO..]
|
||||
uint32 DIFormat;
|
||||
|
||||
FILE *fp;
|
||||
bool FirstFileInstance;
|
||||
bool RawAudioMSBFirst;
|
||||
unsigned int SubchannelMode;
|
||||
|
||||
uint32 LastSamplePos;
|
||||
AudioReader *AReader;
|
||||
};
|
||||
|
||||
struct CD_Chunk
|
||||
{
|
||||
int32 LBA;
|
||||
int32 Track;
|
||||
int32 Index;
|
||||
bool DataType;
|
||||
|
||||
Medium_Chunk Medium;
|
||||
};
|
||||
|
||||
static std::vector<CD_Chunk> Chunks;
|
||||
#endif
|
||||
|
||||
class CDAccess_Image : public CDAccess
|
||||
{
|
||||
@ -68,7 +41,7 @@ class CDAccess_Image : public CDAccess
|
||||
|
||||
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
|
||||
|
||||
virtual void Read_TOC(CDUtility::TOC *toc);
|
||||
virtual void Read_TOC(TOC *toc);
|
||||
|
||||
virtual void Eject(bool eject_status);
|
||||
private:
|
||||
|
@ -23,44 +23,39 @@
|
||||
#include "lec.h"
|
||||
|
||||
#include <assert.h>
|
||||
// Kill_LEC_Correct();
|
||||
|
||||
|
||||
namespace CDUtility
|
||||
{
|
||||
|
||||
// lookup table for crc calculation
|
||||
static uint16 subq_crctab[256] =
|
||||
{
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
|
||||
|
||||
@ -70,163 +65,159 @@ static bool CDUtility_Inited = false;
|
||||
|
||||
static void InitScrambleTable(void)
|
||||
{
|
||||
unsigned cv = 1;
|
||||
unsigned cv = 1;
|
||||
|
||||
for(unsigned i = 12; i < 2352; i++)
|
||||
{
|
||||
unsigned char z = 0;
|
||||
for(unsigned i = 12; i < 2352; i++)
|
||||
{
|
||||
unsigned char z = 0;
|
||||
|
||||
for(int b = 0; b < 8; b++)
|
||||
{
|
||||
z |= (cv & 1) << b;
|
||||
for(int b = 0; b < 8; b++)
|
||||
{
|
||||
z |= (cv & 1) << b;
|
||||
|
||||
int feedback = ((cv >> 1) & 1) ^ (cv & 1);
|
||||
cv = (cv >> 1) | (feedback << 14);
|
||||
}
|
||||
int feedback = ((cv >> 1) & 1) ^ (cv & 1);
|
||||
cv = (cv >> 1) | (feedback << 14);
|
||||
}
|
||||
|
||||
scramble_table[i - 12] = z;
|
||||
}
|
||||
scramble_table[i - 12] = z;
|
||||
}
|
||||
|
||||
//for(int i = 0; i < 2352 - 12; i++)
|
||||
// printf("0x%02x, ", scramble_table[i]);
|
||||
//for(int i = 0; i < 2352 - 12; i++)
|
||||
// printf("0x%02x, ", scramble_table[i]);
|
||||
}
|
||||
|
||||
void CDUtility_Init(void)
|
||||
{
|
||||
if(!CDUtility_Inited)
|
||||
{
|
||||
Init_LEC_Correct();
|
||||
if(!CDUtility_Inited)
|
||||
{
|
||||
Init_LEC_Correct();
|
||||
|
||||
InitScrambleTable();
|
||||
InitScrambleTable();
|
||||
|
||||
CDUtility_Inited = true;
|
||||
}
|
||||
CDUtility_Inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
void encode_mode0_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode0_sector(aba, sector_data);
|
||||
lec_encode_mode0_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode1_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode1_sector(aba, sector_data);
|
||||
lec_encode_mode1_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_sector(aba, sector_data);
|
||||
lec_encode_mode2_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_form1_sector(aba, sector_data);
|
||||
lec_encode_mode2_form1_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data)
|
||||
{
|
||||
CDUtility_Init();
|
||||
CDUtility_Init();
|
||||
|
||||
lec_encode_mode2_form2_sector(aba, sector_data);
|
||||
lec_encode_mode2_form2_sector(aba, sector_data);
|
||||
}
|
||||
|
||||
bool edc_check(const uint8 *sector_data, bool xa)
|
||||
{
|
||||
CDUtility_Init();
|
||||
CDUtility_Init();
|
||||
|
||||
return(CheckEDC(sector_data, xa));
|
||||
return(CheckEDC(sector_data, xa));
|
||||
}
|
||||
|
||||
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa)
|
||||
{
|
||||
CDUtility_Init();
|
||||
CDUtility_Init();
|
||||
|
||||
return(ValidateRawSector(sector_data, xa));
|
||||
return(ValidateRawSector(sector_data, xa));
|
||||
}
|
||||
|
||||
|
||||
bool subq_check_checksum(const uint8 *SubQBuf)
|
||||
{
|
||||
uint16 crc = 0;
|
||||
uint16 stored_crc = 0;
|
||||
uint16 crc = 0;
|
||||
uint16 stored_crc = 0;
|
||||
|
||||
stored_crc = SubQBuf[0xA] << 8;
|
||||
stored_crc |= SubQBuf[0xB];
|
||||
stored_crc = SubQBuf[0xA] << 8;
|
||||
stored_crc |= SubQBuf[0xB];
|
||||
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
|
||||
|
||||
crc = ~crc;
|
||||
crc = ~crc;
|
||||
|
||||
return(crc == stored_crc);
|
||||
return(crc == stored_crc);
|
||||
}
|
||||
|
||||
void subq_generate_checksum(uint8 *buf)
|
||||
{
|
||||
uint16 crc = 0;
|
||||
uint16 crc = 0;
|
||||
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
|
||||
for(int i = 0; i < 0xA; i++)
|
||||
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
|
||||
|
||||
// Checksum
|
||||
buf[0xa] = ~(crc >> 8);
|
||||
buf[0xb] = ~(crc);
|
||||
// Checksum
|
||||
buf[0xa] = ~(crc >> 8);
|
||||
buf[0xb] = ~(crc);
|
||||
}
|
||||
|
||||
void subq_deinterleave(const uint8 *SubPWBuf, uint8 *qbuf)
|
||||
{
|
||||
memset(qbuf, 0, 0xC);
|
||||
memset(qbuf, 0, 0xC);
|
||||
|
||||
for(int i = 0; i < 96; i++)
|
||||
{
|
||||
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
|
||||
}
|
||||
for(int i = 0; i < 96; i++)
|
||||
qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
|
||||
}
|
||||
|
||||
|
||||
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
|
||||
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf)
|
||||
{
|
||||
assert(in_buf != out_buf);
|
||||
assert(in_buf != out_buf);
|
||||
|
||||
memset(out_buf, 0, 96);
|
||||
memset(out_buf, 0, 96);
|
||||
|
||||
for(unsigned ch = 0; ch < 8; ch++)
|
||||
{
|
||||
for(unsigned i = 0; i < 96; i++)
|
||||
{
|
||||
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
|
||||
}
|
||||
}
|
||||
for(unsigned ch = 0; ch < 8; ch++)
|
||||
{
|
||||
for(unsigned i = 0; i < 96; i++)
|
||||
out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
|
||||
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
|
||||
{
|
||||
assert(in_buf != out_buf);
|
||||
assert(in_buf != out_buf);
|
||||
|
||||
for(unsigned d = 0; d < 12; d++)
|
||||
{
|
||||
for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
|
||||
{
|
||||
uint8 rawb = 0;
|
||||
|
||||
for(unsigned ch = 0; ch < 8; ch++)
|
||||
for(unsigned d = 0; d < 12; d++)
|
||||
{
|
||||
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
|
||||
for(unsigned bitpoodle = 0; bitpoodle < 8; bitpoodle++)
|
||||
{
|
||||
uint8 rawb = 0;
|
||||
|
||||
for(unsigned ch = 0; ch < 8; ch++)
|
||||
{
|
||||
rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
|
||||
}
|
||||
out_buf[(d << 3) + bitpoodle] = rawb;
|
||||
}
|
||||
}
|
||||
out_buf[(d << 3) + bitpoodle] = rawb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTES ON LEADOUT AREA SYNTHESIS
|
||||
@ -237,99 +228,85 @@ void subpw_interleave(const uint8 *in_buf, uint8 *out_buf)
|
||||
//
|
||||
void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf)
|
||||
{
|
||||
uint8 buf[0xC];
|
||||
uint32 lba_relative;
|
||||
uint32 ma, sa, fa;
|
||||
uint32 m, s, f;
|
||||
uint8 buf[0xC];
|
||||
uint32 lba_relative;
|
||||
uint32 ma, sa, fa;
|
||||
uint32 m, s, f;
|
||||
|
||||
lba_relative = lba - toc.tracks[100].lba;
|
||||
lba_relative = lba - toc.tracks[100].lba;
|
||||
|
||||
f = (lba_relative % 75);
|
||||
s = ((lba_relative / 75) % 60);
|
||||
m = (lba_relative / 75 / 60);
|
||||
f = (lba_relative % 75);
|
||||
s = ((lba_relative / 75) % 60);
|
||||
m = (lba_relative / 75 / 60);
|
||||
|
||||
fa = (lba + 150) % 75;
|
||||
sa = ((lba + 150) / 75) % 60;
|
||||
ma = ((lba + 150) / 75 / 60);
|
||||
fa = (lba + 150) % 75;
|
||||
sa = ((lba + 150) / 75) % 60;
|
||||
ma = ((lba + 150) / 75 / 60);
|
||||
|
||||
uint8 adr = 0x1; // Q channel data encodes position
|
||||
uint8 control = (toc.tracks[toc.last_track].control & 0x4) | toc.tracks[100].control;
|
||||
uint8 adr = 0x1; // Q channel data encodes position
|
||||
uint8 control = (toc.tracks[toc.last_track].control & 0x4) | toc.tracks[100].control;
|
||||
|
||||
memset(buf, 0, 0xC);
|
||||
buf[0] = (adr << 0) | (control << 4);
|
||||
buf[1] = 0xAA;
|
||||
buf[2] = 0x01;
|
||||
memset(buf, 0, 0xC);
|
||||
buf[0] = (adr << 0) | (control << 4);
|
||||
buf[1] = 0xAA;
|
||||
buf[2] = 0x01;
|
||||
|
||||
// Track relative MSF address
|
||||
buf[3] = U8_to_BCD(m);
|
||||
buf[4] = U8_to_BCD(s);
|
||||
buf[5] = U8_to_BCD(f);
|
||||
// Track relative MSF address
|
||||
buf[3] = U8_to_BCD(m);
|
||||
buf[4] = U8_to_BCD(s);
|
||||
buf[5] = U8_to_BCD(f);
|
||||
|
||||
buf[6] = 0; // Zerroooo
|
||||
buf[6] = 0; // Zerroooo
|
||||
|
||||
// Absolute MSF address
|
||||
buf[7] = U8_to_BCD(ma);
|
||||
buf[8] = U8_to_BCD(sa);
|
||||
buf[9] = U8_to_BCD(fa);
|
||||
// Absolute MSF address
|
||||
buf[7] = U8_to_BCD(ma);
|
||||
buf[8] = U8_to_BCD(sa);
|
||||
buf[9] = U8_to_BCD(fa);
|
||||
|
||||
subq_generate_checksum(buf);
|
||||
subq_generate_checksum(buf);
|
||||
|
||||
for(int i = 0; i < 96; i++)
|
||||
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
|
||||
for(int i = 0; i < 96; i++)
|
||||
SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
|
||||
}
|
||||
|
||||
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf)
|
||||
{
|
||||
memset(out_buf, 0, 2352 + 96);
|
||||
subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
|
||||
memset(out_buf, 0, 2352 + 96);
|
||||
subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
|
||||
|
||||
if((toc.tracks[toc.last_track].control | toc.tracks[100].control) & 0x4)
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
default:
|
||||
encode_mode0_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
if((toc.tracks[toc.last_track].control | toc.tracks[100].control) & 0x4)
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
default:
|
||||
encode_mode0_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
encode_mode1_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
case 0x01:
|
||||
encode_mode1_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
out_buf[18] = 0x20;
|
||||
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 0x02:
|
||||
out_buf[18] = 0x20;
|
||||
encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output)
|
||||
{
|
||||
assert(subq_check_checksum(subq_input));
|
||||
|
||||
|
||||
subq_generate_checksum(subq_output);
|
||||
}
|
||||
#endif
|
||||
|
||||
void scrambleize_data_sector(uint8 *sector_data)
|
||||
{
|
||||
for(unsigned i = 12; i < 2352; i++)
|
||||
sector_data[i] ^= scramble_table[i - 12];
|
||||
}
|
||||
|
||||
for(unsigned i = 12; i < 2352; i++)
|
||||
sector_data[i] ^= scramble_table[i - 12];
|
||||
}
|
||||
|
||||
void MDFN_strtoupper(char *str)
|
||||
{
|
||||
for(size_t x = 0; str[x]; x++)
|
||||
{
|
||||
if(str[x] >= 'a' && str[x] <= 'z')
|
||||
{
|
||||
str[x] = str[x] - 'a' + 'A';
|
||||
}
|
||||
}
|
||||
for(size_t x = 0; str[x]; x++)
|
||||
{
|
||||
if(str[x] >= 'a' && str[x] <= 'z')
|
||||
str[x] = str[x] - 'a' + 'A';
|
||||
}
|
||||
}
|
||||
|
||||
void MDFN_strtoupper(std::string &str)
|
||||
@ -339,8 +316,6 @@ void MDFN_strtoupper(std::string &str)
|
||||
for(size_t x = 0; x < len; x++)
|
||||
{
|
||||
if(str[x] >= 'a' && str[x] <= 'z')
|
||||
{
|
||||
str[x] = str[x] - 'a' + 'A';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,227 +1,224 @@
|
||||
#ifndef __MDFN_CDROM_CDUTILITY_H
|
||||
#define __MDFN_CDROM_CDUTILITY_H
|
||||
|
||||
namespace CDUtility
|
||||
// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
|
||||
// It will also be called automatically if needed for the first time a function in this namespace that requires
|
||||
// the initialization function to be called is called, for potential
|
||||
// usage in constructors of statically-declared objects.
|
||||
void CDUtility_Init(void);
|
||||
|
||||
// Quick definitions here:
|
||||
//
|
||||
// ABA - Absolute block address, synonymous to absolute MSF
|
||||
// aba = (m_a * 60 * 75) + (s_a * 75) + f_a
|
||||
//
|
||||
// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
|
||||
// lba = aba - 150
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
|
||||
// It will also be called automatically if needed for the first time a function in this namespace that requires
|
||||
// the initialization function to be called is called, for potential
|
||||
// usage in constructors of statically-declared objects.
|
||||
void CDUtility_Init(void);
|
||||
|
||||
// Quick definitions here:
|
||||
//
|
||||
// ABA - Absolute block address, synonymous to absolute MSF
|
||||
// aba = (m_a * 60 * 75) + (s_a * 75) + f_a
|
||||
//
|
||||
// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
|
||||
// lba = aba - 150
|
||||
ADR_NOQINFO = 0x00,
|
||||
ADR_CURPOS = 0x01,
|
||||
ADR_MCN = 0x02,
|
||||
ADR_ISRC = 0x03
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
ADR_NOQINFO = 0x00,
|
||||
ADR_CURPOS = 0x01,
|
||||
ADR_MCN = 0x02,
|
||||
ADR_ISRC = 0x03
|
||||
};
|
||||
struct TOC_Track
|
||||
{
|
||||
uint8 adr;
|
||||
uint8 control;
|
||||
uint32 lba;
|
||||
};
|
||||
|
||||
// SubQ control field flags.
|
||||
enum
|
||||
{
|
||||
SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
|
||||
SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
|
||||
SUBQ_CTRLF_DATA = 0x04, // Data track.
|
||||
SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.
|
||||
};
|
||||
|
||||
struct TOC_Track
|
||||
{
|
||||
uint8 adr;
|
||||
uint8 control;
|
||||
uint32 lba;
|
||||
};
|
||||
enum
|
||||
{
|
||||
DISC_TYPE_CDDA_OR_M1 = 0x00,
|
||||
DISC_TYPE_CD_I = 0x10,
|
||||
DISC_TYPE_CD_XA = 0x20
|
||||
};
|
||||
|
||||
// SubQ control field flags.
|
||||
enum
|
||||
{
|
||||
SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
|
||||
SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
|
||||
SUBQ_CTRLF_DATA = 0x04, // Data track.
|
||||
SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DISC_TYPE_CDDA_OR_M1 = 0x00,
|
||||
DISC_TYPE_CD_I = 0x10,
|
||||
DISC_TYPE_CD_XA = 0x20
|
||||
};
|
||||
|
||||
struct TOC
|
||||
{
|
||||
INLINE TOC()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
INLINE void Clear(void)
|
||||
{
|
||||
first_track = last_track = 0;
|
||||
disc_type = 0;
|
||||
|
||||
memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
|
||||
}
|
||||
|
||||
INLINE int FindTrackByLBA(uint32 LBA)
|
||||
{
|
||||
for(int32 track = first_track; track <= (last_track + 1); track++)
|
||||
struct TOC
|
||||
{
|
||||
INLINE TOC()
|
||||
{
|
||||
if(track == (last_track + 1))
|
||||
{
|
||||
if(LBA < tracks[100].lba)
|
||||
return(track - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(LBA < tracks[track].lba)
|
||||
return(track - 1);
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint8 first_track;
|
||||
uint8 last_track;
|
||||
uint8 disc_type;
|
||||
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
|
||||
// Also, for convenience, tracks[last_track + 1] will always refer
|
||||
// to the leadout track(even if last_track < 99, IE the leadout track details are duplicated).
|
||||
};
|
||||
INLINE void Clear(void)
|
||||
{
|
||||
first_track = last_track = 0;
|
||||
disc_type = 0;
|
||||
|
||||
//
|
||||
// Address conversion functions.
|
||||
//
|
||||
static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)
|
||||
{
|
||||
return(f_a + 75 * s_a + 75 * 60 * m_a);
|
||||
}
|
||||
memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.
|
||||
}
|
||||
|
||||
static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
*m_a = aba / 75 / 60;
|
||||
*s_a = (aba - *m_a * 75 * 60) / 75;
|
||||
*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
|
||||
}
|
||||
INLINE int FindTrackByLBA(uint32 LBA)
|
||||
{
|
||||
for(int32 track = first_track; track <= (last_track + 1); track++)
|
||||
{
|
||||
if(track == (last_track + 1))
|
||||
{
|
||||
if(LBA < tracks[100].lba)
|
||||
return(track - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(LBA < tracks[track].lba)
|
||||
return(track - 1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static INLINE int32 ABA_to_LBA(uint32 aba)
|
||||
{
|
||||
return(aba - 150);
|
||||
}
|
||||
uint8 first_track;
|
||||
uint8 last_track;
|
||||
uint8 disc_type;
|
||||
TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.
|
||||
// Also, for convenience, tracks[last_track + 1] will always refer
|
||||
// to the leadout track(even if last_track < 99, IE the leadout track details are duplicated).
|
||||
};
|
||||
|
||||
static INLINE uint32 LBA_to_ABA(int32 lba)
|
||||
{
|
||||
return(lba + 150);
|
||||
}
|
||||
|
||||
static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)
|
||||
{
|
||||
return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
|
||||
}
|
||||
|
||||
static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
|
||||
}
|
||||
|
||||
//
|
||||
// BCD conversion functions
|
||||
//
|
||||
static INLINE bool BCD_is_valid(uint8 bcd_number)
|
||||
{
|
||||
if((bcd_number & 0xF0) >= 0xA0)
|
||||
return(false);
|
||||
|
||||
if((bcd_number & 0x0F) >= 0x0A)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
static INLINE uint8 BCD_to_U8(uint8 bcd_number)
|
||||
{
|
||||
return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
|
||||
}
|
||||
|
||||
static INLINE uint8 U8_to_BCD(uint8 num)
|
||||
{
|
||||
return( ((num / 10) << 4) + (num % 10) );
|
||||
}
|
||||
|
||||
// should always perform the conversion, even if the bcd number is invalid.
|
||||
static INLINE bool BCD_to_U8_check(uint8 bcd_number, uint8 *out_number)
|
||||
{
|
||||
*out_number = BCD_to_U8(bcd_number);
|
||||
|
||||
if(!BCD_is_valid(bcd_number))
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
//
|
||||
// Sector data encoding functions(to full 2352 bytes raw sector).
|
||||
//
|
||||
// sector_data must be able to contain at least 2352 bytes.
|
||||
void encode_mode0_sector(uint32 aba, uint8 *sector_data);
|
||||
void encode_mode1_sector(uint32 aba, uint8 *sector_data); // 2048 bytes of user data at offset 16
|
||||
void encode_mode2_sector(uint32 aba, uint8 *sector_data); // 2336 bytes of user data at offset 16
|
||||
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data); // 2048+8 bytes of user data at offset 16
|
||||
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data); // 2324+8 bytes of user data at offset 16
|
||||
|
||||
|
||||
// out_buf must be able to contain 2352+96 bytes.
|
||||
// "mode" is only used if(toc.tracks[100].control & 0x4)
|
||||
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
|
||||
|
||||
//
|
||||
// User data error detection and correction
|
||||
//
|
||||
|
||||
// Check EDC of a mode 1 or mode 2 form 1 sector.
|
||||
// Returns "true" if checksum is ok(matches).
|
||||
// Returns "false" if checksum mismatch.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_check(const uint8 *sector_data, bool xa);
|
||||
|
||||
// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
|
||||
// Returns "true" if errors weren't detected, or they were corrected succesfully.
|
||||
// Returns "false" if errors couldn't be corrected.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);
|
||||
|
||||
//
|
||||
// Subchannel(Q in particular) functions
|
||||
//
|
||||
|
||||
// Returns false on checksum mismatch, true on match.
|
||||
bool subq_check_checksum(const uint8 *subq_buf);
|
||||
|
||||
// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
|
||||
// in subq_buf.
|
||||
void subq_generate_checksum(uint8 *subq_buf);
|
||||
|
||||
// Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
|
||||
void subq_deinterleave(const uint8 *subpw_buf, uint8 *subq_buf);
|
||||
|
||||
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
|
||||
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf);
|
||||
|
||||
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
|
||||
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf);
|
||||
|
||||
// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
|
||||
// Only valid for ADR_CURPOS.
|
||||
// subq_input must pass subq_check_checksum().
|
||||
// TODO
|
||||
//void subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output);
|
||||
|
||||
// (De)Scrambles data sector.
|
||||
void scrambleize_data_sector(uint8 *sector_data);
|
||||
//
|
||||
// Address conversion functions.
|
||||
//
|
||||
static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)
|
||||
{
|
||||
return(f_a + 75 * s_a + 75 * 60 * m_a);
|
||||
}
|
||||
|
||||
static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
*m_a = aba / 75 / 60;
|
||||
*s_a = (aba - *m_a * 75 * 60) / 75;
|
||||
*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
|
||||
}
|
||||
|
||||
static INLINE int32 ABA_to_LBA(uint32 aba)
|
||||
{
|
||||
return(aba - 150);
|
||||
}
|
||||
|
||||
static INLINE uint32 LBA_to_ABA(int32 lba)
|
||||
{
|
||||
return(lba + 150);
|
||||
}
|
||||
|
||||
static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)
|
||||
{
|
||||
return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
|
||||
}
|
||||
|
||||
static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)
|
||||
{
|
||||
ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
|
||||
}
|
||||
|
||||
//
|
||||
// BCD conversion functions
|
||||
//
|
||||
static INLINE bool BCD_is_valid(uint8 bcd_number)
|
||||
{
|
||||
if((bcd_number & 0xF0) >= 0xA0)
|
||||
return(false);
|
||||
|
||||
if((bcd_number & 0x0F) >= 0x0A)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
static INLINE uint8 BCD_to_U8(uint8 bcd_number)
|
||||
{
|
||||
return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
|
||||
}
|
||||
|
||||
static INLINE uint8 U8_to_BCD(uint8 num)
|
||||
{
|
||||
return( ((num / 10) << 4) + (num % 10) );
|
||||
}
|
||||
|
||||
// should always perform the conversion, even if the bcd number is invalid.
|
||||
static INLINE bool BCD_to_U8_check(uint8 bcd_number, uint8 *out_number)
|
||||
{
|
||||
*out_number = BCD_to_U8(bcd_number);
|
||||
|
||||
if(!BCD_is_valid(bcd_number))
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
//
|
||||
// Sector data encoding functions(to full 2352 bytes raw sector).
|
||||
//
|
||||
// sector_data must be able to contain at least 2352 bytes.
|
||||
void encode_mode0_sector(uint32 aba, uint8 *sector_data);
|
||||
void encode_mode1_sector(uint32 aba, uint8 *sector_data); // 2048 bytes of user data at offset 16
|
||||
void encode_mode2_sector(uint32 aba, uint8 *sector_data); // 2336 bytes of user data at offset 16
|
||||
void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data); // 2048+8 bytes of user data at offset 16
|
||||
void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data); // 2324+8 bytes of user data at offset 16
|
||||
|
||||
|
||||
// out_buf must be able to contain 2352+96 bytes.
|
||||
// "mode" is only used if(toc.tracks[100].control & 0x4)
|
||||
void synth_leadout_sector_lba(const uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);
|
||||
|
||||
//
|
||||
// User data error detection and correction
|
||||
//
|
||||
|
||||
// Check EDC of a mode 1 or mode 2 form 1 sector.
|
||||
// Returns "true" if checksum is ok(matches).
|
||||
// Returns "false" if checksum mismatch.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_check(const uint8 *sector_data, bool xa);
|
||||
|
||||
// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
|
||||
// Returns "true" if errors weren't detected, or they were corrected succesfully.
|
||||
// Returns "false" if errors couldn't be corrected.
|
||||
// sector_data should contain 2352 bytes of raw sector data.
|
||||
bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);
|
||||
|
||||
//
|
||||
// Subchannel(Q in particular) functions
|
||||
//
|
||||
|
||||
// Returns false on checksum mismatch, true on match.
|
||||
bool subq_check_checksum(const uint8 *subq_buf);
|
||||
|
||||
// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
|
||||
// in subq_buf.
|
||||
void subq_generate_checksum(uint8 *subq_buf);
|
||||
|
||||
// Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
|
||||
void subq_deinterleave(const uint8 *subpw_buf, uint8 *subq_buf);
|
||||
|
||||
// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
|
||||
void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf);
|
||||
|
||||
// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
|
||||
void subpw_interleave(const uint8 *in_buf, uint8 *out_buf);
|
||||
|
||||
// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
|
||||
// Only valid for ADR_CURPOS.
|
||||
// subq_input must pass subq_check_checksum().
|
||||
// TODO
|
||||
//void subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output);
|
||||
|
||||
// (De)Scrambles data sector.
|
||||
void scrambleize_data_sector(uint8 *sector_data);
|
||||
|
||||
void MDFN_strtoupper(std::string &str);
|
||||
void MDFN_strtoupper(char *str);
|
||||
|
||||
|
@ -27,8 +27,6 @@
|
||||
|
||||
extern retro_log_printf_t log_cb;
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
enum
|
||||
{
|
||||
// Status/Error messages
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#include <queue>
|
||||
|
||||
typedef CDUtility::TOC CD_TOC;
|
||||
typedef TOC CD_TOC;
|
||||
|
||||
class CDIF
|
||||
{
|
||||
@ -32,7 +32,7 @@ class CDIF
|
||||
CDIF();
|
||||
virtual ~CDIF();
|
||||
|
||||
inline void ReadTOC(CDUtility::TOC *read_target)
|
||||
inline void ReadTOC(TOC *read_target)
|
||||
{
|
||||
*read_target = disc_toc;
|
||||
}
|
||||
@ -61,7 +61,7 @@ class CDIF
|
||||
protected:
|
||||
bool UnrecoverableError;
|
||||
bool is_phys_cache;
|
||||
CDUtility::TOC disc_toc;
|
||||
TOC disc_toc;
|
||||
bool DiscEjected;
|
||||
};
|
||||
|
||||
|
@ -33,13 +33,13 @@
|
||||
|
||||
static inline int mod_fieldmax(int x)
|
||||
{
|
||||
while (x >= GF_FIELDMAX)
|
||||
{
|
||||
x -= GF_FIELDMAX;
|
||||
x = (x >> GF_SYMBOLSIZE) + (x & GF_FIELDMAX);
|
||||
}
|
||||
while (x >= GF_FIELDMAX)
|
||||
{
|
||||
x -= GF_FIELDMAX;
|
||||
x = (x >> GF_SYMBOLSIZE) + (x & GF_FIELDMAX);
|
||||
}
|
||||
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -36,11 +36,10 @@
|
||||
|
||||
/* Initialize the Galois field tables */
|
||||
|
||||
|
||||
GaloisTables* CreateGaloisTables(int32 gf_generator)
|
||||
{
|
||||
GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));
|
||||
{
|
||||
int32 b,log;
|
||||
GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));
|
||||
|
||||
/* Allocate the tables.
|
||||
The encoder uses a special version of alpha_to which has the mod_fieldmax()
|
||||
@ -51,7 +50,7 @@ GaloisTables* CreateGaloisTables(int32 gf_generator)
|
||||
gt->indexOf = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
|
||||
gt->alphaTo = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));
|
||||
gt->encAlphaTo = (int32 *)calloc(2*GF_FIELDSIZE, sizeof(int32));
|
||||
|
||||
|
||||
/* create the log/ilog values */
|
||||
|
||||
for(b=1, log=0; log<GF_FIELDMAX; log++)
|
||||
@ -59,13 +58,13 @@ GaloisTables* CreateGaloisTables(int32 gf_generator)
|
||||
gt->alphaTo[log] = b;
|
||||
b = b << 1;
|
||||
if(b & GF_FIELDSIZE)
|
||||
b = b ^ gf_generator;
|
||||
b = b ^ gf_generator;
|
||||
}
|
||||
|
||||
if(b!=1)
|
||||
{
|
||||
printf("Failed to create the Galois field log tables!\n");
|
||||
exit(1);
|
||||
printf("Failed to create the Galois field log tables!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* we're even closed using infinity (makes things easier) */
|
||||
@ -74,18 +73,21 @@ GaloisTables* CreateGaloisTables(int32 gf_generator)
|
||||
gt->alphaTo[GF_ALPHA0] = 0; /* and the other way around */
|
||||
|
||||
for(b=0; b<2*GF_FIELDSIZE; b++)
|
||||
gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
|
||||
gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
|
||||
|
||||
return gt;
|
||||
}
|
||||
|
||||
void FreeGaloisTables(GaloisTables *gt)
|
||||
{
|
||||
if(gt->indexOf) free(gt->indexOf);
|
||||
if(gt->alphaTo) free(gt->alphaTo);
|
||||
if(gt->encAlphaTo) free(gt->encAlphaTo);
|
||||
if(gt->indexOf)
|
||||
free(gt->indexOf);
|
||||
if(gt->alphaTo)
|
||||
free(gt->alphaTo);
|
||||
if(gt->encAlphaTo)
|
||||
free(gt->encAlphaTo);
|
||||
|
||||
free(gt);
|
||||
free(gt);
|
||||
}
|
||||
|
||||
/***
|
||||
@ -94,10 +96,11 @@ void FreeGaloisTables(GaloisTables *gt)
|
||||
*/
|
||||
|
||||
ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
|
||||
int32 first_consecutive_root,
|
||||
int32 prim_elem,
|
||||
int nroots_in)
|
||||
{ ReedSolomonTables *rt = (ReedSolomonTables *)calloc(1, sizeof(ReedSolomonTables));
|
||||
int32 first_consecutive_root,
|
||||
int32 prim_elem,
|
||||
int nroots_in)
|
||||
{
|
||||
ReedSolomonTables *rt = (ReedSolomonTables *)calloc(1, sizeof(ReedSolomonTables));
|
||||
int32 i,j,root;
|
||||
|
||||
rt->gfTables = gt;
|
||||
@ -115,42 +118,31 @@ ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
|
||||
for(i=0, root=first_consecutive_root*prim_elem; i<rt->nroots; i++, root+=prim_elem)
|
||||
{ rt->gpoly[i+1] = 1;
|
||||
|
||||
/* Multiply gpoly by alpha**(root+x) */
|
||||
/* Multiply gpoly by alpha**(root+x) */
|
||||
|
||||
for(j=i; j>0; j--)
|
||||
{
|
||||
if(rt->gpoly[j] != 0)
|
||||
rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
|
||||
else
|
||||
rt->gpoly[j] = rt->gpoly[j-1];
|
||||
}
|
||||
for(j=i; j>0; j--)
|
||||
{
|
||||
if(rt->gpoly[j] != 0)
|
||||
rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
|
||||
else
|
||||
rt->gpoly[j] = rt->gpoly[j-1];
|
||||
}
|
||||
|
||||
rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
|
||||
rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
|
||||
}
|
||||
|
||||
/* Store the polynomials index for faster encoding */
|
||||
|
||||
for(i=0; i<=rt->nroots; i++)
|
||||
rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
|
||||
|
||||
#if 0
|
||||
/* for the precalculated unrolled loops only */
|
||||
|
||||
for(i=gt->nroots-1; i>0; i--)
|
||||
PrintCLI(
|
||||
" par_idx[((++spk)&%d)] ^= enc_alpha_to[feedback + %3d];\n",
|
||||
nroots-1,gt->gpoly[i]);
|
||||
|
||||
PrintCLI(" par_idx[sp] = enc_alpha_to[feedback + %3d];\n",
|
||||
gt->gpoly[0]);
|
||||
#endif
|
||||
rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
void FreeReedSolomonTables(ReedSolomonTables *rt)
|
||||
{
|
||||
if(rt->gpoly) free(rt->gpoly);
|
||||
if(rt->gpoly)
|
||||
free(rt->gpoly);
|
||||
|
||||
free(rt);
|
||||
free(rt);
|
||||
}
|
||||
|
@ -243,18 +243,18 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
int corrected = 0;
|
||||
int i,j,k;
|
||||
int r,el;
|
||||
|
||||
|
||||
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
|
||||
|
||||
for(i=0; i<NROOTS; i++)
|
||||
syndrome[i] = data[0];
|
||||
syndrome[i] = data[0];
|
||||
|
||||
for(j=1; j<shortened_size; j++)
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
|
||||
/*** Convert syndrome to index form, check for nonzero condition. */
|
||||
|
||||
@ -267,7 +267,7 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
/*** If the syndrome is zero, everything is fine. */
|
||||
|
||||
if(!syn_error)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
/*** Initialize lambda to be the erasure locator polynomial */
|
||||
|
||||
@ -278,7 +278,7 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
erasure_list[1] += padding;
|
||||
|
||||
if(erasure_count > 2) /* sanity check */
|
||||
erasure_count = 0;
|
||||
erasure_count = 0;
|
||||
|
||||
if(erasure_count > 0)
|
||||
{ lambda[1] = gt->alphaTo[mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[0]))];
|
||||
@ -287,17 +287,17 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
{ int u = mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[i]));
|
||||
|
||||
for(j=i+1; j>0; j--)
|
||||
{ int tmp = gt->indexOf[lambda[j-1]];
|
||||
|
||||
{ int tmp = gt->indexOf[lambda[j-1]];
|
||||
|
||||
if(tmp != GF_ALPHA0)
|
||||
lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
|
||||
}
|
||||
lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<NROOTS+1; i++)
|
||||
b[i] = gt->indexOf[lambda[i]];
|
||||
|
||||
b[i] = gt->indexOf[lambda[i]];
|
||||
|
||||
/*** Berlekamp-Massey algorithm to determine error+erasure locator polynomial */
|
||||
|
||||
r = erasure_count; /* r is the step number */
|
||||
@ -309,42 +309,42 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
{ int discr_r = 0;
|
||||
|
||||
for(i=0; i<r; i++)
|
||||
if((lambda[i] != 0) && (syndrome[r-i-1] != GF_ALPHA0))
|
||||
discr_r ^= gt->alphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
|
||||
if((lambda[i] != 0) && (syndrome[r-i-1] != GF_ALPHA0))
|
||||
discr_r ^= gt->alphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
|
||||
|
||||
discr_r = gt->indexOf[discr_r];
|
||||
|
||||
if(discr_r == GF_ALPHA0)
|
||||
{ /* B(x) = x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
else
|
||||
{ int t[NROOTS+1];
|
||||
|
||||
/* T(x) = lambda(x) - discr_r*x*b(x) */
|
||||
t[0] = lambda[0];
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(b[i] != GF_ALPHA0)
|
||||
t[i+1] = lambda[i+1] ^ gt->alphaTo[mod_fieldmax(discr_r + b[i])];
|
||||
else t[i+1] = lambda[i+1];
|
||||
}
|
||||
/* T(x) = lambda(x) - discr_r*x*b(x) */
|
||||
t[0] = lambda[0];
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(b[i] != GF_ALPHA0)
|
||||
t[i+1] = lambda[i+1] ^ gt->alphaTo[mod_fieldmax(discr_r + b[i])];
|
||||
else t[i+1] = lambda[i+1];
|
||||
}
|
||||
|
||||
if(2*el <= r+erasure_count-1)
|
||||
{ el = r + erasure_count - el;
|
||||
if(2*el <= r+erasure_count-1)
|
||||
{ el = r + erasure_count - el;
|
||||
|
||||
/* B(x) <-- inv(discr_r) * lambda(x) */
|
||||
for(i=0; i<=NROOTS; i++)
|
||||
b[i] = (lambda[i] == 0) ? GF_ALPHA0
|
||||
: mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
|
||||
}
|
||||
else
|
||||
{ /* 2 lines below: B(x) <-- x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
/* B(x) <-- inv(discr_r) * lambda(x) */
|
||||
for(i=0; i<=NROOTS; i++)
|
||||
b[i] = (lambda[i] == 0) ? GF_ALPHA0
|
||||
: mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
|
||||
}
|
||||
else
|
||||
{ /* 2 lines below: B(x) <-- x*B(x) */
|
||||
memmove(b+1, b, NROOTS*sizeof(b[0]));
|
||||
b[0] = GF_ALPHA0;
|
||||
}
|
||||
|
||||
memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
|
||||
memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,7 +354,7 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
for(i=0; i<NROOTS+1; i++)
|
||||
{ lambda[i] = gt->indexOf[lambda[i]];
|
||||
if(lambda[i] != GF_ALPHA0)
|
||||
deg_lambda = i;
|
||||
deg_lambda = i;
|
||||
}
|
||||
|
||||
/*** Find roots of the error+erasure locator polynomial by Chien search */
|
||||
@ -367,9 +367,9 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
|
||||
for(j=deg_lambda; j>0; j--)
|
||||
{ if(reg[j] != GF_ALPHA0)
|
||||
{ reg[j] = mod_fieldmax(reg[j] + j);
|
||||
q ^= gt->alphaTo[reg[j]];
|
||||
}
|
||||
{ reg[j] = mod_fieldmax(reg[j] + j);
|
||||
q ^= gt->alphaTo[reg[j]];
|
||||
}
|
||||
}
|
||||
|
||||
if(q != 0) continue; /* Not a root */
|
||||
@ -401,7 +401,7 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
|
||||
for(j=i; j>=0; j--)
|
||||
{ if((syndrome[i - j] != GF_ALPHA0) && (lambda[j] != GF_ALPHA0))
|
||||
tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
|
||||
tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
|
||||
}
|
||||
|
||||
omega[i] = gt->indexOf[tmp];
|
||||
@ -420,59 +420,54 @@ int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
|
||||
|
||||
for(i=deg_omega; i>=0; i--)
|
||||
{ if(omega[i] != GF_ALPHA0)
|
||||
num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
|
||||
num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
|
||||
}
|
||||
|
||||
num2 = gt->alphaTo[mod_fieldmax(root[j] * (LEC_FIRST_ROOT - 1) + GF_FIELDMAX)];
|
||||
den = 0;
|
||||
|
||||
|
||||
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
|
||||
|
||||
for(i=MIN(deg_lambda, NROOTS-1) & ~1; i>=0; i-=2)
|
||||
{ if(lambda[i+1] != GF_ALPHA0)
|
||||
den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
|
||||
den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
|
||||
}
|
||||
|
||||
/* Apply error to data */
|
||||
|
||||
if(num1 != 0 && location >= padding)
|
||||
{
|
||||
corrected++;
|
||||
data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
|
||||
+ GF_FIELDMAX - gt->indexOf[den])];
|
||||
corrected++;
|
||||
data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
|
||||
+ GF_FIELDMAX - gt->indexOf[den])];
|
||||
|
||||
/* If no erasures were given, at most one error was corrected.
|
||||
Return its position in erasure_list[0]. */
|
||||
/* If no erasures were given, at most one error was corrected.
|
||||
Return its position in erasure_list[0]. */
|
||||
|
||||
if(!erasure_count)
|
||||
erasure_list[0] = location-padding;
|
||||
if(!erasure_count)
|
||||
erasure_list[0] = location-padding;
|
||||
}
|
||||
#if 1
|
||||
else return -3;
|
||||
#endif
|
||||
else
|
||||
return -3;
|
||||
}
|
||||
|
||||
/*** Form the syndromes: Evaluate data(x) at roots of g(x) */
|
||||
|
||||
for(i=0; i<NROOTS; i++)
|
||||
syndrome[i] = data[0];
|
||||
syndrome[i] = data[0];
|
||||
|
||||
for(j=1; j<shortened_size; j++)
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
}
|
||||
for(i=0; i<NROOTS; i++)
|
||||
{ if(syndrome[i] == 0)
|
||||
syndrome[i] = data[j];
|
||||
else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
|
||||
+ (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
|
||||
}
|
||||
|
||||
/*** Convert syndrome to index form, check for nonzero condition. */
|
||||
#if 1
|
||||
for(i=0; i<NROOTS; i++)
|
||||
if(syndrome[i])
|
||||
return -2;
|
||||
#endif
|
||||
if(syndrome[i])
|
||||
return -2;
|
||||
|
||||
return corrected;
|
||||
}
|
||||
|
||||
|
||||
|
@ -575,117 +575,25 @@ void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector)
|
||||
*/
|
||||
void lec_scramble(u_int8_t *sector)
|
||||
{
|
||||
u_int16_t i;
|
||||
const u_int8_t *stable = SCRAMBLE_TABLE;
|
||||
u_int8_t *p = sector;
|
||||
u_int8_t tmp;
|
||||
u_int16_t i;
|
||||
const u_int8_t *stable = SCRAMBLE_TABLE;
|
||||
u_int8_t *p = sector;
|
||||
u_int8_t tmp;
|
||||
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
/* just swap bytes of sector sync */
|
||||
tmp = *p;
|
||||
*p = *(p + 1);
|
||||
p++;
|
||||
*p++ = tmp;
|
||||
}
|
||||
for (;i < (2352 / 2); i++) {
|
||||
}
|
||||
for (;i < (2352 / 2); i++) {
|
||||
/* scramble and swap bytes */
|
||||
tmp = *p ^ *stable++;
|
||||
*p = *(p + 1) ^ *stable++;
|
||||
p++;
|
||||
*p++ = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *infile;
|
||||
char *outfile;
|
||||
int fd_in, fd_out;
|
||||
u_int8_t buffer1[2352];
|
||||
u_int8_t buffer2[2352];
|
||||
u_int32_t lba;
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < 2048; i++)
|
||||
buffer1[i + 16] = 234;
|
||||
|
||||
lba = 150;
|
||||
|
||||
for (i = 0; i < 100000; i++) {
|
||||
lec_encode_mode1_sector(lba, buffer1);
|
||||
lec_scramble(buffer2);
|
||||
lba++;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (argc != 3)
|
||||
return 1;
|
||||
|
||||
infile = argv[1];
|
||||
outfile = argv[2];
|
||||
|
||||
|
||||
if ((fd_in = open(infile, O_RDONLY)) < 0) {
|
||||
perror("Cannot open input file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd_out = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
|
||||
perror("Cannot open output file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lba = 150;
|
||||
|
||||
do {
|
||||
if (read(fd_in, buffer1, 2352) != 2352)
|
||||
break;
|
||||
|
||||
switch (*(buffer1 + 12 + 3)) {
|
||||
case 1:
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2048);
|
||||
|
||||
lec_encode_mode1_sector(lba, buffer2);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ((*(buffer1 + 12 + 4 + 2) & 0x20) != 0) {
|
||||
/* form 2 sector */
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2324 + 8);
|
||||
lec_encode_mode2_form2_sector(lba, buffer2);
|
||||
}
|
||||
else {
|
||||
/* form 1 sector */
|
||||
memcpy(buffer2 + 16, buffer1 + 16, 2048 + 8);
|
||||
lec_encode_mode2_form1_sector(lba, buffer2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(buffer1, buffer2, 2352) != 0) {
|
||||
printf("Verify error at lba %ld\n", lba);
|
||||
}
|
||||
|
||||
lec_scramble(buffer2);
|
||||
write(fd_out, buffer2, 2352);
|
||||
|
||||
lba++;
|
||||
} while (1);
|
||||
|
||||
close(fd_in);
|
||||
close(fd_out);
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -49,26 +49,24 @@ void Kill_LEC_Correct(void)
|
||||
|
||||
int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
|
||||
{
|
||||
unsigned int expected_crc, real_crc;
|
||||
unsigned int crc_base = xa_mode ? 2072 : 2064;
|
||||
unsigned int expected_crc, real_crc;
|
||||
unsigned int crc_base = xa_mode ? 2072 : 2064;
|
||||
|
||||
expected_crc = cd_frame[crc_base + 0] << 0;
|
||||
expected_crc |= cd_frame[crc_base + 1] << 8;
|
||||
expected_crc |= cd_frame[crc_base + 2] << 16;
|
||||
expected_crc |= cd_frame[crc_base + 3] << 24;
|
||||
expected_crc = cd_frame[crc_base + 0] << 0;
|
||||
expected_crc |= cd_frame[crc_base + 1] << 8;
|
||||
expected_crc |= cd_frame[crc_base + 2] << 16;
|
||||
expected_crc |= cd_frame[crc_base + 3] << 24;
|
||||
|
||||
if(xa_mode)
|
||||
real_crc = EDCCrc32(cd_frame+16, 2056);
|
||||
else
|
||||
real_crc = EDCCrc32(cd_frame, 2064);
|
||||
if(xa_mode)
|
||||
real_crc = EDCCrc32(cd_frame+16, 2056);
|
||||
else
|
||||
real_crc = EDCCrc32(cd_frame, 2064);
|
||||
|
||||
if(expected_crc == real_crc)
|
||||
return(1);
|
||||
else
|
||||
{
|
||||
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
|
||||
return(0);
|
||||
}
|
||||
if(expected_crc == real_crc)
|
||||
return(1);
|
||||
|
||||
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/***
|
||||
@ -101,31 +99,34 @@ static int simple_lec(unsigned char *frame)
|
||||
/* Perform Q-Parity error correction */
|
||||
|
||||
for(q=0; q<N_Q_VECTORS; q++)
|
||||
{ int err;
|
||||
{
|
||||
int err;
|
||||
|
||||
/* We have no erasure information for Q vectors */
|
||||
|
||||
GetQVector(frame, q_vector, q);
|
||||
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
|
||||
GetQVector(frame, q_vector, q);
|
||||
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
|
||||
|
||||
/* See what we've got */
|
||||
/* See what we've got */
|
||||
|
||||
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
|
||||
{ q_failures++;
|
||||
FillQVector(byte_state, 1, q);
|
||||
}
|
||||
else /* Correctable */
|
||||
{ if(err == 1 || err == 2) /* Store back corrected vector */
|
||||
{ SetQVector(frame, q_vector, q);
|
||||
q_corrected++;
|
||||
}
|
||||
}
|
||||
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
|
||||
{ q_failures++;
|
||||
FillQVector(byte_state, 1, q);
|
||||
}
|
||||
else /* Correctable */
|
||||
{
|
||||
if(err == 1 || err == 2) /* Store back corrected vector */
|
||||
{
|
||||
SetQVector(frame, q_vector, q);
|
||||
q_corrected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform P-Parity error correction */
|
||||
|
||||
for(p=0; p<N_P_VECTORS; p++)
|
||||
{ int err,i;
|
||||
{
|
||||
int err,i;
|
||||
|
||||
/* Try error correction without erasure information */
|
||||
|
||||
@ -133,41 +134,41 @@ static int simple_lec(unsigned char *frame)
|
||||
err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
|
||||
|
||||
/* If unsuccessful, try again using erasures.
|
||||
Erasure information is uncertain, so try this last. */
|
||||
Erasure information is uncertain, so try this last. */
|
||||
|
||||
if(err < 0 || err > 2)
|
||||
{ GetPVector(byte_state, p_state, p);
|
||||
erasure_count = 0;
|
||||
{
|
||||
GetPVector(byte_state, p_state, p);
|
||||
erasure_count = 0;
|
||||
|
||||
for(i=0; i<P_VECTOR_SIZE; i++)
|
||||
if(p_state[i])
|
||||
erasures[erasure_count++] = i;
|
||||
for(i=0; i<P_VECTOR_SIZE; i++)
|
||||
if(p_state[i])
|
||||
erasures[erasure_count++] = i;
|
||||
|
||||
if(erasure_count > 0 && erasure_count <= 2)
|
||||
{ GetPVector(frame, p_vector, p);
|
||||
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
|
||||
}
|
||||
if(erasure_count > 0 && erasure_count <= 2)
|
||||
{
|
||||
GetPVector(frame, p_vector, p);
|
||||
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
|
||||
}
|
||||
}
|
||||
|
||||
/* See what we've got */
|
||||
|
||||
if(err < 0) /* Uncorrectable. */
|
||||
{ p_failures++;
|
||||
}
|
||||
p_failures++;
|
||||
else /* Correctable. */
|
||||
{ if(err == 1 || err == 2) /* Store back corrected vector */
|
||||
{ SetPVector(frame, p_vector, p);
|
||||
p_corrected++;
|
||||
}
|
||||
{
|
||||
if(err == 1 || err == 2) /* Store back corrected vector */
|
||||
{ SetPVector(frame, p_vector, p);
|
||||
p_corrected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sum up */
|
||||
|
||||
if(q_failures || p_failures || q_corrected || p_corrected)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -178,26 +179,21 @@ static int simple_lec(unsigned char *frame)
|
||||
|
||||
int ValidateRawSector(unsigned char *frame, bool xaMode)
|
||||
{
|
||||
int lec_did_sth = FALSE;
|
||||
int lec_did_sth = FALSE;
|
||||
|
||||
/* Do simple L-EC.
|
||||
It seems that drives stop their internal L-EC as soon as the
|
||||
EDC is okay, so we may see uncorrected errors in the parity bytes.
|
||||
Since we are also interested in the user data only and doing the
|
||||
L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
|
||||
/* Do simple L-EC.
|
||||
It seems that drives stop their internal L-EC as soon as the
|
||||
EDC is okay, so we may see uncorrected errors in the parity bytes.
|
||||
Since we are also interested in the user data only and doing the
|
||||
L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
|
||||
|
||||
if(!CheckEDC(frame, xaMode))
|
||||
{
|
||||
lec_did_sth = simple_lec(frame);
|
||||
}
|
||||
/* Test internal sector checksum again */
|
||||
if(!CheckEDC(frame, xaMode))
|
||||
lec_did_sth = simple_lec(frame);
|
||||
/* Test internal sector checksum again */
|
||||
|
||||
if(!CheckEDC(frame, xaMode))
|
||||
{
|
||||
/* EDC failure in RAW sector */
|
||||
return FALSE;
|
||||
}
|
||||
if(!CheckEDC(frame, xaMode))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -52,8 +52,6 @@
|
||||
#include "cdc.h"
|
||||
#include "spu.h"
|
||||
|
||||
using namespace CDUtility;
|
||||
|
||||
PS_CDC::PS_CDC() : DMABuffer(4096)
|
||||
{
|
||||
IsPSXDisc = false;
|
||||
|
@ -181,7 +181,7 @@ class PS_CDC
|
||||
|
||||
int32_t lastts;
|
||||
|
||||
CDUtility::TOC toc;
|
||||
TOC toc;
|
||||
bool IsPSXDisc;
|
||||
uint8 DiscID[4];
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user