Revert "Move some private helper methods to local methods in DiscSystem"
This reverts commit 6f813edbdb
.
This commit is contained in:
parent
7244231cc4
commit
5a6072cdf0
|
@ -91,7 +91,7 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
}
|
||||
#endif
|
||||
|
||||
static MednaDisc()
|
||||
private static void CheckLibrary()
|
||||
{
|
||||
var lib = OSTailoredCode.LinkedLibManager.LoadOrZero("mednadisc.dll");
|
||||
_IsLibraryAvailable = lib != IntPtr.Zero
|
||||
|
@ -99,6 +99,11 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
if (lib != IntPtr.Zero) OSTailoredCode.LinkedLibManager.FreeByPtr(lib);
|
||||
}
|
||||
|
||||
static MednaDisc()
|
||||
{
|
||||
CheckLibrary();
|
||||
}
|
||||
|
||||
private static bool _IsLibraryAvailable;
|
||||
public static bool IsLibraryAvailable => _IsLibraryAvailable;
|
||||
|
||||
|
|
|
@ -146,33 +146,19 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
private List<KeyValuePair<string, ISOFileNode>> fileNodes;
|
||||
private List<ISODirectoryNode> dirsParsed;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a flat list of all recursed files
|
||||
/// </summary>
|
||||
public List<KeyValuePair<string, ISOFileNode>> EnumerateAllFilesRecursively()
|
||||
{
|
||||
var fileNodes = new List<KeyValuePair<string, ISOFileNode>>();
|
||||
fileNodes = new List<KeyValuePair<string, ISOFileNode>>();
|
||||
if (Root.Children == null) return fileNodes;
|
||||
|
||||
var dirsParsed = new List<ISODirectoryNode>();
|
||||
|
||||
void ProcessDirectoryFiles(Dictionary<string, ISONode> idn)
|
||||
{
|
||||
foreach (var n in idn)
|
||||
{
|
||||
if (n.Value is ISODirectoryNode subdirNode)
|
||||
{
|
||||
if (dirsParsed.Contains(subdirNode)) continue;
|
||||
dirsParsed.Add(subdirNode);
|
||||
ProcessDirectoryFiles(subdirNode.Children);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileNodes.Add(new KeyValuePair<string, ISOFileNode>(n.Key, n.Value as ISOFileNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dirsParsed = new List<ISODirectoryNode>();
|
||||
foreach (var idn in Root.Children.Values.OfType<ISODirectoryNode>()) // iterate through each folder
|
||||
{
|
||||
// process all files in this directory (and recursively process files in subfolders)
|
||||
|
@ -181,6 +167,24 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
ProcessDirectoryFiles(idn.Children);
|
||||
}
|
||||
return fileNodes.Distinct().ToList();
|
||||
}
|
||||
|
||||
private void ProcessDirectoryFiles(Dictionary<string, ISONode> idn)
|
||||
{
|
||||
foreach (var n in idn)
|
||||
{
|
||||
if (n.Value is ISODirectoryNode subdirNode)
|
||||
{
|
||||
if (dirsParsed.Contains(subdirNode)) continue;
|
||||
dirsParsed.Add(subdirNode);
|
||||
ProcessDirectoryFiles(subdirNode.Children);
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyValuePair<string, ISOFileNode> f = new KeyValuePair<string, ISOFileNode>(n.Key, n.Value as ISOFileNode);
|
||||
fileNodes.Add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -16,6 +17,11 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
public bool IsAudio;
|
||||
}
|
||||
|
||||
private static string[] Escape(IEnumerable<string> args)
|
||||
{
|
||||
return args.Select(s => s.Contains(" ") ? $"\"{s}\"" : s).ToArray();
|
||||
}
|
||||
|
||||
//note: accepts . or : in the stream stream/substream separator in the stream ID format, since that changed at some point in FFMPEG history
|
||||
//if someone has a better idea how to make the determination of whether an audio stream is available, I'm all ears
|
||||
private static readonly Regex rxHasAudio = new Regex(@"Stream \#(\d*(\.|\:)\d*)\: Audio", RegexOptions.Compiled);
|
||||
|
@ -49,9 +55,9 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
public int ExitCode;
|
||||
}
|
||||
|
||||
public static RunResults Run(params string[] args)
|
||||
public RunResults Run(params string[] args)
|
||||
{
|
||||
args = args.Select(s => s.Contains(" ") ? $"\"{s}\"" : s).ToArray();
|
||||
args = Escape(args);
|
||||
StringBuilder sbCmdline = new StringBuilder();
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
|
@ -100,7 +106,7 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
}
|
||||
}
|
||||
|
||||
internal static class AudioDecoder
|
||||
internal class AudioDecoder
|
||||
{
|
||||
[Serializable]
|
||||
public class AudioDecoder_Exception : Exception
|
||||
|
@ -111,17 +117,50 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
}
|
||||
}
|
||||
|
||||
/// <exception cref="AudioDecoder_Exception">could not find source audio for <paramref name="audioPath"/></exception>
|
||||
public static byte[] AcquireWaveData(string audioPath)
|
||||
public AudioDecoder()
|
||||
{
|
||||
// find audio at a path similar to the provided path (i.e. finds Track01.mp3 for Track01.wav)
|
||||
// TODO isn't this redundant with CueFileResolver?
|
||||
var basePath = Path.GetFileNameWithoutExtension(audioPath);
|
||||
var files = new DirectoryInfo(Path.GetDirectoryName(audioPath)).GetFiles().Select(fi => fi.FullName).ToList();
|
||||
var found = files.Where(f => string.Equals(f, audioPath, StringComparison.InvariantCulture)) // first, look for the file type we actually asked for
|
||||
.Concat(files.Where(f => string.Equals(Path.GetFileNameWithoutExtension(f), basePath, StringComparison.InvariantCulture))) // then, look for any other type
|
||||
.FirstOrDefault(f => new FFMpeg().QueryAudio(f).IsAudio); // ignore false positives
|
||||
return new FFMpeg().DecodeAudio(found ?? throw new AudioDecoder_Exception($"Could not find source audio for: {Path.GetFileName(audioPath)}"));
|
||||
}
|
||||
|
||||
private bool CheckForAudio(string path)
|
||||
{
|
||||
FFMpeg ffmpeg = new FFMpeg();
|
||||
var qa = ffmpeg.QueryAudio(path);
|
||||
return qa.IsAudio;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// finds audio at a path similar to the provided path (i.e. finds Track01.mp3 for Track01.wav)
|
||||
/// TODO - isnt this redundant with CueFileResolver?
|
||||
/// </summary>
|
||||
private string FindAudio(string audioPath)
|
||||
{
|
||||
string basePath = Path.GetFileNameWithoutExtension(audioPath);
|
||||
//look for potential candidates
|
||||
var di = new DirectoryInfo(Path.GetDirectoryName(audioPath));
|
||||
var fis = di.GetFiles();
|
||||
//first, look for the file type we actually asked for
|
||||
foreach (var fi in fis)
|
||||
{
|
||||
if (fi.FullName.ToUpper() == audioPath.ToUpper())
|
||||
if (CheckForAudio(fi.FullName))
|
||||
return fi.FullName;
|
||||
}
|
||||
//then look for any other type
|
||||
foreach (var fi in fis)
|
||||
{
|
||||
if (Path.GetFileNameWithoutExtension(fi.FullName).ToUpper() == basePath.ToUpper())
|
||||
{
|
||||
if (CheckForAudio(fi.FullName))
|
||||
{
|
||||
return fi.FullName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <exception cref="AudioDecoder_Exception">could not find source audio for <paramref name="audioPath"/></exception>
|
||||
public byte[] AcquireWaveData(string audioPath) => new FFMpeg()
|
||||
.DecodeAudio(FindAudio(audioPath) ?? throw new AudioDecoder_Exception($"Could not find source audio for: {Path.GetFileName(audioPath)}"));
|
||||
}
|
||||
}
|
|
@ -67,8 +67,6 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
|
||||
public void Load(string path)
|
||||
{
|
||||
const string MISFORMED_EXCEPTION_MESSAGE = "Mis-formed ECM file";
|
||||
|
||||
stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
|
||||
//skip header
|
||||
|
@ -79,17 +77,17 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
{
|
||||
//read block count. this format is really stupid. maybe its good for detecting non-ecm files or something.
|
||||
int b = stream.ReadByte();
|
||||
if (b == -1) throw new InvalidOperationException(MISFORMED_EXCEPTION_MESSAGE);
|
||||
if (b == -1) MisformedException();
|
||||
int bytes = 1;
|
||||
int T = b & 3;
|
||||
long N = (b >> 2) & 0x1F;
|
||||
int nbits = 5;
|
||||
while (b.Bit(7))
|
||||
{
|
||||
if (bytes == 5) throw new InvalidOperationException(MISFORMED_EXCEPTION_MESSAGE); //if we're gonna need a 6th byte, this file is broken
|
||||
if (bytes == 5) MisformedException(); //if we're gonna need a 6th byte, this file is broken
|
||||
b = stream.ReadByte();
|
||||
bytes++;
|
||||
if (b == -1) throw new InvalidOperationException(MISFORMED_EXCEPTION_MESSAGE);
|
||||
if (b == -1) MisformedException();
|
||||
N |= (long)(b & 0x7F) << nbits;
|
||||
nbits += 7;
|
||||
}
|
||||
|
@ -100,7 +98,7 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
|
||||
//the 0x80000000 business is confusing, but this is almost positively an error
|
||||
if (N >= 0x100000000)
|
||||
throw new InvalidOperationException(MISFORMED_EXCEPTION_MESSAGE);
|
||||
MisformedException();
|
||||
|
||||
uint todo = (uint)N + 1;
|
||||
|
||||
|
@ -134,7 +132,7 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
stream.Seek(todo * 2328, SeekOrigin.Current);
|
||||
logOffset += todo * 2336;
|
||||
}
|
||||
else throw new InvalidOperationException(MISFORMED_EXCEPTION_MESSAGE);
|
||||
else MisformedException();
|
||||
}
|
||||
|
||||
//TODO - endian bug. need an endian-independent binary reader with good license (miscutils is apache license)
|
||||
|
@ -145,6 +143,11 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
Length = logOffset;
|
||||
}
|
||||
|
||||
private void MisformedException()
|
||||
{
|
||||
throw new InvalidOperationException("Mis-formed ECM file");
|
||||
}
|
||||
|
||||
public static bool IsECM(string path)
|
||||
{
|
||||
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
|
|
|
@ -38,6 +38,9 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
BaseStream = null;
|
||||
}
|
||||
|
||||
private static string ReadTag(BinaryReader br) =>
|
||||
string.Concat(br.ReadChar(), br.ReadChar(), br.ReadChar(), br.ReadChar());
|
||||
|
||||
protected static void WriteTag(BinaryWriter bw, string tag)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
|
@ -275,9 +278,7 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
|
||||
private long readCounter;
|
||||
private RiffChunk ReadChunk(BinaryReader br)
|
||||
{
|
||||
static string ReadTag(BinaryReader br) => string.Concat(br.ReadChar(), br.ReadChar(), br.ReadChar(), br.ReadChar());
|
||||
|
||||
{
|
||||
RiffChunk ret;
|
||||
string tag = ReadTag(br); readCounter += 4;
|
||||
uint size = br.ReadUInt32(); readCounter += 4;
|
||||
|
|
|
@ -214,18 +214,31 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
return sections;
|
||||
}
|
||||
|
||||
private int PreParseIntegrityCheck(List<CCDSection> sections)
|
||||
{
|
||||
if (sections.Count == 0) throw new CCDParseException("Malformed CCD format: no sections");
|
||||
|
||||
//we need at least a CloneCD and Disc section
|
||||
if (sections.Count < 2) throw new CCDParseException("Malformed CCD format: insufficient sections");
|
||||
|
||||
var ccdSection = sections[0];
|
||||
if (ccdSection.Name != "CLONECD")
|
||||
throw new CCDParseException("Malformed CCD format: confusing first section name");
|
||||
|
||||
if (!ccdSection.ContainsKey("VERSION"))
|
||||
throw new CCDParseException("Malformed CCD format: missing version in CloneCD section");
|
||||
|
||||
if(sections[1].Name != "DISC")
|
||||
throw new CCDParseException("Malformed CCD format: section[1] isn't [Disc]");
|
||||
|
||||
int version = ccdSection["VERSION"];
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
/// <exception cref="CCDParseException">parsed <see cref="CCDFile.DataTracksScrambled"/> is <c>1</c>, parsed session number is not <c>1</c>, or malformed entry</exception>
|
||||
public CCDFile ParseFrom(Stream stream)
|
||||
{
|
||||
static int PreParseIntegrityCheck(IReadOnlyList<CCDSection> sections)
|
||||
{
|
||||
if (sections.Count == 0) throw new CCDParseException("Malformed CCD format: no sections");
|
||||
if (sections.Count < 2) throw new CCDParseException("Malformed CCD format: insufficient sections"); //we need at least a CloneCD and Disc section
|
||||
if (sections[0].Name != "CLONECD") throw new CCDParseException("Malformed CCD format: confusing first section name");
|
||||
if (sections[1].Name != "DISC") throw new CCDParseException("Malformed CCD format: section[1] isn't [Disc]");
|
||||
return sections[0].TryGetValue("VERSION", out var version) ? version : throw new CCDParseException("Malformed CCD format: missing version in CloneCD section");
|
||||
}
|
||||
|
||||
CCDFile ccdf = new CCDFile();
|
||||
|
||||
var sections = ParseSections(stream);
|
||||
|
|
|
@ -107,7 +107,8 @@ namespace BizHawk.Emulation.DiscSystem.CUE
|
|||
{
|
||||
throw new DiscReferenceException(ccf.FullPath, "No decoding service was available (make sure ffmpeg.exe is available. even though this may be a wav, ffmpeg is used to load oddly formatted wave files. If you object to this, please send us a note and we'll see what we can do. It shouldn't be too hard.)");
|
||||
}
|
||||
byte[] buf = AudioDecoder.AcquireWaveData(ccf.FullPath);
|
||||
AudioDecoder dec = new AudioDecoder();
|
||||
byte[] buf = dec.AcquireWaveData(ccf.FullPath);
|
||||
var blob = new Disc.Blob_WaveFile();
|
||||
OUT_Disc.DisposableResources.Add(file_blob = blob);
|
||||
blob.Load(new MemoryStream(buf));
|
||||
|
|
|
@ -3,8 +3,6 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
|
||||
//disc type identification logic
|
||||
|
||||
namespace BizHawk.Emulation.DiscSystem
|
||||
|
@ -121,79 +119,6 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
/// </summary>
|
||||
public DiscType DetectDiscType()
|
||||
{
|
||||
// this is a reasonable approach to identify Saturn
|
||||
bool DetectSegaSaturn() => StringAt("SEGA SEGASATURN", 0);
|
||||
|
||||
// probably wrong
|
||||
bool DetectMegaCD() => StringAt("SEGADISCSYSTEM", 0) || StringAt("SEGADISCSYSTEM", 16);
|
||||
|
||||
bool DetectPSX() => StringAt(" Licensed by ", 0, 4)
|
||||
&& (
|
||||
StringAt("Sony Computer Entertainment Euro", 32, 4)
|
||||
|| StringAt("Sony Computer Entertainment Inc.", 32, 4)
|
||||
|| StringAt("Sony Computer Entertainment Amer", 32, 4)
|
||||
|| StringAt("Sony Computer Entertainment of A", 32, 4)
|
||||
);
|
||||
|
||||
bool DetectPCFX()
|
||||
{
|
||||
var toc = _disc.TOC;
|
||||
for (var t = toc.FirstRecordedTrackNumber; t <= toc.LastRecordedTrackNumber; t++)
|
||||
{
|
||||
var track = _disc.TOC.TOCItems[t];
|
||||
//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;
|
||||
}
|
||||
|
||||
// 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 (var 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 be run later in the method
|
||||
bool DetectDreamcast()
|
||||
{
|
||||
for (var i = 0; i < 1000; i++) if (SectorContains("segakatana", i)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DetectCDi() => StringAt("CD-RTOS", 8, 16);
|
||||
|
||||
bool DetectGameCube()
|
||||
{
|
||||
var data = ReadSectorCached(0);
|
||||
return data != null && data.Skip(28).Take(4).ToArray().BytesToHexString() == "C2339F3D";
|
||||
}
|
||||
|
||||
bool DetectWii()
|
||||
{
|
||||
var data = ReadSectorCached(0);
|
||||
return data != null && data.Skip(24).Take(4).ToArray().BytesToHexString() == "5D1C9EA3";
|
||||
}
|
||||
|
||||
// PCFX & TurboCD sometimes (if not alltimes) have audio on track 1 - run these before the AudioDisc detection (asni)
|
||||
if (DetectPCFX())
|
||||
return DiscType.PCFX;
|
||||
|
@ -294,6 +219,120 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
return DiscType.UnknownFormat;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is reasonable approach to ID saturn.
|
||||
/// </summary>
|
||||
private bool DetectSegaSaturn()
|
||||
{
|
||||
return StringAt("SEGA SEGASATURN", 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// probably wrong
|
||||
/// </summary>
|
||||
private bool DetectMegaCD()
|
||||
{
|
||||
return StringAt("SEGADISCSYSTEM", 0) || StringAt("SEGADISCSYSTEM", 16);
|
||||
}
|
||||
|
||||
private bool DetectPSX()
|
||||
{
|
||||
if (!StringAt(" Licensed by ", 0, 4)) return false;
|
||||
return (StringAt("Sony Computer Entertainment Euro", 32, 4)
|
||||
|| StringAt("Sony Computer Entertainment Inc.", 32, 4)
|
||||
|| StringAt("Sony Computer Entertainment Amer", 32, 4)
|
||||
|| StringAt("Sony Computer Entertainment of A", 32, 4)
|
||||
);
|
||||
}
|
||||
|
||||
private bool DetectPCFX()
|
||||
{
|
||||
var toc = _disc.TOC;
|
||||
for (int t = toc.FirstRecordedTrackNumber;
|
||||
t <= toc.LastRecordedTrackNumber;
|
||||
t++)
|
||||
{
|
||||
var track = _disc.TOC.TOCItems[t];
|
||||
//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;
|
||||
}
|
||||
|
||||
//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
|
||||
private 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;
|
||||
}
|
||||
|
||||
private 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
|
||||
private bool DetectDreamcast()
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
if (SectorContains("segakatana", i))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool DetectCDi()
|
||||
{
|
||||
return StringAt("CD-RTOS", 8, 16);
|
||||
}
|
||||
|
||||
private 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";
|
||||
}
|
||||
|
||||
private 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 don't have it cached
|
||||
|
|
|
@ -126,6 +126,44 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
return 2448;
|
||||
}
|
||||
|
||||
private int ReadLBA_2048_Mode1(int lba, byte[] buffer, int offset)
|
||||
{
|
||||
//we can read the 2048 bytes directly
|
||||
var sector = disc.SynthProvider.Get(lba);
|
||||
|
||||
if (sector == null) return 0;
|
||||
|
||||
PrepareBuffer(buffer, offset, 2048);
|
||||
PrepareJob(lba);
|
||||
job.DestBuffer2448 = buf2442;
|
||||
job.DestOffset = 0;
|
||||
job.Parts = ESectorSynthPart.User2048;
|
||||
|
||||
sector.Synth(job);
|
||||
Buffer.BlockCopy(buf2442, 16, buffer, offset, 2048);
|
||||
|
||||
return 2048;
|
||||
}
|
||||
|
||||
private int ReadLBA_2048_Mode2_Form1(int lba, byte[] buffer, int offset)
|
||||
{
|
||||
//we can read the 2048 bytes directly but we have to get them from the mode 2 data
|
||||
var sector = disc.SynthProvider.Get(lba);
|
||||
|
||||
if (sector == null) return 0;
|
||||
|
||||
PrepareBuffer(buffer, offset, 2048);
|
||||
PrepareJob(lba);
|
||||
job.DestBuffer2448 = buf2442;
|
||||
job.DestOffset = 0;
|
||||
job.Parts = ESectorSynthPart.User2336;
|
||||
|
||||
sector.Synth(job);
|
||||
Buffer.BlockCopy(buf2442, 24, buffer, offset, 2048);
|
||||
|
||||
return 2048;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads 12 bytes of subQ data from a sector.
|
||||
/// This is necessarily deinterleaved.
|
||||
|
@ -158,48 +196,10 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public int ReadLBA_2048(int lba, byte[] buffer, int offset)
|
||||
{
|
||||
int ReadLBA_2048_Mode1()
|
||||
{
|
||||
//we can read the 2048 bytes directly
|
||||
var sector = disc.SynthProvider.Get(lba);
|
||||
|
||||
if (sector == null) return 0;
|
||||
|
||||
PrepareBuffer(buffer, offset, 2048);
|
||||
PrepareJob(lba);
|
||||
job.DestBuffer2448 = buf2442;
|
||||
job.DestOffset = 0;
|
||||
job.Parts = ESectorSynthPart.User2048;
|
||||
|
||||
sector.Synth(job);
|
||||
Buffer.BlockCopy(buf2442, 16, buffer, offset, 2048);
|
||||
|
||||
return 2048;
|
||||
}
|
||||
|
||||
int ReadLBA_2048_Mode2_Form1()
|
||||
{
|
||||
//we can read the 2048 bytes directly but we have to get them from the mode 2 data
|
||||
var sector = disc.SynthProvider.Get(lba);
|
||||
|
||||
if (sector == null) return 0;
|
||||
|
||||
PrepareBuffer(buffer, offset, 2048);
|
||||
PrepareJob(lba);
|
||||
job.DestBuffer2448 = buf2442;
|
||||
job.DestOffset = 0;
|
||||
job.Parts = ESectorSynthPart.User2336;
|
||||
|
||||
sector.Synth(job);
|
||||
Buffer.BlockCopy(buf2442, 24, buffer, offset, 2048);
|
||||
|
||||
return 2048;
|
||||
}
|
||||
|
||||
if (Policy.UserData2048Mode == DiscSectorReaderPolicy.EUserData2048Mode.AssumeMode1)
|
||||
return ReadLBA_2048_Mode1();
|
||||
return ReadLBA_2048_Mode1(lba, buffer, offset);
|
||||
else if (Policy.UserData2048Mode == DiscSectorReaderPolicy.EUserData2048Mode.AssumeMode2_Form1)
|
||||
return ReadLBA_2048_Mode2_Form1();
|
||||
return ReadLBA_2048_Mode2_Form1(lba, buffer, offset);
|
||||
else
|
||||
{
|
||||
//we need to determine the type of the sector.
|
||||
|
|
|
@ -215,29 +215,40 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
return crc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// returns the address from a sector. useful for saving it before zeroing it for ECC calculations
|
||||
/// </summary>
|
||||
private static uint GetSectorAddress(byte[] sector, int sector_offset)
|
||||
{
|
||||
return (uint)(
|
||||
(sector[sector_offset + 12 + 0] << 0)
|
||||
| (sector[sector_offset + 12 + 1] << 8)
|
||||
| (sector[sector_offset + 12 + 2] << 16)
|
||||
);
|
||||
//| (sector[sector_offset + 12 + 3] << 24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sets the address for a sector. useful for restoring it after zeroing it for ECC calculations
|
||||
/// </summary>
|
||||
private static void SetSectorAddress(byte[] sector, int sector_offset, uint address)
|
||||
{
|
||||
sector[sector_offset + 12 + 0] = (byte)((address >> 0) & 0xFF);
|
||||
sector[sector_offset + 12 + 1] = (byte)((address >> 8) & 0xFF);
|
||||
sector[sector_offset + 12 + 2] = (byte)((address >> 16) & 0xFF);
|
||||
//sector[sector_offset + 12 + 3] = (byte)((address >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// populates a sector with valid ECC information.
|
||||
/// it is safe to supply the same array for sector and dest.
|
||||
/// </summary>
|
||||
public static void ECC_Populate(byte[] src, int src_offset, byte[] dest, int dest_offset, bool zeroSectorAddress)
|
||||
{
|
||||
// returns the address from a sector. useful for saving it before zeroing it for ECC calculations
|
||||
static uint GetSectorAddress(byte[] sector, int sector_offset) => (uint)(
|
||||
(sector[sector_offset + 12 + 0] << 0)
|
||||
| (sector[sector_offset + 12 + 1] << 8)
|
||||
| (sector[sector_offset + 12 + 2] << 16)
|
||||
// | (sector[sector_offset + 12 + 3] << 24)
|
||||
);
|
||||
|
||||
// sets the address for a sector. useful for restoring it after zeroing it for ECC calculations
|
||||
static void SetSectorAddress(byte[] sector, int sector_offset, uint address)
|
||||
{
|
||||
sector[sector_offset + 12 + 0] = (byte)((address >> 0) & 0xFF);
|
||||
sector[sector_offset + 12 + 1] = (byte)((address >> 8) & 0xFF);
|
||||
sector[sector_offset + 12 + 2] = (byte)((address >> 16) & 0xFF);
|
||||
// sector[sector_offset + 12 + 3] = (byte)((address >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
//save the old sector address, so we can restore it later. SOMETIMES ECC is supposed to be calculated without it? see TODO
|
||||
uint address = GetSectorAddress(src, src_offset);
|
||||
if (zeroSectorAddress) SetSectorAddress(src, src_offset, 0);
|
||||
|
|
Loading…
Reference in New Issue