using System; using System.Collections.Generic; using System.IO; using System.Xml; using SabreTools.Data.Extensions; using SabreTools.Data.Models.Listxml; using SabreTools.Text.Extensions; namespace SabreTools.Serialization.Readers { public class Mess : BaseBinaryReader { /// public override Data.Models.Listxml.Mess? Deserialize(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Cache the current offset long initialOffset = data.Position; // Create the XmlTextReader var reader = new XmlTextReader(data); reader.WhitespaceHandling = WhitespaceHandling.None; // Parse the XML, if possible Data.Models.Listxml.Mess? mess = null; while (reader.Read()) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "mess": if (mess is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); mess = ParseMess(reader); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } return mess; } catch { // Ignore the actual error return null; } } /// /// Parse from an XmlTextReader into a Mess /// /// XmlTextReader to read from /// Filled Mess on success, null on error public Data.Models.Listxml.Mess ParseMess(XmlTextReader reader) { var obj = new Data.Models.Listxml.Mess(); obj.Version = reader.GetAttribute("version"); List games = []; while (reader.Read()) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "machine": case "game": var game = ParseGameBase(reader); if (game is not null) games.Add(game); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } obj.Game = [.. games]; return obj; } #region Items /// /// Parse from an XmlTextReader into a Adjuster /// /// XmlTextReader to read from /// Filled Adjuster on success, null on error public Adjuster ParseAdjuster(XmlTextReader reader) { var obj = new Adjuster(); obj.Name = reader.GetAttribute("name"); obj.Default = reader.GetAttribute("default").AsYesNo(); while (reader.Read()) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "condition": if (obj.Condition is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Condition = ParseCondition(reader); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } return obj; } /// /// Parse from an XmlTextReader into a Analog /// /// XmlTextReader to read from /// Filled Analog on success, null on error public Analog ParseAnalog(XmlTextReader reader) { var obj = new Analog(); obj.Mask = reader.GetAttribute("mask"); return obj; } /// /// Parse from an XmlTextReader into a BiosSet /// /// XmlTextReader to read from /// Filled BiosSet on success, null on error public BiosSet ParseBiosSet(XmlTextReader reader) { var obj = new BiosSet(); obj.Name = reader.GetAttribute("name"); obj.Description = reader.GetAttribute("description"); obj.Default = reader.GetAttribute("default").AsYesNo(); return obj; } /// /// Parse from an XmlTextReader into a Chip /// /// XmlTextReader to read from /// Filled Chip on success, null on error public Chip ParseChip(XmlTextReader reader) { var obj = new Chip(); obj.Name = reader.GetAttribute("name"); obj.Tag = reader.GetAttribute("tag"); obj.Type = reader.GetAttribute("type").AsChipType(); obj.SoundOnly = reader.GetAttribute("soundonly").AsYesNo(); obj.Clock = NumberHelper.ConvertToInt64(reader.GetAttribute("clock")); return obj; } /// /// Parse from an XmlTextReader into a Condition /// /// XmlTextReader to read from /// Filled Condition on success, null on error public Condition ParseCondition(XmlTextReader reader) { var obj = new Condition(); obj.Tag = reader.GetAttribute("tag"); obj.Mask = reader.GetAttribute("mask"); obj.Relation = reader.GetAttribute("relation").AsRelation(); obj.Value = reader.GetAttribute("value"); return obj; } /// /// Parse from an XmlTextReader into a Configuration /// /// XmlTextReader to read from /// Filled Configuration on success, null on error public Configuration ParseConfiguration(XmlTextReader reader) { var obj = new Configuration(); obj.Name = reader.GetAttribute("name"); obj.Tag = reader.GetAttribute("tag"); obj.Mask = reader.GetAttribute("mask"); List confLocations = []; List confSettings = []; while (reader.Read()) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "condition": if (obj.Condition is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Condition = ParseCondition(reader); break; case "conflocation": var confLocation = ParseConfLocation(reader); if (confLocation is not null) confLocations.Add(confLocation); break; case "confsetting": var confSetting = ParseConfSetting(reader); if (confSetting is not null) confSettings.Add(confSetting); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } if (confLocations.Count > 0) obj.ConfLocation = [.. confLocations]; if (confSettings.Count > 0) obj.ConfSetting = [.. confSettings]; return obj; } /// /// Parse from an XmlTextReader into a ConfLocation /// /// XmlTextReader to read from /// Filled ConfLocation on success, null on error public ConfLocation ParseConfLocation(XmlTextReader reader) { var obj = new ConfLocation(); obj.Name = reader.GetAttribute("name"); obj.Number = NumberHelper.ConvertToInt64(reader.GetAttribute("number")); obj.Inverted = reader.GetAttribute("inverted").AsYesNo(); return obj; } /// /// Parse from an XmlTextReader into a ConfSetting /// /// XmlTextReader to read from /// Filled ConfSetting on success, null on error public ConfSetting ParseConfSetting(XmlTextReader reader) { var obj = new ConfSetting(); obj.Name = reader.GetAttribute("name"); obj.Value = reader.GetAttribute("value"); obj.Default = reader.GetAttribute("default").AsYesNo(); while (reader.Read()) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "condition": if (obj.Condition is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Condition = ParseCondition(reader); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } return obj; } /// /// Parse from an XmlTextReader into a Control /// /// XmlTextReader to read from /// Filled Control on success, null on error public Control ParseControl(XmlTextReader reader) { var obj = new Control(); obj.Type = reader.GetAttribute("type").AsControlType(); obj.Player = NumberHelper.ConvertToInt64(reader.GetAttribute("player")); obj.Buttons = NumberHelper.ConvertToInt64(reader.GetAttribute("buttons")); obj.ReqButtons = NumberHelper.ConvertToInt64(reader.GetAttribute("reqbuttons")); obj.Minimum = NumberHelper.ConvertToInt64(reader.GetAttribute("minimum")); obj.Maximum = NumberHelper.ConvertToInt64(reader.GetAttribute("maximum")); obj.Sensitivity = NumberHelper.ConvertToInt64(reader.GetAttribute("sensitivity")); obj.KeyDelta = NumberHelper.ConvertToInt64(reader.GetAttribute("keydelta")); obj.Reverse = reader.GetAttribute("reverse").AsYesNo(); obj.Ways = reader.GetAttribute("ways"); obj.Ways2 = reader.GetAttribute("ways2"); obj.Ways3 = reader.GetAttribute("ways3"); return obj; } /// /// Parse from an XmlTextReader into a Device /// /// XmlTextReader to read from /// Filled Device on success, null on error public Device ParseDevice(XmlTextReader reader) { var obj = new Device(); obj.Type = reader.GetAttribute("type").AsDeviceType(); obj.Tag = reader.GetAttribute("tag"); obj.FixedImage = reader.GetAttribute("fixed_image"); obj.Mandatory = reader.GetAttribute("mandatory").AsYesNo(); obj.Interface = reader.GetAttribute("interface"); List extensions = []; while (reader.Read()) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "instance": if (obj.Instance is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Instance = ParseInstance(reader); break; case "extension": var extension = ParseExtension(reader); if (extension is not null) extensions.Add(extension); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } if (extensions.Count > 0) obj.Extension = [.. extensions]; return obj; } /// /// Parse from an XmlTextReader into a DeviceRef /// /// XmlTextReader to read from /// Filled DeviceRef on success, null on error public DeviceRef ParseDeviceRef(XmlTextReader reader) { var obj = new DeviceRef(); obj.Name = reader.GetAttribute("name"); return obj; } /// /// Parse from an XmlTextReader into a DipLocation /// /// XmlTextReader to read from /// Filled DipLocation on success, null on error public DipLocation ParseDipLocation(XmlTextReader reader) { var obj = new DipLocation(); obj.Name = reader.GetAttribute("name"); obj.Number = NumberHelper.ConvertToInt64(reader.GetAttribute("number")); obj.Inverted = reader.GetAttribute("inverted").AsYesNo(); return obj; } /// /// Parse from an XmlTextReader into a DipSwitch /// /// XmlTextReader to read from /// Filled DipSwitch on success, null on error public DipSwitch ParseDipSwitch(XmlTextReader reader) { var obj = new DipSwitch(); obj.Name = reader.GetAttribute("name"); obj.Tag = reader.GetAttribute("tag"); obj.Mask = reader.GetAttribute("mask"); List dipLocations = []; List dipValues = []; while (reader.Read()) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "condition": if (obj.Condition is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Condition = ParseCondition(reader); break; case "diplocation": var dipLocation = ParseDipLocation(reader); if (dipLocation is not null) dipLocations.Add(dipLocation); break; case "dipvalue": var dipValue = ParseDipValue(reader); if (dipValue is not null) dipValues.Add(dipValue); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } if (dipLocations.Count > 0) obj.DipLocation = [.. dipLocations]; if (dipValues.Count > 0) obj.DipValue = [.. dipValues]; return obj; } /// /// Parse from an XmlTextReader into a DipValue /// /// XmlTextReader to read from /// Filled DipValue on success, null on error public DipValue ParseDipValue(XmlTextReader reader) { var obj = new DipValue(); obj.Name = reader.GetAttribute("name"); obj.Value = reader.GetAttribute("value"); obj.Default = reader.GetAttribute("default").AsYesNo(); while (reader.Read()) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "condition": if (obj.Condition is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Condition = ParseCondition(reader); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } return obj; } /// /// Parse from an XmlTextReader into a Disk /// /// XmlTextReader to read from /// Filled Disk on success, null on error public Disk ParseDisk(XmlTextReader reader) { var obj = new Disk(); obj.Name = reader.GetAttribute("name"); obj.MD5 = reader.GetAttribute("md5"); obj.SHA1 = reader.GetAttribute("sha1"); obj.Merge = reader.GetAttribute("merge"); obj.Region = reader.GetAttribute("region"); obj.Index = NumberHelper.ConvertToInt64(reader.GetAttribute("index")); obj.Writable = reader.GetAttribute("writable").AsYesNo(); obj.Status = reader.GetAttribute("status").AsItemStatus(); obj.Optional = reader.GetAttribute("optional").AsYesNo(); return obj; } /// /// Parse from an XmlTextReader into a Display /// /// XmlTextReader to read from /// Filled Display on success, null on error public Display ParseDisplay(XmlTextReader reader) { var obj = new Display(); obj.Tag = reader.GetAttribute("tag"); obj.Type = reader.GetAttribute("type").AsDisplayType(); obj.Rotate = reader.GetAttribute("rotate").AsRotation(); obj.FlipX = reader.GetAttribute("flipx").AsYesNo(); obj.Width = NumberHelper.ConvertToInt64(reader.GetAttribute("width")); obj.Height = NumberHelper.ConvertToInt64(reader.GetAttribute("height")); obj.Refresh = NumberHelper.ConvertToDouble(reader.GetAttribute("refresh")); obj.PixClock = NumberHelper.ConvertToInt64(reader.GetAttribute("pixclock")); obj.HTotal = NumberHelper.ConvertToInt64(reader.GetAttribute("htotal")); obj.HBEnd = NumberHelper.ConvertToInt64(reader.GetAttribute("hbend")); obj.HBStart = NumberHelper.ConvertToInt64(reader.GetAttribute("hbstart")); obj.VTotal = NumberHelper.ConvertToInt64(reader.GetAttribute("vtotal")); obj.VBEnd = NumberHelper.ConvertToInt64(reader.GetAttribute("vbend")); obj.VBStart = NumberHelper.ConvertToInt64(reader.GetAttribute("vbstart")); return obj; } /// /// Parse from an XmlTextReader into a Driver /// /// XmlTextReader to read from /// Filled Driver on success, null on error public Driver ParseDriver(XmlTextReader reader) { var obj = new Driver(); obj.Status = reader.GetAttribute("status").AsSupportStatus(); obj.Color = reader.GetAttribute("color").AsSupportStatus(); obj.Sound = reader.GetAttribute("sound").AsSupportStatus(); obj.PaletteSize = reader.GetAttribute("palettesize"); obj.Emulation = reader.GetAttribute("emulation").AsSupportStatus(); obj.Cocktail = reader.GetAttribute("cocktail").AsSupportStatus(); obj.SaveState = reader.GetAttribute("savestate").AsSupported(); obj.RequiresArtwork = reader.GetAttribute("requiresartwork").AsYesNo(); obj.Unofficial = reader.GetAttribute("unofficial").AsYesNo(); obj.NoSoundHardware = reader.GetAttribute("nosoundhardware").AsYesNo(); obj.Incomplete = reader.GetAttribute("incomplete").AsYesNo(); return obj; } /// /// Parse from an XmlTextReader into a Extension /// /// XmlTextReader to read from /// Filled Extension on success, null on error public Extension ParseExtension(XmlTextReader reader) { var obj = new Extension(); obj.Name = reader.GetAttribute("name"); return obj; } /// /// Parse from an XmlTextReader into a Feature /// /// XmlTextReader to read from /// Filled Feature on success, null on error public Feature ParseFeature(XmlTextReader reader) { var obj = new Feature(); obj.Type = reader.GetAttribute("type").AsFeatureType(); obj.Status = reader.GetAttribute("status").AsFeatureStatus(); obj.Overall = reader.GetAttribute("overall").AsFeatureStatus(); return obj; } /// /// Parse from an XmlTextReader into a GameBase /// /// XmlTextReader to read from /// Filled GameBase on success, null on error public GameBase? ParseGameBase(XmlTextReader reader) { GameBase obj; if (reader.Name == "game") obj = new Game(); else if (reader.Name == "machine") obj = new Machine(); else return null; obj.Name = reader.GetAttribute("name"); obj.SourceFile = reader.GetAttribute("sourcefile"); obj.IsBios = reader.GetAttribute("isbios").AsYesNo(); obj.IsDevice = reader.GetAttribute("isdevice").AsYesNo(); obj.IsMechanical = reader.GetAttribute("ismechanical").AsYesNo(); obj.Runnable = reader.GetAttribute("runnable").AsRunnable(); obj.CloneOf = reader.GetAttribute("cloneof"); obj.RomOf = reader.GetAttribute("romof"); obj.SampleOf = reader.GetAttribute("sampleof"); List biosSets = []; List roms = []; List disks = []; List deviceRefs = []; List samples = []; List chips = []; List displays = []; List