Convert CUE_File.Command.* to readonly structs with a superinterface

This commit is contained in:
YoshiRulz 2021-01-02 20:05:06 +10:00
parent 277f57eebd
commit 84a6c5a426
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
3 changed files with 213 additions and 93 deletions

View File

@ -412,64 +412,54 @@ namespace BizHawk.Emulation.DiscSystem.CUE
//global cd text will acquire the cdtext commands set before track commands
curr_cdtext = OUT_GlobalCDText;
for (int i = 0; i < cue.Commands.Count; i++)
foreach (var cmd in cue.Commands) switch (cmd)
{
var cmd = cue.Commands[i];
//these commands get dealt with globally. nothing to be done here
//(but in the future we need to accumulate them into the compile pass output)
if (cmd is CUE_File.Command.CATALOG || cmd is CUE_File.Command.CDTEXTFILE) continue;
//nothing to be done for comments
if (cmd is CUE_File.Command.REM) continue;
if (cmd is CUE_File.Command.COMMENT) continue;
//CD-text and related
if (cmd is CUE_File.Command.PERFORMER performerCmd) curr_cdtext.Performer = performerCmd.Value;
if (cmd is CUE_File.Command.SONGWRITER songwriterCmd) curr_cdtext.Songwriter = songwriterCmd.Value;
if (cmd is CUE_File.Command.TITLE titleCmd) curr_cdtext.Title = titleCmd.Value;
if (cmd is CUE_File.Command.ISRC isrcCmd) curr_cdtext.ISRC = isrcCmd.Value;
//flags can only be set when a track command is running
if (cmd is CUE_File.Command.FLAGS flagsCmd)
{
if (curr_track == null)
Warn("Ignoring invalid flag commands outside of a track command");
else
//take care to |= it here, so the data flag doesn't get cleared
curr_track.Flags |= flagsCmd.Flags;
}
if (cmd is CUE_File.Command.TRACK trackCmd)
{
case CUE_File.Command.CATALOG:
case CUE_File.Command.CDTEXTFILE:
// these commands get dealt with globally. nothing to be done here
// (but in the future we need to accumulate them into the compile pass output)
continue;
case CUE_File.Command.REM:
case CUE_File.Command.COMMENT:
// nothing to be done for comments
continue;
case CUE_File.Command.PERFORMER performerCmd:
curr_cdtext.Performer = performerCmd.Value;
break;
case CUE_File.Command.SONGWRITER songwriterCmd:
curr_cdtext.Songwriter = songwriterCmd.Value;
break;
case CUE_File.Command.TITLE titleCmd:
curr_cdtext.Title = titleCmd.Value;
break;
case CUE_File.Command.ISRC isrcCmd:
curr_cdtext.ISRC = isrcCmd.Value;
break;
case CUE_File.Command.FLAGS flagsCmd:
// flags can only be set when a track command is running
if (curr_track == null) Warn("Ignoring invalid flag commands outside of a track command");
else curr_track.Flags |= flagsCmd.Flags; // take care to |= it here, so the data flag doesn't get cleared
break;
case CUE_File.Command.TRACK trackCmd:
CloseTrack();
OpenTrack(trackCmd);
}
if (cmd is CUE_File.Command.FILE fileCmd)
{
break;
case CUE_File.Command.FILE fileCmd:
CloseFile();
OpenFile(fileCmd);
}
if (cmd is CUE_File.Command.INDEX indexCmd)
{
//todo - validate no postgap specified
break;
case CUE_File.Command.INDEX indexCmd:
//TODO validate no postgap specified
AddIndex(indexCmd);
}
if (cmd is CUE_File.Command.PREGAP pregapCmd)
{
//validate track open
//validate no indexes
break;
case CUE_File.Command.PREGAP pregapCmd:
//TODO validate track open
//TODO validate no indexes
curr_track.PregapLength = pregapCmd.Length;
}
if (cmd is CUE_File.Command.POSTGAP postgapCmd)
{
break;
case CUE_File.Command.POSTGAP postgapCmd:
curr_track.PostgapLength = postgapCmd.Length;
}
break;
}
//it's a bit odd to close the file before closing the track, but...

View File

