diff --git a/SabreTools.DatFiles/Formats/DosCenter.Reader.cs b/SabreTools.DatFiles/Formats/DosCenter.Reader.cs
index 2ef61262..f6abf864 100644
--- a/SabreTools.DatFiles/Formats/DosCenter.Reader.cs
+++ b/SabreTools.DatFiles/Formats/DosCenter.Reader.cs
@@ -54,7 +54,7 @@ namespace SabreTools.DatFiles.Formats
Header.Comment ??= doscenter.Comment;
// Handle implied SuperDAT
- if (doscenter.Name.Contains(" - SuperDAT") && keep)
+ if (doscenter.Name?.Contains(" - SuperDAT") == true && keep)
Header.Type ??= "SuperDAT";
}
diff --git a/SabreTools.DatFiles/Formats/OpenMSX.Reader.cs b/SabreTools.DatFiles/Formats/OpenMSX.Reader.cs
index c781d187..df9b7dcc 100644
--- a/SabreTools.DatFiles/Formats/OpenMSX.Reader.cs
+++ b/SabreTools.DatFiles/Formats/OpenMSX.Reader.cs
@@ -1,9 +1,6 @@
using System;
-using System.Collections.Generic;
-using System.Xml;
-using System.Xml.Schema;
+using System.Linq;
using SabreTools.Core;
-using SabreTools.Core.Tools;
using SabreTools.DatItems;
using SabreTools.DatItems.Formats;
@@ -17,144 +14,93 @@ namespace SabreTools.DatFiles.Formats
///
public override void ParseFile(string filename, int indexId, bool keep, bool statsOnly = false, bool throwOnError = false)
{
- // Prepare all internal variables
- XmlReader xtr = XmlReader.Create(filename, new XmlReaderSettings
- {
- CheckCharacters = false,
- DtdProcessing = DtdProcessing.Ignore,
- IgnoreComments = true,
- IgnoreWhitespace = true,
- ValidationFlags = XmlSchemaValidationFlags.None,
- ValidationType = ValidationType.None,
- });
-
- // If we got a null reader, just return
- if (xtr == null)
- return;
-
- // Otherwise, read the file to the end
try
{
- xtr.MoveToContent();
- while (!xtr.EOF)
- {
- // We only want elements
- if (xtr.NodeType != XmlNodeType.Element)
- {
- xtr.Read();
- continue;
- }
+ // Deserialize the input file
+ var softwareDb = Serialization.OpenMSX.Deserialize(filename);
- switch (xtr.Name)
- {
- case "softwaredb":
- Header.Name ??= "openMSX Software List";
- Header.Description ??= Header.Name;
- Header.Date ??= xtr.GetAttribute("timestamp");
- xtr.Read();
- break;
+ // Convert the header to the internal format
+ ConvertHeader(softwareDb);
- // We want to process the entire subtree of the software
- case "software":
- ReadSoftware(xtr.ReadSubtree(), statsOnly, filename, indexId);
-
- // Skip the software now that we've processed it
- xtr.Skip();
- break;
-
- default:
- xtr.Read();
- break;
- }
- }
+ // Convert the software data to the internal format
+ ConvertSoftwares(softwareDb?.Software, filename, indexId, statsOnly);
}
catch (Exception ex) when (!throwOnError)
{
- logger.Warning(ex, $"Exception found while parsing '{filename}'");
-
- // For XML errors, just skip the affected node
- xtr?.Read();
+ string message = $"'{filename}' - An error occurred during parsing";
+ logger.Error(ex, message);
}
+ }
- xtr.Dispose();
+ #region Converters
+
+ ///
+ /// Convert header information
+ ///
+ /// Deserialized model to convert
+ private void ConvertHeader(Models.OpenMSX.SoftwareDb? datafile)
+ {
+ // If the datafile is missing, we can't do anything
+ if (datafile == null)
+ return;
+
+ Header.Name ??= "openMSX Software List";
+ Header.Description ??= Header.Name;
+ Header.Date ??= datafile.Timestamp;
}
///
- /// Read software information
+ /// Convert softwares information
///
- /// XmlReader representing a machine block
- /// True to only add item statistics while parsing, false otherwise
+ /// Array of deserialized models to convert
/// Name of the file to be parsed
/// Index ID for the DAT
- private void ReadSoftware(XmlReader reader, bool statsOnly, string filename, int indexId)
+ /// True to only add item statistics while parsing, false otherwise
+ private void ConvertSoftwares(Models.OpenMSX.Software[]? softwares, string filename, int indexId, bool statsOnly)
{
- // If we have an empty machine, skip it
- if (reader == null)
+ // If the software array is missing, we can't do anything
+ if (softwares == null || !softwares.Any())
return;
- // Otherwise, add what is possible
- reader.MoveToContent();
-
- int diskno = 0;
- bool containsItems = false;
-
- // Create a new machine
- Machine machine = new();
-
- while (!reader.EOF)
+ // Loop through the software and add
+ foreach (var software in softwares)
{
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the roms from the machine
- switch (reader.Name)
- {
- case "title":
- machine.Name = reader.ReadElementContentAsString();
- break;
-
- case "genmsxid":
- machine.GenMSXID = reader.ReadElementContentAsString();
- break;
-
- case "system":
- machine.System = reader.ReadElementContentAsString();
- break;
-
- case "company":
- machine.Manufacturer = reader.ReadElementContentAsString();
- break;
-
- case "year":
- machine.Year = reader.ReadElementContentAsString();
- break;
-
- case "country":
- machine.Country = reader.ReadElementContentAsString();
- break;
-
- case "dump":
- containsItems = ReadDump(reader.ReadSubtree(), machine, diskno, statsOnly, filename, indexId);
- diskno++;
-
- // Skip the dump now that we've processed it
- reader.Skip();
- break;
-
- default:
- reader.Read();
- break;
- }
+ ConvertSoftware(software, filename, indexId, statsOnly);
}
+ }
- // If no items were found for this machine, add a Blank placeholder
+ ///
+ /// Convert software 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 ConvertSoftware(Models.OpenMSX.Software software, string filename, int indexId, bool statsOnly, string dirname = null)
+ {
+ // If the software is missing, we can't do anything
+ if (software == null)
+ return;
+
+ // Create the machine for copying information
+ var machine = new Machine
+ {
+ Name = software.Title,
+ GenMSXID = software.GenMSXID,
+ System = software.System,
+ Manufacturer = software.Company,
+ Year = software.Year,
+ Country = software.Country,
+ };
+
+ // Check if there are any items
+ bool containsItems = false;
+ ConvertDumps(software.Dump, machine, filename, indexId, statsOnly, ref containsItems);
+
+ // If we had no items, create a Blank placeholder
if (!containsItems)
{
- Blank blank = new()
+ var blank = new Blank
{
Source = new Source
{
@@ -164,342 +110,78 @@ namespace SabreTools.DatFiles.Formats
};
blank.CopyMachineInformation(machine);
-
- // Now process and add the rom
ParseAddHelper(blank, statsOnly);
}
}
///
- /// Read dump information
+ /// Convert Dump information
///
- /// XmlReader representing a part block
- /// Machine information to pass to contained items
- /// Disk number to use when outputting to other DAT formats
- /// True to only add item statistics while parsing, false otherwise
+ /// Array of deserialized models to convert
+ /// Prefilled machine to use
/// Name of the file to be parsed
/// Index ID for the DAT
- private bool ReadDump(
- XmlReader reader,
- Machine machine,
- int diskno,
- bool statsOnly,
-
- // Standard Dat parsing
- string filename,
- int indexId)
+ /// True to only add item statistics while parsing, false otherwise
+ /// True if there were any items in the array, false otherwise
+ private void ConvertDumps(Models.OpenMSX.Dump[]? dumps, Machine machine, string filename, int indexId, bool statsOnly, ref bool containsItems)
{
- List items = new();
- Original original = null;
+ // If the dumps array is missing, we can't do anything
+ if (dumps == null || !dumps.Any())
+ return;
- while (!reader.EOF)
+ containsItems = true;
+ int index = 0;
+ foreach (var dump in dumps)
{
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
+ // If we don't have rom data, we can't do anything
+ if (dump?.Rom == null)
continue;
+
+ var rom = dump.Rom;
+
+ string name = $"{machine.Name}_{index++}{(!string.IsNullOrWhiteSpace(rom.Remark) ? $" {rom.Remark}" : string.Empty)}";
+ var item = new Rom
+ {
+ Name = name,
+ Offset = dump.Rom?.Start,
+ OpenMSXType = rom.Type,
+ SHA1 = rom.Hash,
+ Remark = rom.Remark,
+
+ Source = new Source
+ {
+ Index = indexId,
+ Name = filename,
+ },
+ };
+
+ if (dump.Original != null)
+ {
+ item.Original = new Original
+ {
+ Value = dump.Original.Value,
+ Content = dump.Original.Content,
+ };
}
- // Get the elements from the dump
- switch (reader.Name)
+ switch (dump.Rom)
{
- case "rom":
- DatItem rom = ReadRom(reader.ReadSubtree(), machine, diskno, filename, indexId);
- if (rom != null)
- items.Add(rom);
-
- // Skip the rom now that we've processed it
- reader.Skip();
+ case Models.OpenMSX.Rom:
+ item.OpenMSXSubType = OpenMSXSubType.Rom;
break;
-
- case "megarom":
- DatItem megarom = ReadMegaRom(reader.ReadSubtree(), machine, diskno, filename, indexId);
- if (megarom != null)
- items.Add(megarom);
-
- // Skip the megarom now that we've processed it
- reader.Skip();
+ case Models.OpenMSX.MegaRom:
+ item.OpenMSXSubType = OpenMSXSubType.MegaRom;
break;
-
- case "sccpluscart":
- DatItem sccpluscart = ReadSccPlusCart(reader.ReadSubtree(), machine, diskno, filename, indexId);
- if (sccpluscart != null)
- items.Add(sccpluscart);
-
- // Skip the sccpluscart now that we've processed it
- reader.Skip();
- break;
-
- case "original":
- original = new Original
- {
- Value = reader.GetAttribute("value").AsYesNo(),
- Content = reader.ReadElementContentAsString()
- };
- break;
-
- default:
- reader.Read();
- break;
- }
- }
-
- // If we have any items, loop through and add them
- foreach (DatItem item in items)
- {
- switch (item.ItemType)
- {
- case ItemType.Rom:
- (item as Rom).Original = original;
+ case Models.OpenMSX.SCCPlusCart:
+ item.OpenMSXSubType = OpenMSXSubType.SCCPlusCart;
break;
}
item.CopyMachineInformation(machine);
ParseAddHelper(item, statsOnly);
}
-
- return items.Count > 0;
}
- ///
- /// Read rom information
- ///
- /// XmlReader representing a rom block
- /// Machine information to pass to contained items
- /// Disk number to use when outputting to other DAT formats
- /// Name of the file to be parsed
- /// Index ID for the DAT
- private DatItem ReadRom(
- XmlReader reader,
- Machine machine,
- int diskno,
-
- // Standard Dat parsing
- string filename,
- int indexId)
- {
- string hash = string.Empty,
- offset = string.Empty,
- type = string.Empty,
- remark = string.Empty;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the rom
- switch (reader.Name)
- {
- case "hash":
- hash = reader.ReadElementContentAsString();
- break;
-
- case "start":
- offset = reader.ReadElementContentAsString();
- break;
-
- case "type":
- type = reader.ReadElementContentAsString();
- break;
-
- case "remark":
- remark = reader.ReadElementContentAsString();
- break;
-
- default:
- reader.Read();
- break;
- }
- }
-
- // If we got a hash, then create and return the item
- if (!string.IsNullOrWhiteSpace(hash))
- {
- return new Rom
- {
- Name = machine.Name + "_" + diskno + (!string.IsNullOrWhiteSpace(remark) ? " " + remark : string.Empty),
- Offset = offset,
- Size = null,
- SHA1 = hash,
-
- Source = new Source
- {
- Index = indexId,
- Name = filename,
- },
-
- OpenMSXSubType = OpenMSXSubType.Rom,
- OpenMSXType = type,
- Remark = remark,
- };
- }
-
- // No valid item means returning null
- return null;
- }
-
- ///
- /// Read megarom information
- ///
- /// XmlReader representing a megarom block
- /// Machine information to pass to contained items
- /// Disk number to use when outputting to other DAT formats
- /// Name of the file to be parsed
- /// Index ID for the DAT
- private DatItem ReadMegaRom(
- XmlReader reader,
- Machine machine,
- int diskno,
-
- // Standard Dat parsing
- string filename,
- int indexId)
- {
- string hash = string.Empty,
- offset = string.Empty,
- type = string.Empty,
- remark = string.Empty;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the dump
- switch (reader.Name)
- {
- case "hash":
- hash = reader.ReadElementContentAsString();
- break;
-
- case "start":
- offset = reader.ReadElementContentAsString();
- break;
-
- case "type":
- reader.ReadElementContentAsString();
- break;
-
- case "remark":
- remark = reader.ReadElementContentAsString();
- break;
-
- default:
- reader.Read();
- break;
- }
- }
-
- // If we got a hash, then create and return the item
- if (!string.IsNullOrWhiteSpace(hash))
- {
- return new Rom
- {
- Name = machine.Name + "_" + diskno + (!string.IsNullOrWhiteSpace(remark) ? " " + remark : string.Empty),
- Offset = offset,
- Size = null,
- SHA1 = hash,
-
- Source = new Source
- {
- Index = indexId,
- Name = filename,
- },
-
- OpenMSXSubType = OpenMSXSubType.MegaRom,
- OpenMSXType = type,
- Remark = remark,
- };
- }
-
- // No valid item means returning null
- return null;
- }
-
- ///
- /// Read sccpluscart information
- ///
- /// XmlReader representing a sccpluscart block
- /// Machine information to pass to contained items
- /// Disk number to use when outputting to other DAT formats
- /// Name of the file to be parsed
- /// Index ID for the DAT
- private DatItem ReadSccPlusCart(
- XmlReader reader,
- Machine machine,
- int diskno,
-
- // Standard Dat parsing
- string filename,
- int indexId)
- {
- string boot = string.Empty,
- hash = string.Empty,
- remark = string.Empty;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the dump
- switch (reader.Name)
- {
- case "boot":
- boot = reader.ReadElementContentAsString();
- break;
-
- case "hash":
- hash = reader.ReadElementContentAsString();
- break;
-
- case "remark":
- remark = reader.ReadElementContentAsString();
- break;
-
- default:
- reader.Read();
- break;
- }
- }
-
- // If we got a hash, then create and return the item
- if (!string.IsNullOrWhiteSpace(hash))
- {
- return new Rom
- {
- Name = machine.Name + "_" + diskno + (!string.IsNullOrWhiteSpace(remark) ? " " + remark : string.Empty),
- Size = null,
- SHA1 = hash,
-
- Source = new Source
- {
- Index = indexId,
- Name = filename,
- },
-
- OpenMSXSubType = OpenMSXSubType.SCCPlusCart,
- Boot = boot,
- Remark = remark,
- };
- }
-
- // No valid item means returning null
- return null;
- }
+ #endregion
}
}
diff --git a/SabreTools.Test/Serialization/SerializationTests.cs b/SabreTools.Test/Serialization/SerializationTests.cs
index d589ed16..e31e410d 100644
--- a/SabreTools.Test/Serialization/SerializationTests.cs
+++ b/SabreTools.Test/Serialization/SerializationTests.cs
@@ -18,7 +18,7 @@ namespace SabreTools.Test.Parser
Assert.NotNull(stream);
byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(stream.GetBuffer());
string hashstr = BitConverter.ToString(hash).Replace("-", string.Empty);
- Assert.Equal("195D11C8A93D73F9FBF1ECD8166D80D7BB1B0974", hashstr);
+ Assert.Equal("268940391C107ABE67E804BC5479E40B5FF68B34", hashstr);
}
#region Payload Generators