DiscIdentifier - Improved detection of PC-FX. Added detection of lots more systems.
This commit is contained in:
parent
1bd535c31f
commit
420aec7870
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
//disc type identification logic
|
//disc type identification logic
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
public enum DiscType
|
public enum DiscType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disc contains audio in track 1. Nothing more can readily be determined
|
/// Disc contains audio in track 1. This may be a PCFX or PCECD game, but if not it is assumed AudioDisc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
AudioDisc,
|
AudioDisc,
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
SegaSaturn,
|
SegaSaturn,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Its not clear whether we can ever have enough info to ID a turboCD disc (we're using hashes)
|
/// PC Engine CD
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TurboCD,
|
TurboCD,
|
||||||
|
|
||||||
|
@ -50,7 +51,47 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// By NEC.
|
/// By NEC.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
PCFX
|
PCFX,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// By Panasonic
|
||||||
|
/// </summary>
|
||||||
|
Panasonic3DO,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Philips
|
||||||
|
/// </summary>
|
||||||
|
CDi,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Nintendo Gamecube
|
||||||
|
/// </summary>
|
||||||
|
GameCube,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Nintendo Wii
|
||||||
|
/// </summary>
|
||||||
|
Wii,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SNK NeoGeo
|
||||||
|
/// </summary>
|
||||||
|
NeoGeoCD,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bandai Playdia
|
||||||
|
/// </summary>
|
||||||
|
Playdia,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Either CDTV or CD32 (I havent found a reliable way of distinguishing between them yet -asni)
|
||||||
|
/// </summary>
|
||||||
|
Amiga,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sega Dreamcast
|
||||||
|
/// </summary>
|
||||||
|
Dreamcast
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DiscIdentifier
|
public class DiscIdentifier
|
||||||
|
@ -76,24 +117,26 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DiscType DetectDiscType()
|
public DiscType DetectDiscType()
|
||||||
{
|
{
|
||||||
// not fully tested yet
|
// PCFX & TurboCD sometimes (if not alltimes) have audio on track 1 - run these before the AudioDisc detection (asni)
|
||||||
if (DetectPCFX())
|
if (DetectPCFX())
|
||||||
return DiscType.PCFX;
|
return DiscType.PCFX;
|
||||||
|
|
||||||
//check track 1's data type. if it's an audio track, further data-track testing is useless
|
if (DetectTurboCD())
|
||||||
//furthermore, it's probably senseless (no binary data there to read)
|
return DiscType.TurboCD;
|
||||||
//NOTE: PCE-CD detection goes through here (no good way to detect PCE cd)
|
|
||||||
if (!_disc.TOC.TOCItems[1].IsData)
|
//check track 1's data type. if it's an audio track, further data-track testing is useless
|
||||||
|
//furthermore, it's probably senseless (no binary data there to read)
|
||||||
|
if (!_disc.TOC.TOCItems[1].IsData)
|
||||||
return DiscType.AudioDisc;
|
return DiscType.AudioDisc;
|
||||||
|
|
||||||
// if (_dsr.ReadLBA_Mode(_disc.TOC.TOCItems[1].LBA) == 0)
|
// if (_dsr.ReadLBA_Mode(_disc.TOC.TOCItems[1].LBA) == 0)
|
||||||
// return DiscType.AudioDisc;
|
// return DiscType.AudioDisc;
|
||||||
|
|
||||||
// sega doesnt put anything identifying in the cdfs volume info. but its consistent about putting its own header here in sector 0
|
// sega doesnt put anything identifying in the cdfs volume info. but its consistent about putting its own header here in sector 0
|
||||||
|
//asni - this isn't strictly true - SystemIdentifier in volume descriptor has been observed on occasion (see below)
|
||||||
if (DetectSegaSaturn())
|
if (DetectSegaSaturn())
|
||||||
return DiscType.SegaSaturn;
|
return DiscType.SegaSaturn;
|
||||||
|
|
||||||
|
|
||||||
// not fully tested yet
|
// not fully tested yet
|
||||||
if (DetectMegaCD())
|
if (DetectMegaCD())
|
||||||
return DiscType.MegaCD;
|
return DiscType.MegaCD;
|
||||||
|
@ -102,31 +145,79 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
if (DetectPSX())
|
if (DetectPSX())
|
||||||
return DiscType.SonyPSX;
|
return DiscType.SonyPSX;
|
||||||
|
|
||||||
//we dont know how to detect TurboCD.
|
if (Detect3DO())
|
||||||
//an emulator frontend will likely just guess TurboCD if the disc is UnknownFormat
|
return DiscType.Panasonic3DO;
|
||||||
//(we can also have a gameDB!)
|
|
||||||
|
|
||||||
var discView = EDiscStreamView.DiscStreamView_Mode1_2048;
|
if (DetectCDi())
|
||||||
|
return DiscType.CDi;
|
||||||
|
|
||||||
|
if (DetectGameCube())
|
||||||
|
return DiscType.GameCube;
|
||||||
|
|
||||||
|
if (DetectWii())
|
||||||
|
return DiscType.Wii;
|
||||||
|
|
||||||
|
var discView = EDiscStreamView.DiscStreamView_Mode1_2048;
|
||||||
if (_disc.TOC.Session1Format == SessionFormat.Type20_CDXA)
|
if (_disc.TOC.Session1Format == SessionFormat.Type20_CDXA)
|
||||||
discView = EDiscStreamView.DiscStreamView_Mode2_Form1_2048;
|
discView = EDiscStreamView.DiscStreamView_Mode2_Form1_2048;
|
||||||
|
|
||||||
var iso = new ISOFile();
|
var iso = new ISOFile();
|
||||||
bool isIso = iso.Parse(new DiscStream(_disc, discView, 0));
|
bool isIso = iso.Parse(new DiscStream(_disc, discView, 0));
|
||||||
|
|
||||||
|
if (!isIso)
|
||||||
|
{
|
||||||
|
// its much quicker to detect dreamcast from ISO data. Only do this if ISO is not detected
|
||||||
|
if (DetectDreamcast())
|
||||||
|
return DiscType.Dreamcast;
|
||||||
|
}
|
||||||
|
|
||||||
|
//*** asni - 20171011 - Suggestion: move this to the beginning of the DetectDiscType() method before any longer running lookups?
|
||||||
|
//its a cheap win for a lot of systems, but ONLY if the iso.Parse() method is quick running (might have to time it)
|
||||||
if (isIso)
|
if (isIso)
|
||||||
{
|
{
|
||||||
var appId = System.Text.Encoding.ASCII.GetString(iso.VolumeDescriptors[0].ApplicationIdentifier).TrimEnd('\0', ' ');
|
var appId = System.Text.Encoding.ASCII.GetString(iso.VolumeDescriptors[0].ApplicationIdentifier).TrimEnd('\0', ' ');
|
||||||
|
var sysId = System.Text.Encoding.ASCII.GetString(iso.VolumeDescriptors[0].SystemIdentifier).TrimEnd('\0', ' ');
|
||||||
|
|
||||||
//for example: PSX magical drop F (JP SLPS_02337) doesn't have the correct iso PVD fields
|
//for example: PSX magical drop F (JP SLPS_02337) doesn't have the correct iso PVD fields
|
||||||
//but, some PSX games (junky rips) don't have the 'licensed by string' so we'll hope they get caught here
|
//but, some PSX games (junky rips) don't have the 'licensed by string' so we'll hope they get caught here
|
||||||
if (appId == "PLAYSTATION")
|
if (appId == "PLAYSTATION")
|
||||||
return DiscType.SonyPSX;
|
return DiscType.SonyPSX;
|
||||||
|
|
||||||
if (appId == "PSP GAME")
|
if (appId == "PSP GAME")
|
||||||
return DiscType.SonyPSP;
|
return DiscType.SonyPSP;
|
||||||
|
// in case the appId is not set correctly...
|
||||||
|
if (iso.Root.Children.Where(a => a.Key == "PSP_GAME").FirstOrDefault().Value as ISODirectoryNode != null)
|
||||||
|
return DiscType.SonyPSP;
|
||||||
|
|
||||||
return DiscType.UnknownCDFS;
|
if (sysId == "SEGA SEGASATURN")
|
||||||
}
|
return DiscType.SegaSaturn;
|
||||||
|
|
||||||
|
if (sysId.Contains("SEGAKATANA"))
|
||||||
|
return DiscType.Dreamcast;
|
||||||
|
|
||||||
|
if (sysId == "MEGA_CD")
|
||||||
|
return DiscType.MegaCD;
|
||||||
|
|
||||||
|
if (sysId == "ASAHI-CDV")
|
||||||
|
return DiscType.Playdia;
|
||||||
|
|
||||||
|
if (sysId == "CDTV" || sysId == "AMIGA")
|
||||||
|
return DiscType.Amiga;
|
||||||
|
foreach (var f in iso.Root.Children)
|
||||||
|
if (f.Key.ToLower().Contains("cd32"))
|
||||||
|
return DiscType.Amiga;
|
||||||
|
|
||||||
|
// NeoGeoCD Check
|
||||||
|
var absTxt = iso.Root.Children.Where(a => a.Key.Contains("ABS.TXT")).ToList();
|
||||||
|
if (absTxt.Count > 0)
|
||||||
|
{
|
||||||
|
if (SectorContains("abstracted by snk", Convert.ToInt32(absTxt.First().Value.Offset)))
|
||||||
|
return DiscType.NeoGeoCD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return DiscType.UnknownCDFS;
|
||||||
|
}
|
||||||
|
|
||||||
return DiscType.UnknownFormat;
|
return DiscType.UnknownFormat;
|
||||||
}
|
}
|
||||||
|
@ -165,13 +256,87 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
t++)
|
t++)
|
||||||
{
|
{
|
||||||
var track = _disc.TOC.TOCItems[t];
|
var track = _disc.TOC.TOCItems[t];
|
||||||
if (track.IsData && StringAt("PC-FX:Hu_CD-ROM", 0, track.LBA))
|
//asni - this search is less specific - turns out there are discs where 'Hu:' is not present
|
||||||
|
if (track.IsData && SectorContains("pc-fx", track.LBA))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] ReadSectorCached(int lba)
|
//asni 20171011 - this ONLY works if a valid cuefile/ccd is passed into DiscIdentifier.
|
||||||
|
//if an .iso is presented, the internally manufactured cue data does not work - possibly something to do with
|
||||||
|
//track 01 being Audio. Not tested, but presumably PCFX has the same issue
|
||||||
|
bool DetectTurboCD()
|
||||||
|
{
|
||||||
|
var toc = _disc.TOC;
|
||||||
|
for (int t = toc.FirstRecordedTrackNumber;
|
||||||
|
t <= toc.LastRecordedTrackNumber;
|
||||||
|
t++)
|
||||||
|
{
|
||||||
|
var track = _disc.TOC.TOCItems[t];
|
||||||
|
//asni - pcfx games also contain the 'PC Engine' string
|
||||||
|
if ((track.IsData && SectorContains("pc engine", track.LBA + 1) && !SectorContains("pc-fx", track.LBA + 1)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Detect3DO()
|
||||||
|
{
|
||||||
|
var toc = _disc.TOC;
|
||||||
|
for (int t = toc.FirstRecordedTrackNumber;
|
||||||
|
t <= toc.LastRecordedTrackNumber;
|
||||||
|
t++)
|
||||||
|
{
|
||||||
|
var track = _disc.TOC.TOCItems[t];
|
||||||
|
if (track.IsData && SectorContains("iamaduckiamaduck", track.LBA))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//asni - slightly longer running than the others due to its brute-force nature. Should run later in the method
|
||||||
|
bool DetectDreamcast()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 10000; i++)
|
||||||
|
{
|
||||||
|
if (SectorContains("segakatana", i))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DetectCDi()
|
||||||
|
{
|
||||||
|
return StringAt("CD-RTOS", 8, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DetectGameCube()
|
||||||
|
{
|
||||||
|
var data = ReadSectorCached(0);
|
||||||
|
if (data == null) return false;
|
||||||
|
byte[] magic = data.Skip(28).Take(4).ToArray();
|
||||||
|
string hexString = "";
|
||||||
|
foreach (var b in magic)
|
||||||
|
hexString += b.ToString("X2");
|
||||||
|
|
||||||
|
return hexString == "C2339F3D";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DetectWii()
|
||||||
|
{
|
||||||
|
var data = ReadSectorCached(0);
|
||||||
|
if (data == null) return false;
|
||||||
|
byte[] magic = data.Skip(24).Take(4).ToArray();
|
||||||
|
string hexString = "";
|
||||||
|
foreach (var b in magic)
|
||||||
|
hexString += b.ToString("X2");
|
||||||
|
|
||||||
|
return hexString == "5D1C9EA3";
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] ReadSectorCached(int lba)
|
||||||
{
|
{
|
||||||
//read it if we dont have it cached
|
//read it if we dont have it cached
|
||||||
//we wont be caching very much here, it's no big deal
|
//we wont be caching very much here, it's no big deal
|
||||||
|
@ -197,5 +362,12 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
Buffer.BlockCopy(data, n, cmp2, 0, cmp.Length);
|
Buffer.BlockCopy(data, n, cmp2, 0, cmp.Length);
|
||||||
return System.Linq.Enumerable.SequenceEqual(cmp, cmp2);
|
return System.Linq.Enumerable.SequenceEqual(cmp, cmp2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool SectorContains(string s, int lba = 0)
|
||||||
|
{
|
||||||
|
var data = ReadSectorCached(lba);
|
||||||
|
if (data == null) return false;
|
||||||
|
return System.Text.Encoding.ASCII.GetString(data).ToLower().Contains(s.ToLower());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue