From ab5869331bb912eb228b01dc5fd934706a26121d Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 3 Jun 2021 21:58:52 -0700 Subject: [PATCH] Add throwability to cuesheet code --- MPF.Library/CueSheets/CueFile.cs | 55 +++++++++++-- MPF.Library/CueSheets/CueIndex.cs | 83 ++++++++++++++++--- MPF.Library/CueSheets/CueSheet.cs | 71 +++++++++++++--- MPF.Library/CueSheets/CueTrack.cs | 132 +++++++++++++++++++++++++----- MPF.Library/CueSheets/PostGap.cs | 69 +++++++++++++--- MPF.Library/CueSheets/PreGap.cs | 69 +++++++++++++--- 6 files changed, 403 insertions(+), 76 deletions(-) diff --git a/MPF.Library/CueSheets/CueFile.cs b/MPF.Library/CueSheets/CueFile.cs index c211b455..afa8d2d2 100644 --- a/MPF.Library/CueSheets/CueFile.cs +++ b/MPF.Library/CueSheets/CueFile.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; /// @@ -71,10 +72,23 @@ namespace MPF.CueSheets /// File type to set /// Lines array to pull from /// Reference to index in array - public CueFile(string fileName, string fileType, string[] cueLines, ref int i) + /// True if errors throw an exception, false otherwise + public CueFile(string fileName, string fileType, string[] cueLines, ref int i, bool throwOnError = false) { - if (cueLines == null || i < 0 || i > cueLines.Length) - return; // TODO: Make this throw an exception + if (cueLines == null) + { + if (throwOnError) + throw new ArgumentNullException(nameof(cueLines)); + + return; + } + else if (i < 0 || i > cueLines.Length) + { + if (throwOnError) + throw new IndexOutOfRangeException(); + + return; + } // Set the current fields this.FileName = fileName.Trim('"'); @@ -102,14 +116,24 @@ namespace MPF.CueSheets // Read track information case "TRACK": if (splitLine.Length < 3) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"TRACK line malformed: {line}"); + + continue; + } if (this.Tracks == null) this.Tracks = new List(); var track = new CueTrack(splitLine[1], splitLine[2], cueLines, ref i); if (track == default) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"TRACK line malformed: {line}"); + + continue; + } this.Tracks.Add(track); break; @@ -126,11 +150,24 @@ namespace MPF.CueSheets /// Write the FILE out to a stream /// /// StreamWriter to write to - public void Write(StreamWriter sw) + /// True if errors throw an exception, false otherwise + public void Write(StreamWriter sw, bool throwOnError = false) { // If we don't have any tracks, it's invalid - if (this.Tracks == null || this.Tracks.Count == 0) - return; // TODO: Make this throw an exception + if (this.Tracks == null) + { + if (throwOnError) + throw new ArgumentNullException(nameof(this.Tracks)); + + return; + } + else if (this.Tracks.Count == 0) + { + if (throwOnError) + throw new ArgumentException("No tracks provided to write"); + + return; + } sw.WriteLine($"FILE \"{this.FileName}\" {FromFileType(this.FileType)}"); diff --git a/MPF.Library/CueSheets/CueIndex.cs b/MPF.Library/CueSheets/CueIndex.cs index 9bda23ba..8a6a52d9 100644 --- a/MPF.Library/CueSheets/CueIndex.cs +++ b/MPF.Library/CueSheets/CueIndex.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; /// @@ -45,47 +46,103 @@ namespace MPF.CueSheets /// /// Index to set /// Start time to set - public CueIndex(string index, string startTime) + /// True if errors throw an exception, false otherwise + public CueIndex(string index, string startTime, bool throwOnError = false) { // Set the current fields if (!int.TryParse(index, out int parsedIndex)) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new ArgumentException($"Index was not a number: {index}"); + + return; + } else if (parsedIndex < 0 || parsedIndex > 99) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Index must be between 0 and 99: {parsedIndex}"); + + return; + } // Ignore empty lines if (string.IsNullOrWhiteSpace(startTime)) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new ArgumentException("Start time was null or whitespace"); + + return; + } // Ignore lines that don't contain the correct information if (startTime.Length != 8 || startTime.Count(c => c == ':') != 2) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Start time was not in a recognized format: {startTime}"); + + return; + } // Split the line string[] splitTime = startTime.Split(':'); if (splitTime.Length != 3) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Start time was not in a recognized format: {startTime}"); + + return; + } // Parse the lengths int[] lengthSegments = new int[3]; // Minutes if (!int.TryParse(splitTime[0], out lengthSegments[0])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Minutes segment was not a number: {splitTime[0]}"); + + return; + } else if (lengthSegments[0] < 0) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}"); + + return; + } // Seconds if (!int.TryParse(splitTime[1], out lengthSegments[1])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Seconds segment was not a number: {splitTime[1]}"); + + return; + } else if (lengthSegments[1] < 0 || lengthSegments[1] > 60) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}"); + + return; + } // Frames if (!int.TryParse(splitTime[2], out lengthSegments[2])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Frames segment was not a number: {splitTime[2]}"); + + return; + } else if (lengthSegments[2] < 0 || lengthSegments[2] > 75) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}"); + + return; + } // Set the values this.Index = parsedIndex; diff --git a/MPF.Library/CueSheets/CueSheet.cs b/MPF.Library/CueSheets/CueSheet.cs index 1bd7022a..4df49700 100644 --- a/MPF.Library/CueSheets/CueSheet.cs +++ b/MPF.Library/CueSheets/CueSheet.cs @@ -56,7 +56,8 @@ namespace MPF.CueSheets /// Create a cuesheet from a file, if possible /// /// - public CueSheet(string filename) + /// True if errors throw an exception, false otherwise + public CueSheet(string filename, bool throwOnError = false) { // Check that the file exists if (!File.Exists(filename)) @@ -97,7 +98,12 @@ namespace MPF.CueSheets // Read MCN case "CATALOG": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"CATALOG line malformed: {line}"); + + continue; + } this.Catalog = splitLine[1]; break; @@ -105,7 +111,12 @@ namespace MPF.CueSheets // Read external CD-Text file path case "CDTEXTFILE": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"CDTEXTFILE line malformed: {line}"); + + continue; + } this.CdTextFile = splitLine[1]; break; @@ -113,7 +124,12 @@ namespace MPF.CueSheets // Read CD-Text enhanced performer case "PERFORMER": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"PERFORMER line malformed: {line}"); + + continue; + } this.Performer = splitLine[1]; break; @@ -121,7 +137,12 @@ namespace MPF.CueSheets // Read CD-Text enhanced songwriter case "SONGWRITER": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"SONGWRITER line malformed: {line}"); + + continue; + } this.Songwriter = splitLine[1]; break; @@ -129,7 +150,12 @@ namespace MPF.CueSheets // Read CD-Text enhanced title case "TITLE": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"TITLE line malformed: {line}"); + + continue; + } this.Title = splitLine[1]; break; @@ -137,14 +163,24 @@ namespace MPF.CueSheets // Read file information case "FILE": if (splitLine.Length < 3) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"FILE line malformed: {line}"); + + continue; + } if (this.Files == null) this.Files = new List(); var file = new CueFile(splitLine[1], splitLine[2], cueLines, ref i); if (file == default) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"FILE line malformed: {line}"); + + continue; + } this.Files.Add(file); break; @@ -168,11 +204,24 @@ namespace MPF.CueSheets /// Write the cuesheet out to a stream /// /// Stream to write to - public void Write(Stream stream) + /// True if errors throw an exception, false otherwise + public void Write(Stream stream, bool throwOnError = false) { // If we don't have any files, it's invalid - if (this.Files == null || this.Files.Count == 0) - return; // TODO: Make this throw an exception + if (this.Files == null) + { + if (throwOnError) + throw new ArgumentNullException(nameof(this.Files)); + + return; + } + else if (this.Files.Count == 0) + { + if (throwOnError) + throw new ArgumentException("No files provided to write"); + + return; + } using (var sw = new StreamWriter(stream, Encoding.ASCII, 1024, true)) { diff --git a/MPF.Library/CueSheets/CueTrack.cs b/MPF.Library/CueSheets/CueTrack.cs index a5b29b3e..9414ab49 100644 --- a/MPF.Library/CueSheets/CueTrack.cs +++ b/MPF.Library/CueSheets/CueTrack.cs @@ -156,16 +156,39 @@ namespace MPF.CueSheets /// Data type to set /// Lines array to pull from /// Reference to index in array - public CueTrack(string number, string dataType, string[] cueLines, ref int i) + /// True if errors throw an exception, false otherwise + public CueTrack(string number, string dataType, string[] cueLines, ref int i, bool throwOnError = false) { - if (cueLines == null || i < 0 || i > cueLines.Length) - return; // TODO: Make this throw an exception + if (cueLines == null) + { + if (throwOnError) + throw new ArgumentNullException(nameof(cueLines)); + + return; + } + else if (i < 0 || i > cueLines.Length) + { + if (throwOnError) + throw new IndexOutOfRangeException(); + + return; + } // Set the current fields if (!int.TryParse(number, out int parsedNumber)) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new ArgumentException($"Number was not a number: {number}"); + + return; + } else if (parsedNumber < 1 || parsedNumber > 99) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Index must be between 1 and 99: {parsedNumber}"); + + return; + } this.Number = parsedNumber; this.DataType = GetDataType(dataType); @@ -192,7 +215,12 @@ namespace MPF.CueSheets // Read flag information case "FLAGS": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"FLAGS line malformed: {line}"); + + continue; + } this.Flags = GetFlags(splitLine); break; @@ -200,7 +228,12 @@ namespace MPF.CueSheets // Read International Standard Recording Code case "ISRC": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"ISRC line malformed: {line}"); + + continue; + } this.ISRC = splitLine[1]; break; @@ -208,7 +241,12 @@ namespace MPF.CueSheets // Read CD-Text enhanced performer case "PERFORMER": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"PERFORMER line malformed: {line}"); + + continue; + } this.Performer = splitLine[1]; break; @@ -216,7 +254,12 @@ namespace MPF.CueSheets // Read CD-Text enhanced songwriter case "SONGWRITER": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"SONGWRITER line malformed: {line}"); + + continue; + } this.Songwriter = splitLine[1]; break; @@ -224,7 +267,12 @@ namespace MPF.CueSheets // Read CD-Text enhanced title case "TITLE": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"TITLE line malformed: {line}"); + + continue; + } this.Title = splitLine[1]; break; @@ -232,11 +280,21 @@ namespace MPF.CueSheets // Read pregap information case "PREGAP": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"PREGAP line malformed: {line}"); + + continue; + } var pregap = new PreGap(splitLine[1]); if (pregap == default) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"PREGAP line malformed: {line}"); + + continue; + } this.PreGap = pregap; break; @@ -244,14 +302,24 @@ namespace MPF.CueSheets // Read index information case "INDEX": if (splitLine.Length < 3) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"INDEX line malformed: {line}"); + + continue; + } if (this.Indices == null) this.Indices = new List(); var index = new CueIndex(splitLine[1], splitLine[2]); if (index == default) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"INDEX line malformed: {line}"); + + continue; + } this.Indices.Add(index); break; @@ -259,11 +327,21 @@ namespace MPF.CueSheets // Read postgap information case "POSTGAP": if (splitLine.Length < 2) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"POSTGAP line malformed: {line}"); + + continue; + } var postgap = new PostGap(splitLine[1]); if (postgap == default) - continue; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"POSTGAP line malformed: {line}"); + + continue; + } this.PostGap = postgap; break; @@ -279,12 +357,25 @@ namespace MPF.CueSheets /// /// Write the TRACK out to a stream /// - /// StreamWriter to write to - public void Write(StreamWriter sw) + /// StreamWriter to write toTrue if errors throw an exception, false otherwise + public void Write(StreamWriter sw, bool throwOnError = false) { // If we don't have any indices, it's invalid - if (this.Indices == null || this.Indices.Count == 0) - return; // TODO: Make this throw an exception + if (this.Indices == null) + { + if (throwOnError) + throw new ArgumentNullException(nameof(this.Indices)); + + return; + } + else if (this.Indices.Count == 0) + { + if (throwOnError) + throw new ArgumentException("No indices provided to write"); + + return; + } sw.WriteLine($" TRACK {this.Number:D2} {FromDataType(this.DataType)}"); @@ -402,7 +493,6 @@ namespace MPF.CueSheets foreach (string flagString in flagStrings) { - // TODO: Make default throw an exception switch (flagString.ToLowerInvariant()) { case "flags": diff --git a/MPF.Library/CueSheets/PostGap.cs b/MPF.Library/CueSheets/PostGap.cs index 7a1e1800..c0e9b7c1 100644 --- a/MPF.Library/CueSheets/PostGap.cs +++ b/MPF.Library/CueSheets/PostGap.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; /// @@ -38,41 +39,87 @@ namespace MPF.CueSheets /// Create a POSTGAP from a mm:ss:ff length /// /// String to get length information from - public PostGap(string length) + /// True if errors throw an exception, false otherwise + public PostGap(string length, bool throwOnError = false) { // Ignore empty lines if (string.IsNullOrWhiteSpace(length)) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new ArgumentException("Length was null or whitespace"); + + return; + } // Ignore lines that don't contain the correct information if (length.Length != 8 || length.Count(c => c == ':') != 2) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Length was not in a recognized format: {length}"); + + return; + } // Split the line string[] splitLength = length.Split(':'); if (splitLength.Length != 3) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Length was not in a recognized format: {length}"); + + return; + } // Parse the lengths int[] lengthSegments = new int[3]; // Minutes if (!int.TryParse(splitLength[0], out lengthSegments[0])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Minutes segment was not a number: {splitLength[0]}"); + + return; + } else if (lengthSegments[0] < 0) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}"); + + return; + } // Seconds if (!int.TryParse(splitLength[1], out lengthSegments[1])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Seconds segment was not a number: {splitLength[1]}"); + + return; + } else if (lengthSegments[1] < 0 || lengthSegments[1] > 60) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}"); + + return; + } // Frames if (!int.TryParse(splitLength[2], out lengthSegments[2])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Frames segment was not a number: {splitLength[2]}"); + + return; + } else if (lengthSegments[2] < 0 || lengthSegments[2] > 75) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}"); + + return; + } // Set the values this.Minutes = lengthSegments[0]; diff --git a/MPF.Library/CueSheets/PreGap.cs b/MPF.Library/CueSheets/PreGap.cs index 5c54e77f..803bc5c5 100644 --- a/MPF.Library/CueSheets/PreGap.cs +++ b/MPF.Library/CueSheets/PreGap.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; /// @@ -39,41 +40,87 @@ namespace MPF.CueSheets /// Create a PREGAP from a mm:ss:ff length /// /// String to get length information from - public PreGap(string length) + /// True if errors throw an exception, false otherwise + public PreGap(string length, bool throwOnError = false) { // Ignore empty lines if (string.IsNullOrWhiteSpace(length)) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new ArgumentException("Length was null or whitespace"); + + return; + } // Ignore lines that don't contain the correct information if (length.Length != 8 || length.Count(c => c == ':') != 2) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Length was not in a recognized format: {length}"); + + return; + } // Split the line string[] splitLength = length.Split(':'); if (splitLength.Length != 3) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Length was not in a recognized format: {length}"); + + return; + } // Parse the lengths int[] lengthSegments = new int[3]; // Minutes if (!int.TryParse(splitLength[0], out lengthSegments[0])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Minutes segment was not a number: {splitLength[0]}"); + + return; + } else if (lengthSegments[0] < 0) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}"); + + return; + } // Seconds if (!int.TryParse(splitLength[1], out lengthSegments[1])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Seconds segment was not a number: {splitLength[1]}"); + + return; + } else if (lengthSegments[1] < 0 || lengthSegments[1] > 60) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}"); + + return; + } // Frames if (!int.TryParse(splitLength[2], out lengthSegments[2])) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new FormatException($"Frames segment was not a number: {splitLength[2]}"); + + return; + } else if (lengthSegments[2] < 0 || lengthSegments[2] > 75) - return; // TODO: Make this throw an exception + { + if (throwOnError) + throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}"); + + return; + } // Set the values this.Minutes = lengthSegments[0];