@ -7,41 +7,171 @@ namespace BizHawk.Emulation.DiscSystem.CUE
/// </summary>
internal class CUE_File
{
// (here are all the commands we can encounter)
public static class Command
/// <remarks>
/// (here are all the commands we can encounter)
/// TODO record line number origin of command? Kind of nice but unessential
/// </remarks>
public interface Command
{
//TODO - record line number origin of command? Kind of nice but inessential
public class CATALOG { public string Value; public override string ToString() { return $"CATALOG: {Value}"; } }
public class CDTEXTFILE { public string Path; public override string ToString() { return $"CDTEXTFILE: {Path}"; } }
public class FILE { public string Path; public CueFileType Type; public override string ToString() { return $"FILE ({Type}): {Path}"; } }
public class FLAGS { public CueTrackFlags Flags; public override string ToString() { return $"FLAGS {Flags}"; } }
public class INDEX { public int Number; public Timestamp Timestamp; public override string ToString() { return $"INDEX {Number,2} {Timestamp}"; } }
public class ISRC { public string Value; public override string ToString() { return $"ISRC: {Value}"; } }
public class PERFORMER { public string Value; public override string ToString() { return $"PERFORMER: {Value}"; } }
public class POSTGAP { public Timestamp Length; public override string ToString() { return $"POSTGAP: {Length}"; } }
public class PREGAP { public Timestamp Length; public override string ToString() { return $"PREGAP: {Length}"; } }
public class REM { public string Value; public override string ToString() { return $"REM: {Value}"; } }
public class COMMENT { public string Value; public override string ToString() { return $"COMMENT: {Value}"; } }
public class SONGWRITER { public string Value; public override string ToString() { return $"SONGWRITER: {Value}"; } }
public class TITLE { public string Value; public override string ToString() { return $"TITLE: {Value}"; } }
public class TRACK { public int Number; public CueTrackType Type; public override string ToString() { return $"TRACK {Number,2} ({Type})"; } }
}
public readonly struct CATALOG : Command
{
public readonly string Value;
public CATALOG(string value) => Value = value;
public override readonly string ToString() => $"CATALOG: {Value}";
}
public readonly struct CDTEXTFILE : Command
{
public readonly string Path;
public CDTEXTFILE(string path) => Path = path;
public override readonly string ToString() => $"CDTEXTFILE: {Path}";
}
public readonly struct FILE : Command
{
public readonly string Path;
public readonly CueFileType Type;
public FILE(string path, CueFileType type)
{
Path = path;
Type = type;
}
public override readonly string ToString() => $"FILE ({Type}): {Path}";
}
public readonly struct FLAGS : Command
{
public readonly CueTrackFlags Flags;
public FLAGS(CueTrackFlags flags) => Flags = flags;
public override readonly string ToString() => $"FLAGS {Flags}";
}
public readonly struct INDEX : Command
{
public readonly int Number;
public readonly Timestamp Timestamp;
public INDEX(int number, Timestamp timestamp)
{
Number = number;
Timestamp = timestamp;
}
public override readonly string ToString() => $"INDEX {Number,2} {Timestamp}";
}
public readonly struct ISRC : Command
{
public readonly string Value;
public ISRC(string value) => Value = value;
public override readonly string ToString() => $"ISRC: {Value}";
}
public readonly struct PERFORMER : Command
{
public readonly string Value;
public PERFORMER(string value) => Value = value;
public override readonly string ToString() => $"PERFORMER: {Value}";
}
public readonly struct POSTGAP : Command
{
public readonly Timestamp Length;
public POSTGAP(Timestamp length) => Length = length;
public override readonly string ToString() => $"POSTGAP: {Length}";
}
public readonly struct PREGAP : Command
{
public readonly Timestamp Length;
public PREGAP(Timestamp length) => Length = length;
public override readonly string ToString() => $"PREGAP: {Length}";
}
public readonly struct REM : Command
{
public readonly string Value;
public REM(string value) => Value = value;
public override readonly string ToString() => $"REM: {Value}";
}
public readonly struct COMMENT : Command
{
public readonly string Value;
public COMMENT(string value) => Value = value;
public override readonly string ToString() => $"COMMENT: {Value}";
}
public readonly struct SONGWRITER : Command
{
public readonly string Value;
public SONGWRITER(string value) => Value = value;
public override readonly string ToString() => $"SONGWRITER: {Value}";
}
public readonly struct TITLE : Command
{
public readonly string Value;
public TITLE(string value) => Value = value;
public override readonly string ToString() => $"TITLE: {Value}";
}
public readonly struct TRACK : Command
{
public readonly int Number;
public readonly CueTrackType Type;
public TRACK(int number, CueTrackType type)
{
Number = number;
Type = type;
}
public override readonly string ToString() => $"TRACK {Number,2} ({Type})";
}
}
/// <summary>
/// Stuff other than the commands, global for the whole disc
/// </summary>
public class DiscInfo
{
public Command.CATALOG Catalog;
public Command.ISRC ISRC;
public Command.CDTEXTFILE CDTextFile;
public Command.CATALOG? Catalog;
public Command.ISRC? ISRC;
public Command.CDTEXTFILE? CDTextFile;
}
/// <summary>
/// The sequential list of commands parsed out of the cue file
/// </summary>
public List<object> Commands = new List<object>();
public readonly List<Command> Commands = new();
/// <summary>
/// Stuff other than the commands, global for the whole disc

View File

