diff --git a/SabreTools.Helper/Objects/Dat/DatFile.cs b/SabreTools.Helper/Objects/Dat/DatFile.cs
index 33093cf2..3b1881b6 100644
--- a/SabreTools.Helper/Objects/Dat/DatFile.cs
+++ b/SabreTools.Helper/Objects/Dat/DatFile.cs
@@ -8,6 +8,8 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
+using System.Xml.Linq;
+using System.Xml.Schema;
namespace SabreTools.Helper
{
@@ -386,7 +388,7 @@ namespace SabreTools.Helper
_md5Count = 0;
_sha1Count = 0;
_nodumpCount = 0;
- }
+ }
#endregion
@@ -3083,6 +3085,851 @@ namespace SabreTools.Helper
xtr.Dispose();
}
+ ///
+ /// Parse an XML DAT (Logiqx, OfflineList, SabreDAT, and Software List) and return all found games and roms within
+ ///
+ /// Name of the file to be parsed
+ /// System ID for the DAT
+ /// Source ID for the DAT
+ /// Name of the game to match (can use asterisk-partials)
+ /// Name of the rom to match (can use asterisk-partials)
+ /// Type of the rom to match
+ /// Find roms greater than or equal to this size
+ /// Find roms less than or equal to this size
+ /// Find roms equal to this size
+ /// CRC of the rom to match (can use asterisk-partials)
+ /// MD5 of the rom to match (can use asterisk-partials)
+ /// SHA-1 of the rom to match (can use asterisk-partials)
+ /// Select roms with the given status
+ /// True if we are supposed to trim names to NTFS length, false otherwise
+ /// True if all games should be replaced by '!', false otherwise
+ /// String representing root directory to compare against for length calculation
+ /// Logger object for console and/or file output
+ /// True if full pathnames are to be kept, false otherwise (default)
+ /// True if game names are sanitized, false otherwise (default)
+ /// True if SL XML names should be kept, false otherwise (default)
+ private void ParseXMLLinq(
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Rom filtering
+ string gamename,
+ string romname,
+ string romtype,
+ long sgt,
+ long slt,
+ long seq,
+ string crc,
+ string md5,
+ string sha1,
+ ItemStatus itemStatus,
+
+ // Rom renaming
+ bool trim,
+ bool single,
+ string root,
+
+ // Miscellaneous
+ Logger logger,
+ bool keep,
+ bool clean,
+ bool softlist)
+
+ {
+ // Prepare all internal variables
+ bool superdat = false, empty = true;
+ string key = "", date = "";
+ long size = -1;
+ ItemStatus its = ItemStatus.None;
+ List parent = new List();
+
+ Encoding enc = Style.GetEncoding(filename);
+ XElement xtr = XElement.Load(FileTools.GetXmlTextReader(filename, logger), LoadOptions.None);
+
+ // If we got a null reader, just return
+ if (xtr == null)
+ {
+ return;
+ }
+
+ // Otherwise, read the file to the end
+ foreach (XElement node in xtr.Nodes())
+ {
+ // If we're ending a folder or game, take care of possibly empty games and removing from the parent
+ if (node.NodeType == XmlNodeType.EndElement && (node.Name == "directory" || node.Name == "dir"))
+ {
+ // If we didn't find any items in the folder, make sure to add the blank rom
+ if (empty)
+ {
+ string tempgame = String.Join("\\", parent);
+ Rom rom = new Rom("null", tempgame);
+
+ // Now process and add the rom
+ ParseAddHelper(rom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+ }
+
+ // Regardless, end the current folder
+ int parentcount = parent.Count;
+ if (parentcount == 0)
+ {
+ logger.Verbose("Empty parent: " + String.Join("\\", parent));
+ empty = true;
+ }
+
+ // If we have an end folder element, remove one item from the parent, if possible
+ if (parentcount > 0)
+ {
+ parent.RemoveAt(parent.Count - 1);
+ if (keep && parentcount > 1)
+ {
+ Type = (String.IsNullOrEmpty(Type) ? "SuperDAT" : Type);
+ superdat = true;
+ }
+ }
+ }
+
+ // We only want elements
+ if (node.NodeType != XmlNodeType.Element)
+ {
+ continue;
+ }
+
+ switch (node.Name.ToString())
+ {
+ // Handle MAME listxml since they're halfway between a SL and a Logiqx XML
+ case "mame":
+ if (node.Attribute("build") != null)
+ {
+ Name = (String.IsNullOrEmpty(Name) ? node.Attribute("build").ToString() : Name);
+ Description = (String.IsNullOrEmpty(Description) ? Name : Name);
+ }
+ break;
+ // New software lists have this behavior
+ case "softwarelist":
+ if (node.Attribute("name") != null)
+ {
+ Name = (String.IsNullOrEmpty(Name) ? node.Attribute("name").ToString() : Name);
+ }
+ if (node.Attribute("description") != null)
+ {
+ Description = (String.IsNullOrEmpty(Description) ? node.Attribute("description").ToString() : Description);
+ }
+ if (node.Attribute("forcemerging") != null)
+ {
+ switch (node.Attribute("forcemerging").ToString())
+ {
+ case "split":
+ ForceMerging = ForceMerging.Split;
+ break;
+ case "none":
+ ForceMerging = ForceMerging.None;
+ break;
+ case "full":
+ ForceMerging = ForceMerging.Full;
+ break;
+ }
+ }
+ if (node.Attribute("forceitemStatus") != null)
+ {
+ switch (node.Attribute("forceitemStatus").ToString())
+ {
+ case "obsolete":
+ ForceNodump = ForceNodump.Obsolete;
+ break;
+ case "required":
+ ForceNodump = ForceNodump.Required;
+ break;
+ case "ignore":
+ ForceNodump = ForceNodump.Ignore;
+ break;
+ }
+ }
+ if (node.Attribute("forcepacking") != null)
+ {
+ switch (node.Attribute("forcepacking").ToString())
+ {
+ case "zip":
+ ForcePacking = ForcePacking.Zip;
+ break;
+ case "unzip":
+ ForcePacking = ForcePacking.Unzip;
+ break;
+ }
+ }
+ break;
+ // Handle M1 DATs since they're 99% the same as a SL DAT
+ case "m1":
+ Name = (String.IsNullOrEmpty(Name) ? "M1" : Name);
+ Description = (String.IsNullOrEmpty(Description) ? "M1" : Description);
+ if (node.Attribute("version") != null)
+ {
+ Version = (String.IsNullOrEmpty(Version) ? node.Attribute("version").ToString() : Version);
+ }
+ break;
+ // OfflineList has a different header format
+ case "configuration":
+ // If there's no subtree to the header, skip it
+ if (!node.HasElements)
+ {
+ continue;
+ }
+
+ // Otherwise, read what we can from the header
+ foreach (XElement headnode in node.Elements())
+ {
+ // We only want elements
+ if (headnode.NodeType != XmlNodeType.Element || headnode.Name == "configuration")
+ {
+ continue;
+ }
+
+ // Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
+ string content = "";
+ switch (headnode.Name.ToString().ToLowerInvariant())
+ {
+ case "datname":
+ content = headnode.Value;
+ Name = (String.IsNullOrEmpty(Name) ? content : Name);
+ superdat = superdat || content.Contains(" - SuperDAT");
+ if (keep && superdat)
+ {
+ Type = (String.IsNullOrEmpty(Type) ? "SuperDAT" : Type);
+ }
+ break;
+ case "datversionurl":
+ content = headnode.Value;
+ Url = (String.IsNullOrEmpty(Name) ? content : Url);
+ break;
+ default:
+ break;
+ }
+ }
+
+ break;
+ // We want to process the entire subtree of the header
+ case "header":
+ // If there's no subtree to the header, skip it
+ if (!node.HasElements)
+ {
+ continue;
+ }
+
+ // Otherwise, read what we can from the header
+ foreach (XElement headnode in node.Elements())
+ {
+ // We only want elements
+ if (headnode.NodeType != XmlNodeType.Element || headnode.Name == "header")
+ {
+ continue;
+ }
+
+ // Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
+ string content = "";
+ switch (headnode.Name.ToString())
+ {
+ case "name":
+ content = headnode.Value;
+ Name = (String.IsNullOrEmpty(Name) ? content : Name);
+ superdat = superdat || content.Contains(" - SuperDAT");
+ if (keep && superdat)
+ {
+ Type = (String.IsNullOrEmpty(Type) ? "SuperDAT" : Type);
+ }
+ break;
+ case "description":
+ content = headnode.Value;
+ Description = (String.IsNullOrEmpty(Description) ? content : Description);
+ break;
+ case "rootdir":
+ content = headnode.Value;
+ RootDir = (String.IsNullOrEmpty(RootDir) ? content : RootDir);
+ break;
+ case "category":
+ content = headnode.Value;
+ Category = (String.IsNullOrEmpty(Category) ? content : Category);
+ break;
+ case "version":
+ content = headnode.Value;
+ Version = (String.IsNullOrEmpty(Version) ? content : Version);
+ break;
+ case "date":
+ content = headnode.Value;
+ Date = (String.IsNullOrEmpty(Date) ? content.Replace(".", "/") : Date);
+ break;
+ case "author":
+ content = headnode.Value;
+ Author = (String.IsNullOrEmpty(Author) ? content : Author);
+
+ // Special cases for SabreDAT
+ Email = (String.IsNullOrEmpty(Email) && headnode.Attribute("email") != null ?
+ headnode.Attribute("email").ToString() : Email);
+ Homepage = (String.IsNullOrEmpty(Homepage) && headnode.Attribute("homepage") != null ?
+ headnode.Attribute("homepage").ToString() : Email);
+ Url = (String.IsNullOrEmpty(Url) && headnode.Attribute("url") != null ?
+ headnode.Attribute("url").ToString() : Email);
+ break;
+ case "email":
+ content = headnode.Value;
+ Email = (String.IsNullOrEmpty(Email) ? content : Email);
+ break;
+ case "homepage":
+ content = headnode.Value;
+ Homepage = (String.IsNullOrEmpty(Homepage) ? content : Homepage);
+ break;
+ case "url":
+ content = headnode.Value;
+ Url = (String.IsNullOrEmpty(Url) ? content : Url);
+ break;
+ case "comment":
+ content = headnode.Value;
+ Comment = (String.IsNullOrEmpty(Comment) ? content : Comment);
+ break;
+ case "type":
+ content = headnode.Value;
+ Type = (String.IsNullOrEmpty(Type) ? content : Type);
+ superdat = superdat || content.Contains("SuperDAT");
+ break;
+ case "clrmamepro":
+ case "romcenter":
+ if (headnode.Attribute("header") != null)
+ {
+ Header = (String.IsNullOrEmpty(Header) ? headnode.Attribute("header").ToString() : Header);
+ }
+ if (headnode.Attribute("plugin") != null)
+ {
+ Header = (String.IsNullOrEmpty(Header) ? headnode.Attribute("plugin").ToString() : Header);
+ }
+ if (headnode.Attribute("forcemerging") != null)
+ {
+ switch (headnode.Attribute("forcemerging").ToString())
+ {
+ case "split":
+ ForceMerging = ForceMerging.Split;
+ break;
+ case "none":
+ ForceMerging = ForceMerging.None;
+ break;
+ case "full":
+ ForceMerging = ForceMerging.Full;
+ break;
+ }
+ }
+ if (headnode.Attribute("forceitemStatus") != null)
+ {
+ switch (headnode.Attribute("forceitemStatus").ToString())
+ {
+ case "obsolete":
+ ForceNodump = ForceNodump.Obsolete;
+ break;
+ case "required":
+ ForceNodump = ForceNodump.Required;
+ break;
+ case "ignore":
+ ForceNodump = ForceNodump.Ignore;
+ break;
+ }
+ }
+ if (headnode.Attribute("forcepacking") != null)
+ {
+ switch (headnode.Attribute("forcepacking").ToString())
+ {
+ case "zip":
+ ForcePacking = ForcePacking.Zip;
+ break;
+ case "unzip":
+ ForcePacking = ForcePacking.Unzip;
+ break;
+ }
+ }
+ break;
+ case "flags":
+ // If there's no subtree to the flags, skip it
+ if (!headnode.HasElements)
+ {
+ continue;
+ }
+
+ // Otherwise, read what we can from the flags
+ foreach (XElement flagnode in node.Elements())
+ {
+ // We only want elements
+ if (flagnode.NodeType != XmlNodeType.Element || flagnode.Name == "flags")
+ {
+ continue;
+ }
+
+ switch (flagnode.Name.ToString())
+ {
+ case "flag":
+ if (flagnode.Attribute("name") != null && flagnode.Attribute("value") != null)
+ {
+ content = flagnode.Attribute("value").ToString();
+ switch (flagnode.Attribute("name").ToString())
+ {
+ case "type":
+ Type = (String.IsNullOrEmpty(Type) ? content : Type);
+ superdat = superdat || content.Contains("SuperDAT");
+ break;
+ case "forcemerging":
+ switch (content)
+ {
+ case "split":
+ ForceMerging = ForceMerging.Split;
+ break;
+ case "none":
+ ForceMerging = ForceMerging.None;
+ break;
+ case "full":
+ ForceMerging = ForceMerging.Full;
+ break;
+ }
+ break;
+ case "forceitemStatus":
+ switch (content)
+ {
+ case "obsolete":
+ ForceNodump = ForceNodump.Obsolete;
+ break;
+ case "required":
+ ForceNodump = ForceNodump.Required;
+ break;
+ case "ignore":
+ ForceNodump = ForceNodump.Ignore;
+ break;
+ }
+ break;
+ case "forcepacking":
+ switch (content)
+ {
+ case "zip":
+ ForcePacking = ForcePacking.Zip;
+ break;
+ case "unzip":
+ ForcePacking = ForcePacking.Unzip;
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case "machine":
+ case "game":
+ case "software":
+ string temptype = node.Name.ToString();
+ string tempname = "", gamedesc = "", romof = "",
+ cloneof = "", sampleof = "", year = "", manufacturer = "";
+
+ // If there's no subtree to the header, skip it
+ if (!node.HasElements)
+ {
+ continue;
+ }
+
+ // Otherwise, add what is possible
+ if (!softlist && temptype == "software" && node.Element("description") != null)
+ {
+ tempname = node.Element("description").Value;
+ gamedesc = tempname;
+ tempname = tempname.Replace('/', '_').Replace("\"", "''");
+ }
+ else
+ {
+ tempname = node.Attribute("name").ToString();
+ romof = (node.Attribute("romof") != null ? node.Attribute("romof").ToString() : "");
+ cloneof = (node.Attribute("cloneof") != null ? node.Attribute("cloneof").ToString() : "");
+ sampleof = (node.Attribute("sampleof") != null ? node.Attribute("sampleof").ToString() : "");
+ }
+
+ if (superdat && !keep)
+ {
+ string tempout = Regex.Match(tempname, @".*?\\(.*)").Groups[1].Value;
+ if (tempout != "")
+ {
+ tempname = tempout;
+ }
+ }
+ // Get the name of the game from the parent
+ else if (superdat && keep && parent.Count > 0)
+ {
+ tempname = String.Join("\\", parent) + "\\" + tempname;
+ }
+
+ // Special offline list parts
+ string ext = "";
+ string releaseNumber = "";
+
+ // Now loop through the rest of the child nodes
+ foreach (XElement gamenode in node.Elements())
+ {
+ // We only want elements
+ if (gamenode.NodeType != XmlNodeType.Element)
+ {
+ continue;
+ }
+
+ // Get the roms from the machine
+ switch (gamenode.Name.ToString())
+ {
+ // For offline lists only
+ case "title":
+ tempname = gamenode.Value;
+ break;
+ case "releaseNumber":
+ releaseNumber = gamenode.Value;
+ break;
+ case "romSize":
+ if (!Int64.TryParse(gamenode.Value, out size))
+ {
+ size = -1;
+ }
+ break;
+ case "romCRC":
+ empty = false;
+
+ ext = (gamenode.Attribute("extension") != null ? gamenode.Attribute("extension").ToString() : "");
+
+ DatItem olrom = new Rom(releaseNumber + " - " + tempname + ext, size, gamenode.Value, null, null, ItemStatus.None,
+ null, tempname, null, tempname, null, null, null, null, null, null, false, null, null, sysid, null, srcid, "");
+
+ // Now process and add the rom
+ ParseAddHelper(olrom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+ break;
+
+ // For Logiqx, SabreDAT, and Software List
+ case "description":
+ gamedesc = gamenode.Value;
+ break;
+ case "year":
+ year = gamenode.Value;
+ break;
+ case "manufacturer":
+ manufacturer = gamenode.Value;
+ break;
+ case "release":
+ empty = false;
+
+ bool? defaultrel = null;
+ if (gamenode.Attribute("default") != null)
+ {
+ if (gamenode.Attribute("default").ToString() == "yes")
+ {
+ defaultrel = true;
+ }
+ else if (gamenode.Attribute("default").ToString() == "no")
+ {
+ defaultrel = false;
+ }
+ }
+
+ DatItem relrom = new Release(gamenode.Attribute("name").ToString(),
+ gamenode.Attribute("region").ToString(), gamenode.Attribute("language").ToString(), date, defaultrel);
+
+ // Now process and add the rom
+ ParseAddHelper(relrom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+ break;
+ case "biosset":
+ empty = false;
+
+ bool? defaultbios = null;
+ if (gamenode.Attribute("default") != null)
+ {
+ if (gamenode.Attribute("default").ToString() == "yes")
+ {
+ defaultbios = true;
+ }
+ else if (gamenode.Attribute("default").ToString() == "no")
+ {
+ defaultbios = false;
+ }
+ }
+
+ DatItem biosrom = new BiosSet(gamenode.Attribute("name").ToString(), gamenode.Attribute("description").ToString(), defaultbios,
+ tempname, null, gamedesc, null, null, romof, cloneof, sampleof, null, false, null, null, sysid, filename, srcid, null);
+
+ // Now process and add the rom
+ ParseAddHelper(biosrom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+ break;
+ case "archive":
+ empty = false;
+
+ DatItem archiverom = new Archive(gamenode.Attribute("name").ToString(), tempname, null, gamedesc, null, null,
+ romof, cloneof, sampleof, null, false, null, null, sysid, filename, srcid, null);
+
+ // Now process and add the rom
+ ParseAddHelper(archiverom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+ break;
+ case "sample":
+ empty = false;
+
+ DatItem samplerom = new Sample(gamenode.Attribute("name").ToString(), tempname, null, gamedesc, null, null,
+ romof, cloneof, sampleof, null, false, null, null, sysid, filename, srcid, null);
+
+ // Now process and add the rom
+ ParseAddHelper(samplerom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+ break;
+ case "rom":
+ case "disk":
+ empty = false;
+
+ // If the rom has a status, flag it
+ its = ItemStatus.None;
+ if (gamenode.Attribute("flags").ToString() == "good" || gamenode.Attribute("status").ToString() == "good")
+ {
+ its = ItemStatus.Good;
+ }
+ if (gamenode.Attribute("flags").ToString() == "baddump" || gamenode.Attribute("status").ToString() == "baddump")
+ {
+ logger.Verbose("Bad dump detected: " +
+ (gamenode.Attribute("name") != null ? "\"" + node.Attribute("name") + "\"" : "ROM NAME NOT FOUND"));
+ its = ItemStatus.BadDump;
+ }
+ if (gamenode.Attribute("flags").ToString() == "itemStatus" || gamenode.Attribute("status").ToString() == "itemStatus")
+ {
+ logger.Verbose("Nodump detected: " +
+ (gamenode.Attribute("name") != null ? "\"" + node.Attribute("name") + "\"" : "ROM NAME NOT FOUND"));
+ its = ItemStatus.Nodump;
+ }
+ if (gamenode.Attribute("flags").ToString() == "verified" || gamenode.Attribute("status").ToString() == "verified")
+ {
+ its = ItemStatus.Verified;
+ }
+
+ // If the rom has a Date attached, read it in and then sanitize it
+ date = "";
+ if (gamenode.Attribute("date") != null)
+ {
+ DateTime dateTime = DateTime.Now;
+ if (DateTime.TryParse(gamenode.Attribute("date").ToString(), out dateTime))
+ {
+ date = dateTime.ToString();
+ }
+ else
+ {
+ date = gamenode.Attribute("date").ToString();
+ }
+ }
+
+ // Take care of hex-sized files
+ size = -1;
+ if (gamenode.Attribute("size") != null && gamenode.Attribute("size").ToString().Contains("0x"))
+ {
+ size = Convert.ToInt64(gamenode.Attribute("size").ToString(), 16);
+ }
+ else if (gamenode.Attribute("size") != null)
+ {
+ Int64.TryParse(gamenode.Attribute("size").ToString(), out size);
+ }
+
+ // If the rom is continue or ignore, add the size to the previous rom
+ if (gamenode.Attribute("loadflag").ToString() == "continue" || gamenode.Attribute("loadflag").ToString() == "ignore")
+ {
+ int index = Files[key].Count() - 1;
+ DatItem lastrom = Files[key][index];
+ if (lastrom.Type == ItemType.Rom)
+ {
+ ((Rom)lastrom).Size += size;
+ }
+ Files[key].RemoveAt(index);
+ Files[key].Add(lastrom);
+ continue;
+ }
+
+ // If we're in clean mode, sanitize the game name
+ if (clean)
+ {
+ tempname = Style.CleanGameName(tempname.Split(Path.DirectorySeparatorChar));
+ }
+
+ DatItem inrom;
+ switch (gamenode.Name.ToString().ToLowerInvariant())
+ {
+ case "disk":
+ inrom = new Disk(gamenode.Attribute("name").ToString(), gamenode.Attribute("md5").ToString(), gamenode.Attribute("sha1").ToString(),
+ its, tempname, null, gamedesc, null, null, romof, cloneof, sampleof, null, false, null, null, sysid,
+ filename, srcid, null);
+ break;
+ case "rom":
+ default:
+ inrom = new Rom(gamenode.Attribute("name").ToString(), size, gamenode.Attribute("crc").ToString(), gamenode.Attribute("md5").ToString(),
+ gamenode.Attribute("sha1").ToString(), its, date, tempname, null, gamedesc, null, null, romof, cloneof, sampleof,
+ null, false, null, null, sysid, filename, srcid, null);
+ break;
+ }
+
+ // Now process and add the rom
+ ParseAddHelper(inrom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // If we didn't find any items in the folder, make sure to add the blank rom
+ if (empty)
+ {
+ tempname = (parent.Count > 0 ? String.Join("\\", parent) + Path.DirectorySeparatorChar : "") + tempname;
+
+ Rom inrom = new Rom("null", tempname);
+
+ // Now process and add the rom
+ ParseAddHelper(inrom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+
+ // Regardless, end the current folder
+ if (parent.Count == 0)
+ {
+ empty = true;
+ }
+ }
+ break;
+ case "dir":
+ case "directory":
+ // Set SuperDAT flag for all SabreDAT inputs, regardless of depth
+ superdat = true;
+ if (keep)
+ {
+ Type = (Type == "" ? "SuperDAT" : Type);
+ }
+
+ string foldername = (node.Attribute("name") == null ? "" : node.Attribute("name").ToString());
+ if (foldername != "")
+ {
+ parent.Add(foldername);
+ }
+ break;
+ case "file":
+ empty = false;
+
+ // If the rom is itemStatus, flag it
+ its = ItemStatus.None;
+ // If there's no subtree to the flags, skip it
+ if (!node.HasElements)
+ {
+ continue;
+ }
+
+ // Otherwise, read what we can from the flags
+ foreach (XElement flagnode in node.Elements())
+ {
+ // We only want elements
+ if (flagnode.NodeType != XmlNodeType.Element || flagnode.Name == "flags")
+ {
+ continue;
+ }
+
+ switch (flagnode.Name.ToString())
+ {
+ case "flag":
+ case "status":
+ if (flagnode.Attribute("name") != null && flagnode.Attribute("value") != null)
+ {
+ string content = flagnode.Attribute("value").ToString();
+ switch (flagnode.Attribute("name").ToString())
+ {
+ case "good":
+ its = ItemStatus.Good;
+ break;
+ case "baddump":
+ logger.Verbose("Bad dump detected: " + (node.Attribute("name") != null ?
+ "\"" + node.Attribute("name") + "\"" : "ROM NAME NOT FOUND"));
+ its = ItemStatus.BadDump;
+ break;
+ case "itemStatus":
+ logger.Verbose("Nodump detected: " + (node.Attribute("name") != null ?
+ "\"" + node.Attribute("name") + "\"" : "ROM NAME NOT FOUND"));
+ its = ItemStatus.Nodump;
+ break;
+ case "verified":
+ its = ItemStatus.Verified;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ // If the rom has a Date attached, read it in and then sanitize it
+ date = "";
+ if (node.Attribute("date") != null)
+ {
+ date = DateTime.Parse(node.Attribute("date").ToString()).ToString();
+ }
+
+ // Take care of hex-sized files
+ size = -1;
+ if (node.Attribute("size") != null && node.Attribute("size").ToString().Contains("0x"))
+ {
+ size = Convert.ToInt64(node.Attribute("size").ToString(), 16);
+ }
+ else if (node.Attribute("size") != null)
+ {
+ Int64.TryParse(node.Attribute("size").ToString(), out size);
+ }
+
+ // If the rom is continue or ignore, add the size to the previous rom
+ if (node.Attribute("loadflag").ToString() == "continue" || node.Attribute("loadflag").ToString() == "ignore")
+ {
+ int index = Files[key].Count() - 1;
+ DatItem lastrom = Files[key][index];
+ if (lastrom.Type == ItemType.Rom)
+ {
+ ((Rom)lastrom).Size += size;
+ }
+ Files[key].RemoveAt(index);
+ Files[key].Add(lastrom);
+ continue;
+ }
+
+ // Get the name of the game from the parent
+ tempname = String.Join("\\", parent);
+
+ // If we aren't keeping names, trim out the path
+ if (!keep || !superdat)
+ {
+ string tempout = Regex.Match(tempname, @".*?\\(.*)").Groups[1].Value;
+ if (tempout != "")
+ {
+ tempname = tempout;
+ }
+ }
+
+ DatItem rom;
+ switch (node.Attribute("type").ToString().ToLowerInvariant())
+ {
+ case "disk":
+ rom = new Disk(node.Attribute("name").ToString(), node.Attribute("md5")?.ToString().ToLowerInvariant(),
+ node.Attribute("sha1")?.ToString().ToLowerInvariant(), its, tempname, null, tempname, null, null,
+ null, null, null, null, false, null, null, sysid, filename, srcid, null);
+ break;
+ case "rom":
+ default:
+ rom = new Rom(node.Attribute("name").ToString(), size, node.Attribute("crc")?.ToString().ToLowerInvariant(),
+ node.Attribute("md5")?.ToString().ToLowerInvariant(), node.Attribute("sha1")?.ToString().ToLowerInvariant(), its,
+ date, tempname, null, tempname, null, null, null, null, null, null, false, null, null, sysid, filename,
+ srcid, null);
+ break;
+ }
+
+ // Now process and add the rom
+ ParseAddHelper(rom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, itemStatus, trim, single, root, clean, logger, out key);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
///
/// Add a rom to the Dat after checking
///