using System; using System.Collections.Generic; using System.IO; using System.Xml; using SabreTools.Data.Extensions; using SabreTools.Data.Models.OpenMSX; namespace SabreTools.Serialization.Readers { public class OpenMSX : BaseBinaryReader { /// public override SoftwareDb? 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 SoftwareDb? softwareDb = 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 "softwaredb": if (softwareDb is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); softwareDb = ParseSoftwareDb(reader); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } return softwareDb; } catch { // Ignore the actual error return null; } } /// /// Parse from an XmlTextReader into a SoftwareDb /// /// XmlTextReader to read from /// Filled SoftwareDb on success, null on error public SoftwareDb ParseSoftwareDb(XmlTextReader reader) { var obj = new SoftwareDb(); obj.Timestamp = reader.GetAttribute("timestamp"); List softwares = []; reader.Read(); while (!reader.EOF) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "software": var software = ParseSoftware(reader); if (software is not null) softwares.Add(software); reader.Skip(); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); reader.Skip(); break; } } if (softwares.Count > 0) obj.Software = [.. softwares]; return obj; } /// /// Parse from an XmlTextReader into a Dump /// /// XmlTextReader to read from /// Filled Dump on success, null on error public Dump ParseDump(XmlTextReader reader) { var obj = new Dump(); reader.Read(); while (!reader.EOF) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "original": if (obj.Original is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Original = ParseOriginal(reader); break; case "rom": case "megarom": case "sccpluscart": if (obj.Rom is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Rom = ParseRomBase(reader); reader.Skip(); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); break; } } return obj; } /// /// Parse from an XmlTextReader into a Original /// /// XmlTextReader to read from /// Filled Original on success, null on error public Original ParseOriginal(XmlTextReader reader) { var obj = new Original(); obj.Value = reader.GetAttribute("value").AsYesNo(); obj.Content = reader.ReadElementContentAsString(); return obj; } /// /// Parse from an XmlTextReader into a RomBase /// /// XmlTextReader to read from /// Filled RomBase on success, null on error public RomBase? ParseRomBase(XmlTextReader reader) { RomBase obj; if (reader.Name == "rom") obj = new Rom(); else if (reader.Name == "megarom") obj = new MegaRom(); else if (reader.Name == "sccpluscart") obj = new SCCPlusCart(); else return null; reader.Read(); while (!reader.EOF) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "start": if (obj.Start is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Start = reader.ReadElementContentAsString(); break; case "type": if (obj.Type is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Type = reader.ReadElementContentAsString(); break; case "hash": if (obj.Hash is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Hash = reader.ReadElementContentAsString(); break; case "remark": if (obj.Remark is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Remark = reader.ReadElementContentAsString(); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); reader.Skip(); break; } } return obj; } /// /// Parse from an XmlTextReader into a Software /// /// XmlTextReader to read from /// Filled Software on success, null on error public Software ParseSoftware(XmlTextReader reader) { var obj = new Software(); List dumps = []; reader.Read(); while (!reader.EOF) { // An ending element means exit if (reader.NodeType == XmlNodeType.EndElement) break; // Only process starting elements if (!reader.IsStartElement()) continue; switch (reader.Name) { case "title": if (obj.Title is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Title = reader.ReadElementContentAsString(); break; case "genmsxid": if (obj.GenMSXID is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.GenMSXID = reader.ReadElementContentAsString(); break; case "system": if (obj.System is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.System = reader.ReadElementContentAsString(); break; case "company": if (obj.Company is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Company = reader.ReadElementContentAsString(); break; case "year": if (obj.Year is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Year = reader.ReadElementContentAsString(); break; case "country": if (obj.Country is not null && Debug) Console.WriteLine($"'{reader.Name}' element already found, overwriting"); obj.Country = reader.ReadElementContentAsString(); break; case "dump": var dump = ParseDump(reader); if (dump is not null) dumps.Add(dump); reader.Skip(); break; default: if (Debug) Console.Error.WriteLine($"Element '{reader.Name}' is not recognized"); reader.Skip(); break; } } if (dumps.Count > 0) obj.Dump = [.. dumps]; return obj; } } }