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 //global cd text will acquire the cdtext commands set before track commands
curr_cdtext = OUT_GlobalCDText; 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]; case CUE_File.Command.CATALOG:
case CUE_File.Command.CDTEXTFILE:
//these commands get dealt with globally. nothing to be done here // 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) // (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; continue;
case CUE_File.Command.REM:
//nothing to be done for comments case CUE_File.Command.COMMENT:
if (cmd is CUE_File.Command.REM) continue; // nothing to be done for comments
if (cmd is CUE_File.Command.COMMENT) continue; continue;
case CUE_File.Command.PERFORMER performerCmd:
//CD-text and related curr_cdtext.Performer = performerCmd.Value;
if (cmd is CUE_File.Command.PERFORMER performerCmd) curr_cdtext.Performer = performerCmd.Value; break;
if (cmd is CUE_File.Command.SONGWRITER songwriterCmd) curr_cdtext.Songwriter = songwriterCmd.Value; case CUE_File.Command.SONGWRITER songwriterCmd:
if (cmd is CUE_File.Command.TITLE titleCmd) curr_cdtext.Title = titleCmd.Value; curr_cdtext.Songwriter = songwriterCmd.Value;
if (cmd is CUE_File.Command.ISRC isrcCmd) curr_cdtext.ISRC = isrcCmd.Value; break;
case CUE_File.Command.TITLE titleCmd:
//flags can only be set when a track command is running curr_cdtext.Title = titleCmd.Value;
if (cmd is CUE_File.Command.FLAGS flagsCmd) break;
{ case CUE_File.Command.ISRC isrcCmd:
if (curr_track == null) curr_cdtext.ISRC = isrcCmd.Value;
Warn("Ignoring invalid flag commands outside of a track command"); break;
else case CUE_File.Command.FLAGS flagsCmd:
//take care to |= it here, so the data flag doesn't get cleared // flags can only be set when a track command is running
curr_track.Flags |= flagsCmd.Flags; 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;
if (cmd is CUE_File.Command.TRACK trackCmd) case CUE_File.Command.TRACK trackCmd:
{
CloseTrack(); CloseTrack();
OpenTrack(trackCmd); OpenTrack(trackCmd);
} break;
case CUE_File.Command.FILE fileCmd:
if (cmd is CUE_File.Command.FILE fileCmd)
{
CloseFile(); CloseFile();
OpenFile(fileCmd); OpenFile(fileCmd);
} break;
case CUE_File.Command.INDEX indexCmd:
if (cmd is CUE_File.Command.INDEX indexCmd) //TODO validate no postgap specified
{
//todo - validate no postgap specified
AddIndex(indexCmd); AddIndex(indexCmd);
} break;
case CUE_File.Command.PREGAP pregapCmd:
if (cmd is CUE_File.Command.PREGAP pregapCmd) //TODO validate track open
{ //TODO validate no indexes
//validate track open
//validate no indexes
curr_track.PregapLength = pregapCmd.Length; curr_track.PregapLength = pregapCmd.Length;
} break;
case CUE_File.Command.POSTGAP postgapCmd:
if (cmd is CUE_File.Command.POSTGAP postgapCmd)
{
curr_track.PostgapLength = postgapCmd.Length; curr_track.PostgapLength = postgapCmd.Length;
} break;
} }
//it's a bit odd to close the file before closing the track, but... //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> /// </summary>
internal class CUE_File internal class CUE_File
{ {
// (here are all the commands we can encounter) /// <remarks>
public static class Command /// (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 readonly struct CATALOG : Command
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 readonly string Value;
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 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> /// <summary>
/// Stuff other than the commands, global for the whole disc /// Stuff other than the commands, global for the whole disc
/// </summary> /// </summary>
public class DiscInfo public class DiscInfo
{ {
public Command.CATALOG Catalog; public Command.CATALOG? Catalog;
public Command.ISRC ISRC; public Command.ISRC? ISRC;
public Command.CDTEXTFILE CDTextFile; public Command.CDTEXTFILE? CDTextFile;
} }
/// <summary> /// <summary>
/// The sequential list of commands parsed out of the cue file /// The sequential list of commands parsed out of the cue file
/// </summary> /// </summary>
public List<object> Commands = new List<object>(); public readonly List<Command> Commands = new();
/// <summary> /// <summary>
/// Stuff other than the commands, global for the whole disc /// Stuff other than the commands, global for the whole disc

View File

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