From 139e5e63666262628b0074a1e7de7cedd2e7055b Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 8 Sep 2023 21:04:08 -0400 Subject: [PATCH] Add and convert AttractMode --- AttractMode.cs | 14 ++++ CrossModel/AttractMode.Deserializer.cs | 94 +++++++++++++++++++++ CrossModel/AttractMode.Serializer.cs | 92 +++++++++++++++++++++ Files/AttractMode.Deserializer.cs | 20 +++++ Files/AttractMode.Serializer.cs | 29 +++++++ Streams/AttractMode.Deserializer.cs | 110 +++++++++++++++++++++++++ Streams/AttractMode.Serializer.cs | 91 ++++++++++++++++++++ 7 files changed, 450 insertions(+) create mode 100644 AttractMode.cs create mode 100644 CrossModel/AttractMode.Deserializer.cs create mode 100644 CrossModel/AttractMode.Serializer.cs create mode 100644 Files/AttractMode.Deserializer.cs create mode 100644 Files/AttractMode.Serializer.cs create mode 100644 Streams/AttractMode.Deserializer.cs create mode 100644 Streams/AttractMode.Serializer.cs diff --git a/AttractMode.cs b/AttractMode.cs new file mode 100644 index 00000000..ab008487 --- /dev/null +++ b/AttractMode.cs @@ -0,0 +1,14 @@ +namespace SabreTools.Serialization +{ + /// + /// Separated value serializer/deserializer for AttractMode romlists + /// + public static class AttractMode + { + public const string HeaderWithoutRomname = "#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons"; + public const int HeaderWithoutRomnameCount = 17; + + public 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"; + public const int HeaderWithRomnameCount = 22; + } +} \ No newline at end of file diff --git a/CrossModel/AttractMode.Deserializer.cs b/CrossModel/AttractMode.Deserializer.cs new file mode 100644 index 00000000..979d57b3 --- /dev/null +++ b/CrossModel/AttractMode.Deserializer.cs @@ -0,0 +1,94 @@ +using System; +using System.Linq; +using SabreTools.Models.AttractMode; + +namespace SabreTools.Serialization.CrossModel +{ + public partial class AttractMode : IModelSerializer + { + /// +#if NET48 + public MetadataFile Deserialize(Models.Metadata.MetadataFile obj) +#else + public MetadataFile? Deserialize(Models.Metadata.MetadataFile? obj) +#endif + { + if (obj == null) + return null; + + var header = obj.Read(Models.Metadata.MetadataFile.HeaderKey); + var metadataFile = header != null ? ConvertHeaderFromInternalModel(header) : new MetadataFile(); + + var machines = obj.Read(Models.Metadata.MetadataFile.MachineKey); + if (machines != null && machines.Any()) + { + metadataFile.Row = machines + .Where(m => m != null) + .SelectMany(ConvertMachineFromInternalModel) + .ToArray(); + } + + return metadataFile; + } + + /// + /// Convert from to + /// + private static MetadataFile ConvertHeaderFromInternalModel(Models.Metadata.Header item) + { + var metadataFile = new MetadataFile + { + Header = item.ReadStringArray(Models.Metadata.Header.HeaderKey), + }; + return metadataFile; + } + + /// + /// Convert from to an array of + /// + private static Row[] ConvertMachineFromInternalModel(Models.Metadata.Machine item) + { + var roms = item.Read(Models.Metadata.Machine.RomKey); + if (roms == null || !roms.Any()) + return Array.Empty(); + + return roms + .Where(r => r != null) + .Select(rom => ConvertFromInternalModel(rom, item)) + .ToArray(); + } + + /// + /// Convert from to + /// + private static Row ConvertFromInternalModel(Models.Metadata.Rom item, Models.Metadata.Machine parent) + { + var row = new Row + { + Name = parent.ReadString(Models.Metadata.Machine.NameKey), + Title = item.ReadString(Models.Metadata.Rom.NameKey), + Emulator = parent.ReadString(Models.Metadata.Machine.EmulatorKey), + CloneOf = parent.ReadString(Models.Metadata.Machine.CloneOfKey), + Year = parent.ReadString(Models.Metadata.Machine.YearKey), + Manufacturer = parent.ReadString(Models.Metadata.Machine.ManufacturerKey), + Category = parent.ReadString(Models.Metadata.Machine.CategoryKey), + Players = parent.ReadString(Models.Metadata.Machine.PlayersKey), + Rotation = parent.ReadString(Models.Metadata.Machine.RotationKey), + Control = parent.ReadString(Models.Metadata.Machine.ControlKey), + Status = parent.ReadString(Models.Metadata.Machine.StatusKey), + DisplayCount = parent.ReadString(Models.Metadata.Machine.DisplayCountKey), + DisplayType = parent.ReadString(Models.Metadata.Machine.DisplayTypeKey), + AltRomname = item.ReadString(Models.Metadata.Rom.AltRomnameKey), + AltTitle = item.ReadString(Models.Metadata.Rom.AltTitleKey), + Extra = parent.ReadString(Models.Metadata.Machine.ExtraKey), + Buttons = parent.ReadString(Models.Metadata.Machine.ButtonsKey), + Favorite = parent.ReadString(Models.Metadata.Machine.FavoriteKey), + Tags = parent.ReadString(Models.Metadata.Machine.TagsKey), + PlayedCount = parent.ReadString(Models.Metadata.Machine.PlayedCountKey), + PlayedTime = parent.ReadString(Models.Metadata.Machine.PlayedTimeKey), + FileIsAvailable = item.ReadString(Models.Metadata.Rom.FileIsAvailableKey), + }; + return row; + } + } +} \ No newline at end of file diff --git a/CrossModel/AttractMode.Serializer.cs b/CrossModel/AttractMode.Serializer.cs new file mode 100644 index 00000000..3617c4b5 --- /dev/null +++ b/CrossModel/AttractMode.Serializer.cs @@ -0,0 +1,92 @@ +using System.Linq; +using SabreTools.Models.AttractMode; + +namespace SabreTools.Serialization.CrossModel +{ + public partial class AttractMode : IModelSerializer + { + /// +#if NET48 + public Models.Metadata.MetadataFile Serialize(MetadataFile obj) +#else + public Models.Metadata.MetadataFile? Serialize(MetadataFile? obj) +#endif + { + if (obj == null) + return null; + + var metadataFile = new Models.Metadata.MetadataFile + { + [Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(obj), + }; + + if (obj?.Row != null && obj.Row.Any()) + { + metadataFile[Models.Metadata.MetadataFile.MachineKey] = obj.Row + .Where(r => r != null) + .Select(ConvertMachineToInternalModel) + .ToArray(); + } + + return metadataFile; + } + + /// + /// Convert from to + /// + private static Models.Metadata.Header ConvertHeaderToInternalModel(MetadataFile item) + { + var header = new Models.Metadata.Header + { + [Models.Metadata.Header.HeaderKey] = item.Header, + }; + return header; + } + + /// + /// Convert from to + /// + private static Models.Metadata.Machine ConvertMachineToInternalModel(Row item) + { + var machine = new Models.Metadata.Machine + { + [Models.Metadata.Machine.NameKey] = item.Name, + [Models.Metadata.Machine.EmulatorKey] = item.Emulator, + [Models.Metadata.Machine.CloneOfKey] = item.CloneOf, + [Models.Metadata.Machine.YearKey] = item.Year, + [Models.Metadata.Machine.ManufacturerKey] = item.Manufacturer, + [Models.Metadata.Machine.CategoryKey] = item.Category, + [Models.Metadata.Machine.PlayersKey] = item.Players, + [Models.Metadata.Machine.RotationKey] = item.Rotation, + [Models.Metadata.Machine.ControlKey] = item.Control, + [Models.Metadata.Machine.StatusKey] = item.Status, + [Models.Metadata.Machine.DisplayCountKey] = item.DisplayCount, + [Models.Metadata.Machine.DisplayTypeKey] = item.DisplayType, + [Models.Metadata.Machine.ExtraKey] = item.Extra, + [Models.Metadata.Machine.ButtonsKey] = item.Buttons, + [Models.Metadata.Machine.FavoriteKey] = item.Favorite, + [Models.Metadata.Machine.TagsKey] = item.Tags, + [Models.Metadata.Machine.PlayedCountKey] = item.PlayedCount, + [Models.Metadata.Machine.PlayedTimeKey] = item.PlayedTime, + [Models.Metadata.Machine.PlayedTimeKey] = item.PlayedTime, + [Models.Metadata.Machine.RomKey] = ConvertToInternalModel(item), + }; + return machine; + } + + /// + /// Convert from to + /// + private static Models.Metadata.Rom ConvertToInternalModel(Row item) + { + var rom = new Models.Metadata.Rom + { + [Models.Metadata.Rom.NameKey] = item.Title, + [Models.Metadata.Rom.AltRomnameKey] = item.AltRomname, + [Models.Metadata.Rom.AltTitleKey] = item.AltTitle, + [Models.Metadata.Rom.FileIsAvailableKey] = item.FileIsAvailable, + }; + return rom; + } + } +} \ No newline at end of file diff --git a/Files/AttractMode.Deserializer.cs b/Files/AttractMode.Deserializer.cs new file mode 100644 index 00000000..2407e92d --- /dev/null +++ b/Files/AttractMode.Deserializer.cs @@ -0,0 +1,20 @@ +using SabreTools.Models.AttractMode; + +namespace SabreTools.Serialization.Files +{ + public partial class AttractMode : IFileSerializer + { + /// +#if NET48 + public MetadataFile Deserialize(string path) +#else + public MetadataFile? Deserialize(string? path) +#endif + { + using (var stream = PathProcessor.OpenStream(path)) + { + return new Streams.AttractMode().Deserialize(stream); + } + } + } +} \ No newline at end of file diff --git a/Files/AttractMode.Serializer.cs b/Files/AttractMode.Serializer.cs new file mode 100644 index 00000000..d47a6529 --- /dev/null +++ b/Files/AttractMode.Serializer.cs @@ -0,0 +1,29 @@ +using System.IO; +using SabreTools.Models.AttractMode; + +namespace SabreTools.Serialization.Files +{ + public partial class AttractMode : IFileSerializer + { + /// +#if NET48 + public bool Serialize(MetadataFile obj, string path) +#else + public bool Serialize(MetadataFile? obj, string? path) + +#endif + { + using (var stream = new Streams.AttractMode().Serialize(obj)) + { + if (stream == null) + return false; + + using (var fs = File.OpenWrite(path)) + { + stream.CopyTo(fs); + return true; + } + } + } + } +} \ No newline at end of file diff --git a/Streams/AttractMode.Deserializer.cs b/Streams/AttractMode.Deserializer.cs new file mode 100644 index 00000000..38771813 --- /dev/null +++ b/Streams/AttractMode.Deserializer.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using SabreTools.IO.Readers; +using SabreTools.Models.AttractMode; + +namespace SabreTools.Serialization.Streams +{ + public partial class AttractMode : IStreamSerializer + { + /// +#if NET48 + public MetadataFile Deserialize(Stream data) +#else + public MetadataFile? Deserialize(Stream? data) +#endif + { + // If the stream is null + if (data == null) + return default; + + // Setup the reader and output + var reader = new SeparatedValueReader(data, Encoding.UTF8) + { + Separator = ';', + VerifyFieldCount = false, + }; + var dat = new MetadataFile(); + + // Read the header values first + if (!reader.ReadHeader() || reader.HeaderValues == null) + 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() || reader.Line == null) + break; + + // Parse the line into a row + Row row; + if (reader.Line.Count < Serialization.AttractMode.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 > Serialization.AttractMode.HeaderWithoutRomnameCount) + row.ADDITIONAL_ELEMENTS = reader.Line.Skip(Serialization.AttractMode.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 > Serialization.AttractMode.HeaderWithRomnameCount) + row.ADDITIONAL_ELEMENTS = reader.Line.Skip(Serialization.AttractMode.HeaderWithRomnameCount).ToArray(); + } + + rows.Add(row); + } + + // Assign the rows to the Dat and return + dat.Row = rows.ToArray(); + return dat; + } + } +} \ No newline at end of file diff --git a/Streams/AttractMode.Serializer.cs b/Streams/AttractMode.Serializer.cs new file mode 100644 index 00000000..c8272ee0 --- /dev/null +++ b/Streams/AttractMode.Serializer.cs @@ -0,0 +1,91 @@ +using System.IO; +using System.Linq; +using System.Text; +using SabreTools.IO.Writers; +using SabreTools.Models.AttractMode; + +namespace SabreTools.Serialization.Streams +{ + public partial class AttractMode : IStreamSerializer + { + /// +#if NET48 + public Stream Serialize(MetadataFile obj) +#else + public Stream? Serialize(MetadataFile? obj) +#endif + { + // If the metadata file is null + if (obj == null) + return null; + + // Setup the writer and output + var stream = new MemoryStream(); + var writer = new SeparatedValueWriter(stream, Encoding.UTF8) + { + Separator = ';', + Quotes = false, + VerifyFieldCount = false, + }; + + // TODO: Include flag to write out long or short header + // Write the short header + writer.WriteString(Serialization.AttractMode.HeaderWithoutRomname); // TODO: Convert to array of values + + // Write out the rows, if they exist + WriteRows(obj.Row, writer); + + // Return the stream + stream.Seek(0, SeekOrigin.Begin); + return stream; + } + + /// + /// Write rows information to the current writer + /// + /// Array of Row objects representing the rows information + /// SeparatedValueWriter representing the output +#if NET48 + private static void WriteRows(Row[] rows, SeparatedValueWriter writer) +#else + private static void WriteRows(Row[]? rows, SeparatedValueWriter writer) +#endif + { + // 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) + { +#if NET48 + var rowArray = new string[] +#else + var rowArray = new string?[] +#endif + { + 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