2015-06-23 18:57:11 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.DiscSystem
|
|
|
|
|
{
|
2015-07-01 08:55:59 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// General disc policies to be logically applied at mounting time. The choices are irreversible once a disc is loaded.
|
|
|
|
|
/// Maybe these are only for CUEs, but maybe not. Not sure yet.
|
2015-07-01 09:44:03 +00:00
|
|
|
|
/// Could put caching policies here too (cached ecm calculations, etc.)
|
2015-07-01 08:55:59 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
public class DiscMountPolicy
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// "At the beginning of a Pause (i.e. Index = 00) the relative time is
|
|
|
|
|
/// --A-- set to the duration of the Pause.
|
|
|
|
|
/// During the Pause this relative time decreases and
|
|
|
|
|
/// --B-- equals zero in the last Section"
|
|
|
|
|
/// This is a contradiction.
|
2015-07-01 10:26:10 +00:00
|
|
|
|
/// By choosing true, mode A is selected, and the final sector of the pause is -1.
|
|
|
|
|
/// (I like this better. Defaulting until proven otherwise [write test case here])
|
|
|
|
|
/// By choosing false, mode B is selected, and the final sector of the pause is 0.
|
|
|
|
|
/// (Mednafen does it this way)
|
2015-07-01 08:55:59 +00:00
|
|
|
|
/// Discs (including PSX) exist using A, or B, or possibly (reference please) neither.
|
|
|
|
|
/// </summary>
|
2015-07-01 11:26:04 +00:00
|
|
|
|
public bool CUE_PregapContradictionModeA = true;
|
2015-07-01 08:55:59 +00:00
|
|
|
|
|
2015-07-02 01:28:02 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Mednafen sets mode2 pregap sectors as XA Form2 sectors.
|
|
|
|
|
/// This is almost surely not right in every case.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool CUE_PregapMode2_As_XA_Form2 = true;
|
|
|
|
|
|
2015-07-02 06:06:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Mednafen loads SBI files oddly
|
|
|
|
|
/// </summary>
|
2015-07-03 09:11:07 +00:00
|
|
|
|
public bool SBI_As_Mednafen = true;
|
2015-07-02 06:06:03 +00:00
|
|
|
|
|
|
|
|
|
public void SetForPSX()
|
2015-07-01 08:55:59 +00:00
|
|
|
|
{
|
2015-07-03 09:11:07 +00:00
|
|
|
|
CUE_PregapContradictionModeA = false;
|
|
|
|
|
CUE_PregapMode2_As_XA_Form2 = true;
|
|
|
|
|
SBI_As_Mednafen = true;
|
2015-07-01 08:55:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-23 18:57:11 +00:00
|
|
|
|
public partial class DiscMountJob : LoggedJob
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The filename to be loaded
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string IN_FromPath;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Slow-loading cues won't finish loading if this threshold is exceeded.
|
|
|
|
|
/// Set to 10 to always load a cue
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int IN_SlowLoadAbortThreshold = 10;
|
|
|
|
|
|
2015-07-01 08:55:59 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Cryptic policies to be used when mounting the disc.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public DiscMountPolicy IN_DiscMountPolicy = new DiscMountPolicy();
|
|
|
|
|
|
2015-06-23 18:57:11 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The interface to be used for loading the disc.
|
|
|
|
|
/// Usually you'll want DiscInterface.BizHawk, but others can be used for A/B testing
|
|
|
|
|
/// </summary>
|
|
|
|
|
public DiscInterface IN_DiscInterface = DiscInterface.BizHawk;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The resulting disc
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Disc OUT_Disc;
|
|
|
|
|
|
|
|
|
|
public void Run()
|
|
|
|
|
{
|
|
|
|
|
switch (IN_DiscInterface)
|
|
|
|
|
{
|
|
|
|
|
case DiscInterface.LibMirage:
|
|
|
|
|
throw new NotSupportedException("LibMirage not supported yet");
|
|
|
|
|
case DiscInterface.BizHawk:
|
|
|
|
|
RunBizHawk();
|
|
|
|
|
break;
|
|
|
|
|
case DiscInterface.MednaDisc:
|
|
|
|
|
RunMednaDisc();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-07-08 03:29:11 +00:00
|
|
|
|
|
|
|
|
|
if (OUT_Disc != null)
|
|
|
|
|
{
|
|
|
|
|
//generate toc and structure:
|
|
|
|
|
//1. TOCRaw from RawTOCEntries
|
|
|
|
|
var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob() { Entries = OUT_Disc.RawTOCEntries };
|
|
|
|
|
tocSynth.Run();
|
|
|
|
|
OUT_Disc.TOCRaw = tocSynth.Result;
|
|
|
|
|
//2. Structure frmo TOCRaw
|
|
|
|
|
var structureSynth = new DiscStructure.SynthesizeFromTOCRawJob() { IN_Disc = OUT_Disc, TOCRaw = OUT_Disc.TOCRaw };
|
|
|
|
|
structureSynth.Run();
|
|
|
|
|
OUT_Disc.Structure = structureSynth.Result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-23 18:57:11 +00:00
|
|
|
|
FinishLog();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RunBizHawk()
|
|
|
|
|
{
|
|
|
|
|
string infile = IN_FromPath;
|
|
|
|
|
string cue_content = null;
|
|
|
|
|
|
|
|
|
|
var cfr = new CUE_Format2.CueFileResolver();
|
|
|
|
|
|
|
|
|
|
RERUN:
|
|
|
|
|
var ext = Path.GetExtension(infile).ToLowerInvariant();
|
|
|
|
|
|
|
|
|
|
if (ext == ".iso")
|
|
|
|
|
{
|
|
|
|
|
//make a fake cue file to represent this iso file and rerun it as a cue
|
|
|
|
|
string filebase = Path.GetFileName(infile);
|
|
|
|
|
cue_content = string.Format(@"
|
|
|
|
|
FILE ""{0}"" BINARY
|
|
|
|
|
TRACK 01 MODE1/2048
|
|
|
|
|
INDEX 01 00:00:00",
|
|
|
|
|
filebase);
|
|
|
|
|
infile = Path.ChangeExtension(infile, ".cue");
|
|
|
|
|
goto RERUN;
|
|
|
|
|
}
|
|
|
|
|
if (ext == ".cue")
|
|
|
|
|
{
|
2015-07-01 06:09:20 +00:00
|
|
|
|
//TODO - make sure code is designed so no matter what happens, a disc is disposed in case of errors.
|
|
|
|
|
//perhaps the CUE_Format2 (once renamed to something like Context) can handle that
|
2015-06-23 18:57:11 +00:00
|
|
|
|
var cuePath = IN_FromPath;
|
|
|
|
|
var cue2 = new CUE_Format2();
|
2015-07-01 08:55:59 +00:00
|
|
|
|
cue2.DiscMountPolicy = IN_DiscMountPolicy;
|
2015-06-23 18:57:11 +00:00
|
|
|
|
|
|
|
|
|
cue2.Resolver = cfr;
|
|
|
|
|
if (!cfr.IsHardcodedResolve) cfr.SetBaseDirectory(Path.GetDirectoryName(infile));
|
|
|
|
|
|
|
|
|
|
//parse the cue file
|
|
|
|
|
var parseJob = new CUE_Format2.ParseCueJob();
|
|
|
|
|
if (cue_content == null)
|
|
|
|
|
cue_content = File.ReadAllText(cuePath);
|
|
|
|
|
parseJob.IN_CueString = cue_content;
|
|
|
|
|
cue2.ParseCueFile(parseJob);
|
2015-07-02 05:22:10 +00:00
|
|
|
|
//TODO - need better handling of log output
|
|
|
|
|
if (!string.IsNullOrEmpty(parseJob.OUT_Log)) Console.WriteLine(parseJob.OUT_Log);
|
2015-06-23 18:57:11 +00:00
|
|
|
|
ConcatenateJobLog(parseJob);
|
|
|
|
|
|
2015-07-01 06:09:20 +00:00
|
|
|
|
//compile the cue file:
|
|
|
|
|
//includes this work: resolve required bin files and find out what it's gonna take to load the cue
|
|
|
|
|
var compileJob = new CUE_Format2.CompileCueJob();
|
2015-07-01 08:55:59 +00:00
|
|
|
|
compileJob.IN_CueFormat = cue2;
|
2015-07-01 06:09:20 +00:00
|
|
|
|
compileJob.IN_CueFile = parseJob.OUT_CueFile;
|
|
|
|
|
compileJob.Run();
|
2015-07-02 05:22:10 +00:00
|
|
|
|
//TODO - need better handling of log output
|
|
|
|
|
if (!string.IsNullOrEmpty(compileJob.OUT_Log)) Console.WriteLine(compileJob.OUT_Log);
|
2015-07-01 06:09:20 +00:00
|
|
|
|
ConcatenateJobLog(compileJob);
|
2015-06-23 18:57:11 +00:00
|
|
|
|
|
|
|
|
|
//check slow loading threshold
|
2015-07-01 06:09:20 +00:00
|
|
|
|
if (compileJob.OUT_LoadTime >= IN_SlowLoadAbortThreshold)
|
2015-06-23 18:57:11 +00:00
|
|
|
|
{
|
|
|
|
|
Warn("Loading terminated due to slow load threshold");
|
|
|
|
|
goto DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//actually load it all up
|
|
|
|
|
var loadJob = new CUE_Format2.LoadCueJob();
|
2015-07-01 06:09:20 +00:00
|
|
|
|
loadJob.IN_CompileJob = compileJob;
|
2015-06-28 10:33:10 +00:00
|
|
|
|
loadJob.Run();
|
2015-07-02 05:22:10 +00:00
|
|
|
|
//TODO - need better handling of log output
|
|
|
|
|
if (!string.IsNullOrEmpty(loadJob.OUT_Log)) Console.WriteLine(loadJob.OUT_Log);
|
2015-07-01 06:09:20 +00:00
|
|
|
|
ConcatenateJobLog(loadJob);
|
2015-06-23 18:57:11 +00:00
|
|
|
|
|
|
|
|
|
OUT_Disc = loadJob.OUT_Disc;
|
2015-07-02 01:28:02 +00:00
|
|
|
|
//OUT_Disc.DiscMountPolicy = IN_DiscMountPolicy; //NOT SURE WE NEED THIS (only makes sense for cue probably)
|
2015-06-23 18:57:11 +00:00
|
|
|
|
|
|
|
|
|
//apply SBI if it exists (TODO - for formats other than cue?)
|
|
|
|
|
var sbiPath = Path.ChangeExtension(IN_FromPath, ".sbi");
|
|
|
|
|
if (File.Exists(sbiPath) && SBI.SBIFormat.QuickCheckISSBI(sbiPath))
|
|
|
|
|
{
|
|
|
|
|
var sbiJob = new SBI.LoadSBIJob();
|
|
|
|
|
sbiJob.IN_Path = sbiPath;
|
|
|
|
|
sbiJob.Run();
|
2015-07-03 09:11:07 +00:00
|
|
|
|
OUT_Disc.ApplySBI(sbiJob.OUT_Data, IN_DiscMountPolicy.SBI_As_Mednafen);
|
2015-06-23 18:57:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (ext == ".ccd")
|
|
|
|
|
{
|
|
|
|
|
CCD_Format ccdLoader = new CCD_Format();
|
|
|
|
|
OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-08 03:29:11 +00:00
|
|
|
|
DONE: ;
|
2015-06-23 18:57:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|