@ -162,7 +162,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE
if (startsWithSemicolon)
{
clp.EOF = true;
OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT() { Value = line });
OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT(line));
}
else switch (key)
{
@ -175,7 +175,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE
job.Warn("Multiple CATALOG commands detected. Subsequent ones are ignored.");
else if (clp.EOF)
job.Warn("Ignoring empty CATALOG command");
else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.Catalog = new CUE_File.Command.CATALOG() { Value = clp.ReadToken() });
else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.Catalog = new CUE_File.Command.CATALOG(clp.ReadToken()));
break;
case "CDTEXTFILE":
@ -183,7 +183,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE
job.Warn("Multiple CDTEXTFILE commands detected. Subsequent ones are ignored.");
else if (clp.EOF)
job.Warn("Ignoring empty CDTEXTFILE command");
else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.CDTextFile = new CUE_File.Command.CDTEXTFILE() { Path = clp.ReadPath() });
else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.CDTextFile = new CUE_File.Command.CDTEXTFILE(clp.ReadPath()));
break;
case "FILE":
@ -211,14 +211,13 @@ namespace BizHawk.Emulation.DiscSystem.CUE
case "MP3": ft = CueFileType.MP3; break;
}
}
OUT_CueFile.Commands.Add(new CUE_File.Command.FILE() { Path = path, Type = ft });
OUT_CueFile.Commands.Add(new CUE_File.Command.FILE(path, ft));
}
break;
case "FLAGS":
{
var cmd = new CUE_File.Command.FLAGS();
OUT_CueFile.Commands.Add(cmd);
CueTrackFlags flags = default;
while (!clp.EOF)
{
var flag = clp.ReadToken().ToUpperInvariant();
@ -228,14 +227,15 @@ namespace BizHawk.Emulation.DiscSystem.CUE
default:
job.Warn($"Unknown FLAG: {flag}");
break;
case "DCP": cmd.Flags |= CueTrackFlags.DCP; break;
case "4CH": cmd.Flags |= CueTrackFlags._4CH; break;
case "PRE": cmd.Flags |= CueTrackFlags.PRE; break;
case "SCMS": cmd.Flags |= CueTrackFlags.SCMS; break;
case "DCP": flags |= CueTrackFlags.DCP; break;
case "4CH": flags |= CueTrackFlags._4CH; break;
case "PRE": flags |= CueTrackFlags.PRE; break;
case "SCMS": flags |= CueTrackFlags.SCMS; break;
}
}
if (cmd.Flags == CueTrackFlags.None)
if (flags == CueTrackFlags.None)
job.Warn("Empty FLAG command");
OUT_CueFile.Commands.Add(new CUE_File.Command.FLAGS(flags));
}
break;
@ -266,7 +266,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE
job.Error($"Invalid INDEX timestamp: {str_timestamp}");
break;
}
OUT_CueFile.Commands.Add(new CUE_File.Command.INDEX() { Number = indexnum, Timestamp = ts });
OUT_CueFile.Commands.Add(new CUE_File.Command.INDEX(indexnum, ts));
}
break;
@ -282,13 +282,13 @@ namespace BizHawk.Emulation.DiscSystem.CUE
job.Warn($"Invalid ISRC code ignored: {isrc}");
else
{
OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.ISRC = new CUE_File.Command.ISRC() { Value = isrc });
OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.ISRC = new CUE_File.Command.ISRC(isrc));
}
}
break;
case "PERFORMER":
OUT_CueFile.Commands.Add(new CUE_File.Command.PERFORMER() { Value = clp.ReadPath() ?? "" });
OUT_CueFile.Commands.Add(new CUE_File.Command.PERFORMER(clp.ReadPath() ?? ""));
break;
case "POSTGAP":
@ -301,23 +301,23 @@ namespace BizHawk.Emulation.DiscSystem.CUE
else
{
if (key == "POSTGAP")
OUT_CueFile.Commands.Add(new CUE_File.Command.POSTGAP() { Length = msf });
OUT_CueFile.Commands.Add(new CUE_File.Command.POSTGAP(msf));
else
OUT_CueFile.Commands.Add(new CUE_File.Command.PREGAP() { Length = msf });
OUT_CueFile.Commands.Add(new CUE_File.Command.PREGAP(msf));
}
}
break;
case "REM":
OUT_CueFile.Commands.Add(new CUE_File.Command.REM() { Value = clp.ReadLine() });
OUT_CueFile.Commands.Add(new CUE_File.Command.REM(clp.ReadLine()));
break;
case "SONGWRITER":
OUT_CueFile.Commands.Add(new CUE_File.Command.SONGWRITER() { Value = clp.ReadPath() ?? "" });
OUT_CueFile.Commands.Add(new CUE_File.Command.SONGWRITER(clp.ReadPath() ?? ""));
break;
case "TITLE":
OUT_CueFile.Commands.Add(new CUE_File.Command.TITLE() { Value = clp.ReadPath() ?? "" });
OUT_CueFile.Commands.Add(new CUE_File.Command.TITLE(clp.ReadPath() ?? ""));
break;
case "TRACK":
@ -355,7 +355,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE
case "CDI/2352": tt = CueTrackType.CDI_2352; break;
}
OUT_CueFile.Commands.Add(new CUE_File.Command.TRACK() { Number = tracknum, Type = tt });
OUT_CueFile.Commands.Add(new CUE_File.Command.TRACK(tracknum, tt));
}
break;
}
@ -366,7 +366,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE
if (remainder.TrimStart().StartsWith(";"))
{
//add a comment
OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT() { Value = remainder });
OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT(remainder));
}
else job.Warn($"Unknown text at end of line after processing command: {key}");
}