using System; using System.Collections.Generic; using System.IO; using System.Xml; using SabreTools.Data.Models.Listxml; 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"); 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"); 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"); obj.SoundOnly = reader.GetAttribute("soundonly"); obj.Clock = 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"); 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 = reader.GetAttribute("number"); obj.Inverted = reader.GetAttribute("inverted"); 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"); 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"); obj.Player = reader.GetAttribute("player"); obj.Buttons = reader.GetAttribute("buttons"); obj.ReqButtons = reader.GetAttribute("reqbuttons"); obj.Minimum = reader.GetAttribute("minimum"); obj.Maximum = reader.GetAttribute("maximum"); obj.Sensitivity = reader.GetAttribute("sensitivity"); obj.KeyDelta = reader.GetAttribute("keydelta"); obj.Reverse = reader.GetAttribute("reverse"); 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"); obj.Tag = reader.GetAttribute("tag"); obj.FixedImage = reader.GetAttribute("fixed_image"); obj.Mandatory = reader.GetAttribute("mandatory"); 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 = reader.GetAttribute("number"); obj.Inverted = reader.GetAttribute("inverted"); 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"); 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 = reader.GetAttribute("index"); obj.Writable = reader.GetAttribute("writable"); obj.Status = reader.GetAttribute("status"); obj.Optional = reader.GetAttribute("optional"); 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"); obj.Rotate = reader.GetAttribute("rotate"); obj.FlipX = reader.GetAttribute("flipx"); obj.Width = reader.GetAttribute("width"); obj.Height = reader.GetAttribute("height"); obj.Refresh = reader.GetAttribute("refresh"); obj.PixClock = reader.GetAttribute("pixclock"); obj.HTotal = reader.GetAttribute("htotal"); obj.HBEnd = reader.GetAttribute("hbend"); obj.HBStart = reader.GetAttribute("hbstart"); obj.VTotal = reader.GetAttribute("vtotal"); obj.VBEnd = reader.GetAttribute("vbend"); obj.VBStart = 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"); obj.Color = reader.GetAttribute("color"); obj.Sound = reader.GetAttribute("sound"); obj.PaletteSize = reader.GetAttribute("palettesize"); obj.Emulation = reader.GetAttribute("emulation"); obj.Cocktail = reader.GetAttribute("cocktail"); obj.SaveState = reader.GetAttribute("savestate"); obj.RequiresArtwork = reader.GetAttribute("requiresartwork"); obj.Unofficial = reader.GetAttribute("unofficial"); obj.NoSoundHardware = reader.GetAttribute("nosoundhardware"); obj.Incomplete = reader.GetAttribute("incomplete"); 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"); obj.Status = reader.GetAttribute("status"); obj.Overall = reader.GetAttribute("overall"); 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"); obj.IsDevice = reader.GetAttribute("isdevice"); obj.IsMechanical = reader.GetAttribute("ismechanical"); obj.Runnable = reader.GetAttribute("runnable"); 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