diff --git a/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs b/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs
index a9add9cf4e..7db33ef622 100644
--- a/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs
+++ b/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
//disc type identification logic
@@ -8,7 +9,7 @@ namespace BizHawk.Emulation.DiscSystem
public enum DiscType
{
///
- /// 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
///
AudioDisc,
@@ -38,7 +39,7 @@ namespace BizHawk.Emulation.DiscSystem
SegaSaturn,
///
- /// Its not clear whether we can ever have enough info to ID a turboCD disc (we're using hashes)
+ /// PC Engine CD
///
TurboCD,
@@ -50,7 +51,47 @@ namespace BizHawk.Emulation.DiscSystem
///
/// By NEC.
///
- PCFX
+ PCFX,
+
+ ///
+ /// By Panasonic
+ ///
+ Panasonic3DO,
+
+ ///
+ /// Philips
+ ///
+ CDi,
+
+ ///
+ /// Nintendo Gamecube
+ ///
+ GameCube,
+
+ ///
+ /// Nintendo Wii
+ ///
+ Wii,
+
+ ///
+ /// SNK NeoGeo
+ ///
+ NeoGeoCD,
+
+ ///
+ /// Bandai Playdia
+ ///
+ Playdia,
+
+ ///
+ /// Either CDTV or CD32 (I havent found a reliable way of distinguishing between them yet -asni)
+ ///
+ Amiga,
+
+ ///
+ /// Sega Dreamcast
+ ///
+ Dreamcast
}
public class DiscIdentifier
@@ -76,24 +117,26 @@ namespace BizHawk.Emulation.DiscSystem
///
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())
return DiscType.PCFX;
- //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)
- //NOTE: PCE-CD detection goes through here (no good way to detect PCE cd)
- if (!_disc.TOC.TOCItems[1].IsData)
+ if (DetectTurboCD())
+ return DiscType.TurboCD;
+
+ //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;
// if (_dsr.ReadLBA_Mode(_disc.TOC.TOCItems[1].LBA) == 0)
// 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
+ //asni - this isn't strictly true - SystemIdentifier in volume descriptor has been observed on occasion (see below)
if (DetectSegaSaturn())
return DiscType.SegaSaturn;
-
// not fully tested yet
if (DetectMegaCD())
return DiscType.MegaCD;
@@ -102,31 +145,79 @@ namespace BizHawk.Emulation.DiscSystem
if (DetectPSX())
return DiscType.SonyPSX;
- //we dont know how to detect TurboCD.
- //an emulator frontend will likely just guess TurboCD if the disc is UnknownFormat
- //(we can also have a gameDB!)
+ if (Detect3DO())
+ return DiscType.Panasonic3DO;
- 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)
discView = EDiscStreamView.DiscStreamView_Mode2_Form1_2048;
var iso = new ISOFile();
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)
{
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
- //but, some PSX games (junky rips) don't have the 'licensed by string' so we'll hope they get caught here
- if (appId == "PLAYSTATION")
+ //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
+ if (appId == "PLAYSTATION")
return DiscType.SonyPSX;
if (appId == "PSP GAME")
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;
}
@@ -165,13 +256,87 @@ namespace BizHawk.Emulation.DiscSystem
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 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
//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);
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());
+ }
}
}
\ No newline at end of file