From db7dd3d353e1707772f1d405870219ed7d62584a Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sat, 29 Jul 2023 00:06:31 -0400 Subject: [PATCH] Create and use AttractMode serializer --- .../Formats/AttractMode.Reader.cs | 111 ++++++++ .../Formats/AttractMode.Writer.cs | 143 ++++++++++ SabreTools.DatFiles/Formats/AttractMode.cs | 253 +----------------- .../Formats/ClrMamePro.Reader.cs | 2 - SabreTools.Models/AttractMode/Row.cs | 42 +-- .../AttractMode.Deserializer.cs | 140 ++++++++++ .../AttractMode.Serializer.cs | 114 ++++++++ SabreTools.Serialization/AttractMode.cs | 136 +--------- 8 files changed, 534 insertions(+), 407 deletions(-) create mode 100644 SabreTools.DatFiles/Formats/AttractMode.Reader.cs create mode 100644 SabreTools.DatFiles/Formats/AttractMode.Writer.cs create mode 100644 SabreTools.Serialization/AttractMode.Deserializer.cs create mode 100644 SabreTools.Serialization/AttractMode.Serializer.cs diff --git a/SabreTools.DatFiles/Formats/AttractMode.Reader.cs b/SabreTools.DatFiles/Formats/AttractMode.Reader.cs new file mode 100644 index 00000000..526e6f2e --- /dev/null +++ b/SabreTools.DatFiles/Formats/AttractMode.Reader.cs @@ -0,0 +1,111 @@ +using System; +using System.Linq; +using SabreTools.Core; +using SabreTools.DatItems; +using SabreTools.DatItems.Formats; + +namespace SabreTools.DatFiles.Formats +{ + /// + /// Represents parsing of an AttractMode DAT + /// + internal partial class AttractMode : DatFile + { + /// + public override void ParseFile(string filename, int indexId, bool keep, bool statsOnly = false, bool throwOnError = false) + { + try + { + // Deserialize the input file + var metadataFile = Serialization.AttractMode.Deserialize(filename); + + // Convert the row data to the internal format + ConvertRows(metadataFile?.Row, filename, indexId, statsOnly); + } + catch (Exception ex) when (!throwOnError) + { + string message = $"'{filename}' - An error occurred during parsing"; + logger.Error(ex, message); + } + } + + #region Converters + + /// + /// Convert rows information + /// + /// Array of deserialized models to convert + /// Name of the file to be parsed + /// Index ID for the DAT + /// True to only add item statistics while parsing, false otherwise + private void ConvertRows(Models.AttractMode.Row[]? rows, string filename, int indexId, bool statsOnly) + { + // If the rows array is missing, we can't do anything + if (rows == null || !rows.Any()) + return; + + // Loop through the rows and add + foreach (var row in rows) + { + ConvertRow(row, filename, indexId, statsOnly); + } + } + + /// + /// Convert rows information + /// + /// Deserialized model to convert + /// Name of the file to be parsed + /// Index ID for the DAT + /// True to only add item statistics while parsing, false otherwise + private void ConvertRow(Models.AttractMode.Row? row, string filename, int indexId, bool statsOnly) + { + // If the row is missing, we can't do anything + if (row == null) + return; + + var rom = new Rom() + { + Name = "-", + Size = Constants.SizeZero, + CRC = Constants.CRCZero, + MD5 = Constants.MD5Zero, + SHA1 = Constants.SHA1Zero, + ItemStatus = ItemStatus.None, + + Machine = new Machine + { + Name = row.Name, + Description = row.Title, + CloneOf = row.CloneOf, + Year = row.Year, + Manufacturer = row.Manufacturer, + Category = row.Category, + Players = row.Players, + Rotation = row.Rotation, + Control = row.Control, + Status = row.Status, + DisplayCount = row.DisplayCount, + DisplayType = row.DisplayType, + Comment = row.Extra, + Buttons = row.Buttons + }, + + AltName = row.AltRomname, + AltTitle = row.AltTitle, + // TODO: Add extended fields + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + // Now process and add the rom + ParseAddHelper(rom, statsOnly); + } + + #endregion + } +} diff --git a/SabreTools.DatFiles/Formats/AttractMode.Writer.cs b/SabreTools.DatFiles/Formats/AttractMode.Writer.cs new file mode 100644 index 00000000..7b89fa16 --- /dev/null +++ b/SabreTools.DatFiles/Formats/AttractMode.Writer.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SabreTools.Core; +using SabreTools.DatItems; +using SabreTools.DatItems.Formats; + +namespace SabreTools.DatFiles.Formats +{ + /// + /// Represents parsing and writing of an AttractMode DAT + /// + internal partial class AttractMode : DatFile + { + /// + protected override ItemType[] GetSupportedTypes() + { + return new ItemType[] { ItemType.Rom }; + } + + /// + protected override List GetMissingRequiredFields(DatItem datItem) + { + List missingFields = new(); + + // Check item name + if (string.IsNullOrWhiteSpace(datItem.GetName())) + missingFields.Add(DatItemField.Name); + + return missingFields; + } + + /// + public override bool WriteToFile(string outfile, bool ignoreblanks = false, bool throwOnError = false) + { + try + { + logger.User($"Writing to '{outfile}'..."); + + var metadataFile = CreateMetadataFile(ignoreblanks); + if (!Serialization.AttractMode.SerializeToFile(metadataFile, outfile)) + { + logger.Warning($"File '{outfile}' could not be written! See the log for more details."); + return false; + } + } + catch (Exception ex) when (!throwOnError) + { + logger.Error(ex); + return false; + } + + return true; + } + + #region Converters + + /// + /// Create a MetadataFile from the current internal information + /// + /// True if blank roms should be skipped on output, false otherwise + private Models.AttractMode.MetadataFile CreateMetadataFile(bool ignoreblanks) + { + var metadataFile = new Models.AttractMode.MetadataFile + { + Row = CreateRows(ignoreblanks) + }; + return metadataFile; + } + + /// + /// Create an array of Row from the current internal information + /// + /// True if blank roms should be skipped on output, false otherwise + private Models.AttractMode.Row[]? CreateRows(bool ignoreblanks) + { + // If we don't have items, we can't do anything + if (this.Items == null || !this.Items.Any()) + return null; + + // Create a list of hold the rows + var rows = new List(); + + // Loop through the sorted items and create games for them + foreach (string key in Items.SortedKeys) + { + var items = Items.FilteredItems(key); + if (items == null || !items.Any()) + continue; + + // Loop through and convert the items to respective lists + foreach (var item in items) + { + // Skip if we're ignoring the item + if (ShouldIgnore(item, ignoreblanks)) + continue; + + switch (item) + { + case Rom rom: + rows.Add(CreateRow(rom)); + break; + } + } + } + + // TODO: Populate the games + + return rows.ToArray(); + } + + /// + /// Create a Row from the current Rom DatItem + /// + private Models.AttractMode.Row CreateRow(Rom rom) + { + var row = new Models.AttractMode.Row + { + Name = rom.Machine.Name, + Title = rom.Machine.Description, + Emulator = Header.FileName, + CloneOf = rom.Machine.CloneOf, + Year = rom.Machine.Year, + Manufacturer = rom.Machine.Manufacturer, + Category = rom.Machine.Category, + Players = rom.Machine.Players, + Rotation = rom.Machine.Rotation, + Control = rom.Machine.Control, + Status = rom.Machine.Status, + DisplayCount = rom.Machine.DisplayCount, + DisplayType = rom.Machine.DisplayType, + AltRomname = rom.AltName, + AltTitle = rom.AltTitle, + Extra = rom.Machine.Comment, + Buttons = rom.Machine.Buttons, + // TODO: Add extended fields + }; + return row; + } + + #endregion + } +} diff --git a/SabreTools.DatFiles/Formats/AttractMode.cs b/SabreTools.DatFiles/Formats/AttractMode.cs index 09e93f0c..cb13d77b 100644 --- a/SabreTools.DatFiles/Formats/AttractMode.cs +++ b/SabreTools.DatFiles/Formats/AttractMode.cs @@ -1,20 +1,9 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using SabreTools.Core; -using SabreTools.DatItems; -using SabreTools.DatItems.Formats; -using SabreTools.IO; -using SabreTools.IO.Readers; -using SabreTools.IO.Writers; - -namespace SabreTools.DatFiles.Formats +namespace SabreTools.DatFiles.Formats { /// - /// Represents parsing and writing of an AttractMode DAT + /// Represents an AttractMode DAT /// - internal class AttractMode : DatFile + internal partial class AttractMode : DatFile { /// /// Constructor designed for casting a base DatFile @@ -24,241 +13,5 @@ namespace SabreTools.DatFiles.Formats : base(datFile) { } - - /// - public override void ParseFile(string filename, int indexId, bool keep, bool statsOnly = false, bool throwOnError = false) - { - // Open a file reader - Encoding enc = filename.GetEncoding(); - SeparatedValueReader svr = new(System.IO.File.OpenRead(filename), enc) - { - Header = true, - Quotes = false, - Separator = ';', - VerifyFieldCount = true - }; - - // If we're somehow at the end of the stream already, we can't do anything - if (svr.EndOfStream) - return; - - // Read in the header - svr.ReadHeader(); - - // Header values should match - // #Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons - - // Loop through all of the data lines - while (!svr.EndOfStream) - { - try - { - // Get the current line, split and parse - svr.ReadNextLine(); - - Rom rom = new() - { - Name = "-", - Size = Constants.SizeZero, - CRC = Constants.CRCZero, - MD5 = Constants.MD5Zero, - SHA1 = Constants.SHA1Zero, - ItemStatus = ItemStatus.None, - - Machine = new Machine - { - Name = svr.Line[0], // #Name - Description = svr.Line[1], // Title - CloneOf = svr.Line[3], // CloneOf - Year = svr.Line[4], // Year - Manufacturer = svr.Line[5], // Manufacturer - Category = svr.Line[6], // Category - Players = svr.Line[7], // Players - Rotation = svr.Line[8], // Rotation - Control = svr.Line[9], // Control - Status = svr.Line[10], // Status - DisplayCount = svr.Line[11], // DisplayCount - DisplayType = svr.Line[12], // DisplayType - Comment = svr.Line[15], // Extra - Buttons = svr.Line[16], // Buttons - }, - - AltName = svr.Line[13], // AltRomname - AltTitle = svr.Line[14], // AltTitle - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - // Now process and add the rom - ParseAddHelper(rom, statsOnly); - } - catch (Exception ex) when (!throwOnError) - { - string message = $"'{filename}' - There was an error parsing line {svr.LineNumber} '{svr.CurrentLine}'"; - logger.Error(ex, message); - } - } - - svr.Dispose(); - } - - /// - protected override ItemType[] GetSupportedTypes() - { - return new ItemType[] { ItemType.Rom }; - } - - /// - protected override List GetMissingRequiredFields(DatItem datItem) - { - // TODO: Check required fields - return null; - } - - /// - public override bool WriteToFile(string outfile, bool ignoreblanks = false, bool throwOnError = false) - { - try - { - logger.User($"Writing to '{outfile}'..."); - FileStream fs = System.IO.File.Create(outfile); - - // If we get back null for some reason, just log and return - if (fs == null) - { - logger.Warning($"File '{outfile}' could not be created for writing! Please check to see if the file is writable"); - return false; - } - - SeparatedValueWriter svw = new(fs, new UTF8Encoding(false)) - { - Quotes = false, - Separator = ';', - VerifyFieldCount = true - }; - - // Write out the header - WriteHeader(svw); - - // Use a sorted list of games to output - foreach (string key in Items.SortedKeys) - { - ConcurrentList datItems = Items.FilteredItems(key); - - // If this machine doesn't contain any writable items, skip - if (!ContainsWritable(datItems)) - continue; - - // Resolve the names in the block - datItems = DatItem.ResolveNames(datItems); - - for (int index = 0; index < datItems.Count; index++) - { - DatItem datItem = datItems[index]; - - // Check for a "null" item - datItem = ProcessNullifiedItem(datItem); - - // Write out the item if we're not ignoring - if (!ShouldIgnore(datItem, ignoreblanks)) - WriteDatItem(svw, datItem); - } - } - - logger.User($"'{outfile}' written!{Environment.NewLine}"); - svw.Dispose(); - fs.Dispose(); - } - catch (Exception ex) when (!throwOnError) - { - logger.Error(ex); - return false; - } - - return true; - } - - /// - /// Write out DAT header using the supplied StreamWriter - /// - /// SeparatedValueWriter to output to - private void WriteHeader(SeparatedValueWriter svw) - { - string[] headers = new string[] - { - "#Name", - "Title", - "Emulator", - "CloneOf", - "Year", - "Manufacturer", - "Category", - "Players", - "Rotation", - "Control", - "Status", - "DisplayCount", - "DisplayType", - "AltRomname", - "AltTitle", - "Extra", - "Buttons", - }; - - svw.WriteHeader(headers); - - svw.Flush(); - } - - /// - /// Write out Game start using the supplied StreamWriter - /// - /// SeparatedValueWriter to output to - /// DatItem object to be output - /// True if the error that is thrown should be thrown back to the caller, false otherwise - private void WriteDatItem(SeparatedValueWriter svw, DatItem datItem) - { - // No game should start with a path separator - datItem.Machine.Name = datItem.Machine.Name.TrimStart(Path.DirectorySeparatorChar); - - // Pre-process the item name - ProcessItemName(datItem, true); - - // Build the state - switch (datItem.ItemType) - { - case ItemType.Rom: - var rom = datItem as Rom; - string[] fields = new string[] - { - rom.Machine.Name, - rom.Machine.Description, - Header.FileName, - rom.Machine.CloneOf, - rom.Machine.Year, - rom.Machine.Manufacturer, - rom.Machine.Category, - rom.Machine.Players, - rom.Machine.Rotation, - rom.Machine.Control, - rom.ItemStatus.ToString(), - rom.Machine.DisplayCount, - rom.Machine.DisplayType, - rom.AltName, - rom.AltTitle, - rom.Machine.Comment, - rom.Machine.Buttons, - }; - - svw.WriteValues(fields); - break; - } - - svw.Flush(); - } } } diff --git a/SabreTools.DatFiles/Formats/ClrMamePro.Reader.cs b/SabreTools.DatFiles/Formats/ClrMamePro.Reader.cs index 4e54dae0..83b83189 100644 --- a/SabreTools.DatFiles/Formats/ClrMamePro.Reader.cs +++ b/SabreTools.DatFiles/Formats/ClrMamePro.Reader.cs @@ -32,8 +32,6 @@ namespace SabreTools.DatFiles.Formats string message = $"'{filename}' - An error occurred during parsing"; logger.Error(ex, message); } - - return; } #region Converters diff --git a/SabreTools.Models/AttractMode/Row.cs b/SabreTools.Models/AttractMode/Row.cs index 278eede2..bf8d300e 100644 --- a/SabreTools.Models/AttractMode/Row.cs +++ b/SabreTools.Models/AttractMode/Row.cs @@ -5,47 +5,47 @@ namespace SabreTools.Models.AttractMode /// Also called Romname public string Name { get; set; } - public string Title { get; set; } + public string? Title { get; set; } - public string Emulator { get; set; } + public string? Emulator { get; set; } - public string CloneOf { get; set; } + public string? CloneOf { get; set; } - public string Year { get; set; } + public string? Year { get; set; } - public string Manufacturer { get; set; } + public string? Manufacturer { get; set; } - public string Category { get; set; } + public string? Category { get; set; } - public string Players { get; set; } + public string? Players { get; set; } - public string Rotation { get; set; } + public string? Rotation { get; set; } - public string Control { get; set; } + public string? Control { get; set; } - public string Status { get; set; } + public string? Status { get; set; } - public string DisplayCount { get; set; } + public string? DisplayCount { get; set; } - public string DisplayType { get; set; } + public string? DisplayType { get; set; } - public string AltRomname { get; set; } + public string? AltRomname { get; set; } - public string AltTitle { get; set; } + public string? AltTitle { get; set; } - public string Extra { get; set; } + public string? Extra { get; set; } - public string Buttons { get; set; } + public string? Buttons { get; set; } - public string Favorite { get; set; } + public string? Favorite { get; set; } - public string Tags { get; set; } + public string? Tags { get; set; } - public string PlayedCount { get; set; } + public string? PlayedCount { get; set; } - public string PlayedTime { get; set; } + public string? PlayedTime { get; set; } - public string FileIsAvailable { get; set; } + public string? FileIsAvailable { get; set; } #region DO NOT USE IN PRODUCTION diff --git a/SabreTools.Serialization/AttractMode.Deserializer.cs b/SabreTools.Serialization/AttractMode.Deserializer.cs new file mode 100644 index 00000000..39a8031c --- /dev/null +++ b/SabreTools.Serialization/AttractMode.Deserializer.cs @@ -0,0 +1,140 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using SabreTools.IO.Readers; +using SabreTools.Models.AttractMode; + +namespace SabreTools.Serialization +{ + /// + /// Separated value deserializer for AttractMode romlists + /// + public partial class AttractMode + { + /// + /// Deserializes an AttractMode romlist to the defined type + /// + /// Path to the file to deserialize + /// Deserialized data on success, null on failure + public static MetadataFile? Deserialize(string path) + { + try + { + using var stream = PathProcessor.OpenStream(path); + return Deserialize(stream); + } + catch + { + // TODO: Handle logging the exception + return default; + } + } + + /// + /// Deserializes an AttractMode romlist in a stream to the defined type + /// + /// Stream to deserialize + /// Deserialized data on success, null on failure + public static MetadataFile? Deserialize(Stream? stream) + { + try + { + // If the stream is null + if (stream == null) + return default; + + // Setup the reader and output + var reader = new SeparatedValueReader(stream, Encoding.UTF8) + { + Separator = ';', + VerifyFieldCount = false, + }; + var dat = new MetadataFile(); + + // Read the header values first + if (!reader.ReadHeader()) + return null; + + dat.Header = reader.HeaderValues.ToArray(); + + // Loop through the rows and parse out values + var rows = new List(); + while (!reader.EndOfStream) + { + // If we have no next line + if (!reader.ReadNextLine()) + break; + + // Parse the line into a row + Row? row = null; + if (reader.Line.Count < HeaderWithRomnameCount) + { + row = new Row + { + Name = reader.Line[0], + Title = reader.Line[1], + Emulator = reader.Line[2], + CloneOf = reader.Line[3], + Year = reader.Line[4], + Manufacturer = reader.Line[5], + Category = reader.Line[6], + Players = reader.Line[7], + Rotation = reader.Line[8], + Control = reader.Line[9], + Status = reader.Line[10], + DisplayCount = reader.Line[11], + DisplayType = reader.Line[12], + AltRomname = reader.Line[13], + AltTitle = reader.Line[14], + Extra = reader.Line[15], + Buttons = reader.Line[16], + }; + + // If we have additional fields + if (reader.Line.Count > HeaderWithoutRomnameCount) + row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithoutRomnameCount).ToArray(); + } + else + { + row = new Row + { + Name = reader.Line[0], + Title = reader.Line[1], + Emulator = reader.Line[2], + CloneOf = reader.Line[3], + Year = reader.Line[4], + Manufacturer = reader.Line[5], + Category = reader.Line[6], + Players = reader.Line[7], + Rotation = reader.Line[8], + Control = reader.Line[9], + Status = reader.Line[10], + DisplayCount = reader.Line[11], + DisplayType = reader.Line[12], + AltRomname = reader.Line[13], + AltTitle = reader.Line[14], + Extra = reader.Line[15], + Buttons = reader.Line[16], + }; + + // If we have additional fields + if (reader.Line.Count > HeaderWithRomnameCount) + row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithRomnameCount).ToArray(); + } + + rows.Add(row); + } + + // Assign the rows to the Dat and return + dat.Row = rows.ToArray(); + return dat; + } + catch + { + // TODO: Handle logging the exception + return default; + } + } + } +} \ No newline at end of file diff --git a/SabreTools.Serialization/AttractMode.Serializer.cs b/SabreTools.Serialization/AttractMode.Serializer.cs new file mode 100644 index 00000000..c51880de --- /dev/null +++ b/SabreTools.Serialization/AttractMode.Serializer.cs @@ -0,0 +1,114 @@ +using System.IO; +using System.Linq; +using System.Text; +using SabreTools.IO.Writers; +using SabreTools.Models.AttractMode; + +namespace SabreTools.Serialization +{ + /// + /// Separated value serializer for AttractMode romlists + /// + public partial class AttractMode + { + /// + /// Serializes the defined type to an AttractMode romlist + /// + /// Data to serialize + /// Path to the file to serialize to + /// True on successful serialization, false otherwise + public static bool SerializeToFile(MetadataFile? metadataFile, string path) + { + try + { + using var stream = SerializeToStream(metadataFile); + if (stream == null) + return false; + + using var fs = File.OpenWrite(path); + stream.Seek(0, SeekOrigin.Begin); + stream.CopyTo(fs); + return true; + } + catch + { + // TODO: Handle logging the exception + return false; + } + } + + /// + /// Serializes the defined type to a stream + /// + /// Data to serialize + /// Stream containing serialized data on success, null otherwise + public static Stream? SerializeToStream(MetadataFile? metadataFile) + { + try + { + // If the metadata file is null + if (metadataFile == null) + return null; + + // Setup the writer and output + var stream = new MemoryStream(); + var writer = new SeparatedValueWriter(stream, Encoding.UTF8) { Separator = ';', Quotes = false }; + + // TODO: Include flag to write out long or short header + // Write the short header + writer.WriteString(HeaderWithoutRomname); // TODO: Convert to array of values + + // Write out the rows, if they exist + WriteRows(metadataFile.Row, writer); + + // Return the stream + return stream; + } + catch + { + // TODO: Handle logging the exception + return null; + } + } + + /// + /// Write rows information to the current writer + /// + /// Array of Row objects representing the rows information + /// SeparatedValueWriter representing the output + private static void WriteRows(Row[]? rows, SeparatedValueWriter writer) + { + // If the games information is missing, we can't do anything + if (rows == null || !rows.Any()) + return; + + // Loop through and write out the rows + foreach (var row in rows) + { + var rowArray = new string[] + { + row.Name, + row.Title, + row.Emulator, + row.CloneOf, + row.Year, + row.Manufacturer, + row.Category, + row.Players, + row.Rotation, + row.Control, + row.Status, + row.DisplayCount, + row.DisplayType, + row.AltRomname, + row.AltTitle, + row.Extra, + row.Buttons, + }; + + writer.WriteValues(rowArray); + writer.Flush(); + } + } + } +} \ No newline at end of file diff --git a/SabreTools.Serialization/AttractMode.cs b/SabreTools.Serialization/AttractMode.cs index 1636552c..a359dd59 100644 --- a/SabreTools.Serialization/AttractMode.cs +++ b/SabreTools.Serialization/AttractMode.cs @@ -1,146 +1,14 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using SabreTools.IO.Readers; -using SabreTools.Models.AttractMode; - namespace SabreTools.Serialization { /// - /// Separated value serializer for AttractMode romlists + /// Separated value serializer/deserializer for AttractMode romlists /// - public class AttractMode + public partial class AttractMode { private const string HeaderWithoutRomname = "#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons"; private const int HeaderWithoutRomnameCount = 17; private const string HeaderWithRomname = "#Romname;Title;Emulator;Cloneof;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons;Favourite;Tags;PlayedCount;PlayedTime;FileIsAvailable"; private const int HeaderWithRomnameCount = 22; - - /// - /// Deserializes an AttractMode romlist to the defined type - /// - /// Path to the file to deserialize - /// Deserialized data on success, null on failure - public static MetadataFile? Deserialize(string path) - { - try - { - using var stream = PathProcessor.OpenStream(path); - return Deserialize(stream); - } - catch - { - // TODO: Handle logging the exception - return default; - } - } - - /// - /// Deserializes an AttractMode romlist in a stream to the defined type - /// - /// Stream to deserialize - /// Deserialized data on success, null on failure - public static MetadataFile? Deserialize(Stream? stream) - { - try - { - // If the stream is null - if (stream == null) - return default; - - // Setup the reader and output - var reader = new SeparatedValueReader(stream, Encoding.UTF8) - { - Separator = ';', - VerifyFieldCount = false, - }; - var dat = new MetadataFile(); - - // Read the header values first - if (!reader.ReadHeader()) - return null; - - dat.Header = reader.HeaderValues.ToArray(); - - // Loop through the rows and parse out values - var rows = new List(); - while (!reader.EndOfStream) - { - // If we have no next line - if (!reader.ReadNextLine()) - break; - - // Parse the line into a row - Row? row = null; - if (reader.Line.Count < HeaderWithRomnameCount) - { - row = new Row - { - Name = reader.Line[0], - Title = reader.Line[1], - Emulator = reader.Line[2], - CloneOf = reader.Line[3], - Year = reader.Line[4], - Manufacturer = reader.Line[5], - Category = reader.Line[6], - Players = reader.Line[7], - Rotation = reader.Line[8], - Control = reader.Line[9], - Status = reader.Line[10], - DisplayCount = reader.Line[11], - DisplayType = reader.Line[12], - AltRomname = reader.Line[13], - AltTitle = reader.Line[14], - Extra = reader.Line[15], - Buttons = reader.Line[16], - }; - - // If we have additional fields - if (reader.Line.Count > HeaderWithoutRomnameCount) - row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithoutRomnameCount).ToArray(); - } - else - { - row = new Row - { - Name = reader.Line[0], - Title = reader.Line[1], - Emulator = reader.Line[2], - CloneOf = reader.Line[3], - Year = reader.Line[4], - Manufacturer = reader.Line[5], - Category = reader.Line[6], - Players = reader.Line[7], - Rotation = reader.Line[8], - Control = reader.Line[9], - Status = reader.Line[10], - DisplayCount = reader.Line[11], - DisplayType = reader.Line[12], - AltRomname = reader.Line[13], - AltTitle = reader.Line[14], - Extra = reader.Line[15], - Buttons = reader.Line[16], - }; - - // If we have additional fields - if (reader.Line.Count > HeaderWithRomnameCount) - row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithRomnameCount).ToArray(); - } - - rows.Add(row); - } - - // Assign the rows to the Dat and return - dat.Row = rows.ToArray(); - return dat; - } - catch - { - // TODO: Handle logging the exception - return default; - } - } } } \ No newline at end of file