diff --git a/SabreTools.Library/DatFiles/SabreDat.cs b/SabreTools.Library/DatFiles/SabreDat.cs
index 78e787b4..a349637b 100644
--- a/SabreTools.Library/DatFiles/SabreDat.cs
+++ b/SabreTools.Library/DatFiles/SabreDat.cs
@@ -37,7 +37,7 @@ namespace SabreTools.Library.DatFiles
}
///
- /// Parse an SabreDat XML DAT and return all found games and roms within
+ /// Parse an SabreDat XML DAT and return all found directories and files within
///
/// Name of the file to be parsed
/// System ID for the DAT
@@ -45,8 +45,6 @@ namespace SabreTools.Library.DatFiles
/// True if full pathnames are to be kept, false otherwise (default)
/// True if game names are sanitized, false otherwise (default)
/// True if we should remove non-ASCII characters from output, false otherwise (default)
- ///
- ///
public override void ParseFile(
// Standard Dat parsing
string filename,
@@ -64,11 +62,8 @@ namespace SabreTools.Library.DatFiles
return;
// Prepare all internal variables
- XmlReader subreader, headreader, flagreader;
- bool superdat = false, empty = true;
- string key = "", date = "";
- long size = -1;
- ItemStatus its = ItemStatus.None;
+ bool empty = true;
+ string key = "";
List parent = new List();
Encoding enc = Utilities.GetEncoding(filename);
@@ -114,7 +109,6 @@ namespace SabreTools.Library.DatFiles
if (keep && parentcount > 1)
{
Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
- superdat = true;
}
}
}
@@ -128,916 +122,18 @@ namespace SabreTools.Library.DatFiles
switch (xtr.Name)
{
- // Handle MAME listxml since they're halfway between a SL and a Logiqx XML
- case "mame":
- if (xtr.GetAttribute("build") != null)
- {
- Name = (String.IsNullOrWhiteSpace(Name) ? xtr.GetAttribute("build") : Name);
- Description = (String.IsNullOrWhiteSpace(Description) ? Name : Name);
- }
- xtr.Read();
- break;
- // New software lists have this behavior
- case "softwarelist":
- if (xtr.GetAttribute("name") != null)
- {
- Name = (String.IsNullOrWhiteSpace(Name) ? xtr.GetAttribute("name") : Name);
- }
- if (xtr.GetAttribute("description") != null)
- {
- Description = (String.IsNullOrWhiteSpace(Description) ? xtr.GetAttribute("description") : Description);
- }
- if (ForceMerging == ForceMerging.None)
- {
- ForceMerging = Utilities.GetForceMerging(xtr.GetAttribute("forcemerging"));
- }
- if (ForceNodump == ForceNodump.None)
- {
- ForceNodump = Utilities.GetForceNodump(xtr.GetAttribute("forcenodump"));
- }
- if (ForcePacking == ForcePacking.None)
- {
- ForcePacking = Utilities.GetForcePacking(xtr.GetAttribute("forcepacking"));
- }
- xtr.Read();
- break;
- // Handle M1 DATs since they're 99% the same as a SL DAT
- case "m1":
- Name = (String.IsNullOrWhiteSpace(Name) ? "M1" : Name);
- Description = (String.IsNullOrWhiteSpace(Description) ? "M1" : Description);
- if (xtr.GetAttribute("version") != null)
- {
- Version = (String.IsNullOrWhiteSpace(Version) ? xtr.GetAttribute("version") : Version);
- }
- xtr.Read();
- break;
- // OfflineList has a different header format
- case "configuration":
- headreader = xtr.ReadSubtree();
-
- // If there's no subtree to the header, skip it
- if (headreader == null)
- {
- xtr.Skip();
- continue;
- }
-
- // Otherwise, read what we can from the header
- while (!headreader.EOF)
- {
- // We only want elements
- if (headreader.NodeType != XmlNodeType.Element || headreader.Name == "configuration")
- {
- headreader.Read();
- continue;
- }
-
- // Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
- string content = "";
- switch (headreader.Name.ToLowerInvariant())
- {
- case "datname":
- content = headreader.ReadElementContentAsString(); ;
- Name = (String.IsNullOrWhiteSpace(Name) ? content : Name);
- superdat = superdat || content.Contains(" - SuperDAT");
- if (keep && superdat)
- {
- Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
- }
- break;
- case "datversionurl":
- content = headreader.ReadElementContentAsString(); ;
- Url = (String.IsNullOrWhiteSpace(Name) ? content : Url);
- break;
- default:
- headreader.Read();
- break;
- }
- }
-
- break;
// We want to process the entire subtree of the header
case "header":
- headreader = xtr.ReadSubtree();
-
- // If there's no subtree to the header, skip it
- if (headreader == null)
- {
- xtr.Skip();
- continue;
- }
-
- // Otherwise, read what we can from the header
- while (!headreader.EOF)
- {
- // We only want elements
- if (headreader.NodeType != XmlNodeType.Element || headreader.Name == "header")
- {
- headreader.Read();
- continue;
- }
-
- // Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
- string content = "";
- switch (headreader.Name)
- {
- case "name":
- content = headreader.ReadElementContentAsString(); ;
- Name = (String.IsNullOrWhiteSpace(Name) ? content : Name);
- superdat = superdat || content.Contains(" - SuperDAT");
- if (keep && superdat)
- {
- Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
- }
- break;
- case "description":
- content = headreader.ReadElementContentAsString();
- Description = (String.IsNullOrWhiteSpace(Description) ? content : Description);
- break;
- case "rootdir":
- content = headreader.ReadElementContentAsString();
- RootDir = (String.IsNullOrWhiteSpace(RootDir) ? content : RootDir);
- break;
- case "category":
- content = headreader.ReadElementContentAsString();
- Category = (String.IsNullOrWhiteSpace(Category) ? content : Category);
- break;
- case "version":
- content = headreader.ReadElementContentAsString();
- Version = (String.IsNullOrWhiteSpace(Version) ? content : Version);
- break;
- case "date":
- content = headreader.ReadElementContentAsString();
- Date = (String.IsNullOrWhiteSpace(Date) ? content.Replace(".", "/") : Date);
- break;
- case "author":
- content = headreader.ReadElementContentAsString();
- Author = (String.IsNullOrWhiteSpace(Author) ? content : Author);
-
- // Special cases for SabreDAT
- Email = (String.IsNullOrWhiteSpace(Email) && !String.IsNullOrWhiteSpace(headreader.GetAttribute("email")) ?
- headreader.GetAttribute("email") : Email);
- Homepage = (String.IsNullOrWhiteSpace(Homepage) && !String.IsNullOrWhiteSpace(headreader.GetAttribute("homepage")) ?
- headreader.GetAttribute("homepage") : Homepage);
- Url = (String.IsNullOrWhiteSpace(Url) && !String.IsNullOrWhiteSpace(headreader.GetAttribute("url")) ?
- headreader.GetAttribute("url") : Url);
- break;
- case "email":
- content = headreader.ReadElementContentAsString();
- Email = (String.IsNullOrWhiteSpace(Email) ? content : Email);
- break;
- case "homepage":
- content = headreader.ReadElementContentAsString();
- Homepage = (String.IsNullOrWhiteSpace(Homepage) ? content : Homepage);
- break;
- case "url":
- content = headreader.ReadElementContentAsString();
- Url = (String.IsNullOrWhiteSpace(Url) ? content : Url);
- break;
- case "comment":
- content = headreader.ReadElementContentAsString();
- Comment = (String.IsNullOrWhiteSpace(Comment) ? content : Comment);
- break;
- case "type":
- content = headreader.ReadElementContentAsString();
- Type = (String.IsNullOrWhiteSpace(Type) ? content : Type);
- superdat = superdat || content.Contains("SuperDAT");
- break;
- case "clrmamepro":
- case "romcenter":
- if (headreader.GetAttribute("header") != null)
- {
- Header = (String.IsNullOrWhiteSpace(Header) ? headreader.GetAttribute("header") : Header);
- }
- if (headreader.GetAttribute("plugin") != null)
- {
- Header = (String.IsNullOrWhiteSpace(Header) ? headreader.GetAttribute("plugin") : Header);
- }
- if (ForceMerging == ForceMerging.None)
- {
- ForceMerging = Utilities.GetForceMerging(headreader.GetAttribute("forcemerging"));
- }
- if (ForceNodump == ForceNodump.None)
- {
- ForceNodump = Utilities.GetForceNodump(headreader.GetAttribute("forcenodump"));
- }
- if (ForcePacking == ForcePacking.None)
- {
- ForcePacking = Utilities.GetForcePacking(headreader.GetAttribute("forcepacking"));
- }
- headreader.Read();
- break;
- case "flags":
- flagreader = xtr.ReadSubtree();
-
- // If we somehow have a null flag section, skip it
- if (flagreader == null)
- {
- xtr.Skip();
- continue;
- }
-
- while (!flagreader.EOF)
- {
- // We only want elements
- if (flagreader.NodeType != XmlNodeType.Element || flagreader.Name == "flags")
- {
- flagreader.Read();
- continue;
- }
-
- switch (flagreader.Name)
- {
- case "flag":
- if (flagreader.GetAttribute("name") != null && flagreader.GetAttribute("value") != null)
- {
- content = flagreader.GetAttribute("value");
- switch (flagreader.GetAttribute("name"))
- {
- case "type":
- Type = (String.IsNullOrWhiteSpace(Type) ? content : Type);
- superdat = superdat || content.Contains("SuperDAT");
- break;
- case "forcemerging":
- if (ForceMerging == ForceMerging.None)
- {
- ForceMerging = Utilities.GetForceMerging(content);
- }
- break;
- case "forcenodump":
- if (ForceNodump == ForceNodump.None)
- {
- ForceNodump = Utilities.GetForceNodump(content);
- }
- break;
- case "forcepacking":
- if (ForcePacking == ForcePacking.None)
- {
- ForcePacking = Utilities.GetForcePacking(content);
- }
- break;
- }
- }
- flagreader.Read();
- break;
- default:
- flagreader.Read();
- break;
- }
- }
- headreader.Skip();
- break;
- default:
- headreader.Read();
- break;
- }
- }
+ ReadHeader(xtr.ReadSubtree(), keep);
// Skip the header node now that we've processed it
- xtr.Skip();
- break;
- case "machine":
- case "game":
- case "software":
- string temptype = xtr.Name, publisher = "", partname = "", partinterface = "", areaname = "";
- bool? supported = null;
- long? areasize = null;
- List> infos = new List>();
- List> features = new List>();
- bool containsItems = false;
-
- // We want to process the entire subtree of the game
- subreader = xtr.ReadSubtree();
-
- // Safeguard for interesting case of "software" without anything except roms
- bool software = false;
-
- // If we have an empty machine, skip it
- if (subreader == null)
- {
- xtr.Skip();
- continue;
- }
-
- // Otherwise, add what is possible
- subreader.MoveToContent();
-
- // Create a new machine
- MachineType machineType = MachineType.NULL;
- if (Utilities.GetYesNo(xtr.GetAttribute("isbios")) == true)
- {
- machineType |= MachineType.Bios;
- }
- if (Utilities.GetYesNo(xtr.GetAttribute("isdevice")) == true)
- {
- machineType |= MachineType.Device;
- }
- if (Utilities.GetYesNo(xtr.GetAttribute("ismechanical")) == true)
- {
- machineType |= MachineType.Mechanical;
- }
-
- Machine machine = new Machine
- {
- Name = xtr.GetAttribute("name"),
- Description = xtr.GetAttribute("name"),
-
- RomOf = xtr.GetAttribute("romof") ?? "",
- CloneOf = xtr.GetAttribute("cloneof") ?? "",
- SampleOf = xtr.GetAttribute("sampleof") ?? "",
-
- Devices = new List(),
- MachineType = (machineType == MachineType.NULL ? MachineType.None : machineType),
- };
-
- // Get the supported value from the reader
- if (subreader.GetAttribute("supported") != null)
- {
- supported = Utilities.GetYesNo(subreader.GetAttribute("supported"));
- }
-
- // Get the runnable value from the reader
- if (subreader.GetAttribute("runnable") != null)
- {
- machine.Runnable = Utilities.GetYesNo(subreader.GetAttribute("runnable"));
- }
-
- if (superdat && !keep)
- {
- string tempout = Regex.Match(machine.Name, @".*?\\(.*)").Groups[1].Value;
- if (!String.IsNullOrWhiteSpace(tempout))
- {
- machine.Name = tempout;
- }
- }
- // Get the name of the game from the parent
- else if (superdat && keep && parent.Count > 0)
- {
- machine.Name = String.Join("\\", parent) + "\\" + machine.Name;
- }
-
- // Special offline list parts
- string ext = "";
- string releaseNumber = "";
-
- while (software || !subreader.EOF)
- {
- software = false;
-
- // We only want elements
- if (subreader.NodeType != XmlNodeType.Element)
- {
- if (subreader.NodeType == XmlNodeType.EndElement && subreader.Name == "part")
- {
- partname = "";
- partinterface = "";
- features = new List>();
- }
- if (subreader.NodeType == XmlNodeType.EndElement && (subreader.Name == "dataarea" || subreader.Name == "diskarea"))
- {
- areaname = "";
- areasize = null;
- }
-
- subreader.Read();
- continue;
- }
-
- // Get the roms from the machine
- switch (subreader.Name)
- {
- // For OfflineList only
- case "title":
- machine.Name = subreader.ReadElementContentAsString();
- break;
- case "releaseNumber":
- releaseNumber = subreader.ReadElementContentAsString();
- break;
- case "romSize":
- if (!Int64.TryParse(subreader.ReadElementContentAsString(), out size))
- {
- size = -1;
- }
- break;
- case "romCRC":
- empty = false;
- containsItems = true;
-
- ext = (subreader.GetAttribute("extension") ?? "");
-
- DatItem olrom = new Rom
- {
- Name = releaseNumber + " - " + machine.Name + ext,
- Size = size,
- CRC = subreader.ReadElementContentAsString(),
- ItemStatus = ItemStatus.None,
- };
-
- olrom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(olrom, clean, remUnicode);
- break;
-
- // For Software List and MAME listxml only
- case "device_ref":
- string device = subreader.GetAttribute("name");
- if (!machine.Devices.Contains(device))
- {
- machine.Devices.Add(device);
- }
-
- subreader.Read();
- break;
- case "slotoption":
- string slotoption = subreader.GetAttribute("devname");
- if (!machine.Devices.Contains(slotoption))
- {
- machine.Devices.Add(slotoption);
- }
-
- subreader.Read();
- break;
- case "publisher":
- publisher = subreader.ReadElementContentAsString();
- break;
- case "info":
- infos.Add(Tuple.Create(subreader.GetAttribute("name"), subreader.GetAttribute("value")));
- subreader.Read();
- break;
- case "part":
- partname = subreader.GetAttribute("name");
- partinterface = subreader.GetAttribute("interface");
- subreader.Read();
- break;
- case "feature":
- features.Add(Tuple.Create(subreader.GetAttribute("name"), subreader.GetAttribute("value")));
- subreader.Read();
- break;
- case "dataarea":
- case "diskarea":
- areaname = subreader.GetAttribute("name");
- long areasizetemp = -1;
- if (Int64.TryParse(subreader.GetAttribute("size"), out areasizetemp))
- {
- areasize = areasizetemp;
- }
- subreader.Read();
- break;
-
- // For Logiqx, SabreDAT, and Software List
- case "description":
- machine.Description = subreader.ReadElementContentAsString();
- break;
- case "year":
- machine.Year = subreader.ReadElementContentAsString();
- break;
- case "manufacturer":
- machine.Manufacturer = subreader.ReadElementContentAsString();
- break;
- case "release":
- empty = false;
- containsItems = true;
-
- bool? defaultrel = null;
- if (subreader.GetAttribute("default") != null)
- {
- defaultrel = Utilities.GetYesNo(subreader.GetAttribute("default"));
- }
-
- DatItem relrom = new Release
- {
- Name = subreader.GetAttribute("name"),
- Region = subreader.GetAttribute("region"),
- Language = subreader.GetAttribute("language"),
- Date = date,
- Default = defaultrel,
-
- Supported = supported,
- Publisher = publisher,
- Infos = infos,
- PartName = partname,
- PartInterface = partinterface,
- Features = features,
- AreaName = areaname,
- AreaSize = areasize,
- };
-
- relrom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(relrom, clean, remUnicode);
-
- subreader.Read();
- break;
- case "biosset":
- empty = false;
- containsItems = true;
-
- bool? defaultbios = null;
- if (subreader.GetAttribute("default") != null)
- {
- defaultbios = Utilities.GetYesNo(subreader.GetAttribute("default"));
- }
-
- DatItem biosrom = new BiosSet
- {
- Name = subreader.GetAttribute("name"),
- Description = subreader.GetAttribute("description"),
- Default = defaultbios,
-
- Supported = supported,
- Publisher = publisher,
- Infos = infos,
- PartName = partname,
- PartInterface = partinterface,
- Features = features,
- AreaName = areaname,
- AreaSize = areasize,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- biosrom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(biosrom, clean, remUnicode);
-
- subreader.Read();
- break;
- case "archive":
- empty = false;
- containsItems = true;
-
- DatItem archiverom = new Archive
- {
- Name = subreader.GetAttribute("name"),
-
- Supported = supported,
- Publisher = publisher,
- Infos = infos,
- PartName = partname,
- PartInterface = partinterface,
- Features = features,
- AreaName = areaname,
- AreaSize = areasize,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- archiverom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(archiverom, clean, remUnicode);
-
- subreader.Read();
- break;
- case "sample":
- empty = false;
- containsItems = true;
-
- DatItem samplerom = new Sample
- {
- Name = subreader.GetAttribute("name"),
-
- Supported = supported,
- Publisher = publisher,
- Infos = infos,
- PartName = partname,
- PartInterface = partinterface,
- Features = features,
- AreaName = areaname,
- AreaSize = areasize,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- samplerom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(samplerom, clean, remUnicode);
-
- subreader.Read();
- break;
- case "rom":
- case "disk":
- empty = false;
- containsItems = true;
-
- // If the rom has a merge tag, add it
- string merge = subreader.GetAttribute("merge");
-
- // If the rom has a status, flag it
- its = Utilities.GetItemStatus(subreader.GetAttribute("status"));
- if (its == ItemStatus.None)
- {
- its = Utilities.GetItemStatus(subreader.GetAttribute("flags"));
- }
-
- // If the rom has a Date attached, read it in and then sanitize it
- date = "";
- if (subreader.GetAttribute("date") != null)
- {
- DateTime dateTime = DateTime.Now;
- if (DateTime.TryParse(subreader.GetAttribute("date"), out dateTime))
- {
- date = dateTime.ToString();
- }
- else
- {
- date = subreader.GetAttribute("date");
- }
- }
-
- // Take care of hex-sized files
- size = -1;
- if (subreader.GetAttribute("size") != null && subreader.GetAttribute("size").Contains("0x"))
- {
- size = Convert.ToInt64(subreader.GetAttribute("size"), 16);
- }
- else if (subreader.GetAttribute("size") != null)
- {
- Int64.TryParse(subreader.GetAttribute("size"), out size);
- }
-
- // If the rom is continue or ignore, add the size to the previous rom
- if (subreader.GetAttribute("loadflag") == "continue" || subreader.GetAttribute("loadflag") == "ignore")
- {
- int index = this[key].Count - 1;
- DatItem lastrom = this[key][index];
- if (lastrom.Type == ItemType.Rom)
- {
- ((Rom)lastrom).Size += size;
- }
- this[key].RemoveAt(index);
- this[key].Add(lastrom);
- subreader.Read();
- continue;
- }
-
- // If we're in clean mode, sanitize the game name
- if (clean)
- {
- machine.Name = Utilities.CleanGameName(machine.Name.Split(Path.DirectorySeparatorChar));
- }
-
- DatItem inrom;
- switch (subreader.Name.ToLowerInvariant())
- {
- case "disk":
- inrom = new Disk
- {
- Name = subreader.GetAttribute("name"),
- MD5 = subreader.GetAttribute("md5")?.ToLowerInvariant(),
- SHA1 = subreader.GetAttribute("sha1")?.ToLowerInvariant(),
- SHA256 = subreader.GetAttribute("sha256")?.ToLowerInvariant(),
- SHA384 = subreader.GetAttribute("sha384")?.ToLowerInvariant(),
- SHA512 = subreader.GetAttribute("sha512")?.ToLowerInvariant(),
- MergeTag = merge,
- ItemStatus = its,
-
- Supported = supported,
- Publisher = publisher,
- Infos = infos,
- PartName = partname,
- PartInterface = partinterface,
- Features = features,
- AreaName = areaname,
- AreaSize = areasize,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- break;
- case "rom":
- default:
- inrom = new Rom
- {
- Name = subreader.GetAttribute("name"),
- Size = size,
- CRC = subreader.GetAttribute("crc"),
- MD5 = subreader.GetAttribute("md5")?.ToLowerInvariant(),
- SHA1 = subreader.GetAttribute("sha1")?.ToLowerInvariant(),
- SHA256 = subreader.GetAttribute("sha256")?.ToLowerInvariant(),
- SHA384 = subreader.GetAttribute("sha384")?.ToLowerInvariant(),
- SHA512 = subreader.GetAttribute("sha512")?.ToLowerInvariant(),
- ItemStatus = its,
- MergeTag = merge,
- Date = date,
-
- Supported = supported,
- Publisher = publisher,
- Infos = infos,
- PartName = partname,
- PartInterface = partinterface,
- Features = features,
- AreaName = areaname,
- AreaSize = areasize,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- break;
- }
-
- inrom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(inrom, clean, remUnicode);
-
- subreader.Read();
- break;
- default:
- subreader.Read();
- break;
- }
- }
-
- // If no items were found for this machine, add a Blank placeholder
- if (!containsItems)
- {
- Blank blank = new Blank()
- {
- Supported = supported,
- Publisher = publisher,
- Infos = infos,
- PartName = partname,
- PartInterface = partinterface,
- Features = features,
- AreaName = areaname,
- AreaSize = areasize,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- blank.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(blank, clean, remUnicode);
- }
-
xtr.Skip();
break;
case "dir":
case "directory":
- // Set SuperDAT flag for all SabreDAT inputs, regardless of depth
- superdat = true;
- if (keep)
- {
- Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
- }
-
- string foldername = (xtr.GetAttribute("name") ?? "");
- if (!String.IsNullOrWhiteSpace(foldername))
- {
- parent.Add(foldername);
- }
-
- xtr.Read();
- break;
- case "file":
- empty = false;
- containsItems = true;
-
- // If the rom is itemStatus, flag it
- its = ItemStatus.None;
- flagreader = xtr.ReadSubtree();
-
- // If the subtree is empty, skip it
- if (flagreader == null)
- {
- xtr.Skip();
- continue;
- }
-
- while (!flagreader.EOF)
- {
- // We only want elements
- if (flagreader.NodeType != XmlNodeType.Element || flagreader.Name == "flags")
- {
- flagreader.Read();
- continue;
- }
-
- switch (flagreader.Name)
- {
- case "flag":
- case "status":
- if (flagreader.GetAttribute("name") != null && flagreader.GetAttribute("value") != null)
- {
- string content = flagreader.GetAttribute("value");
- its = Utilities.GetItemStatus(flagreader.GetAttribute("name"));
- }
- break;
- }
-
- flagreader.Read();
- }
-
- // If the rom has a Date attached, read it in and then sanitize it
- date = "";
- if (xtr.GetAttribute("date") != null)
- {
- date = DateTime.Parse(xtr.GetAttribute("date")).ToString();
- }
-
- // Take care of hex-sized files
- size = -1;
- if (xtr.GetAttribute("size") != null && xtr.GetAttribute("size").Contains("0x"))
- {
- size = Convert.ToInt64(xtr.GetAttribute("size"), 16);
- }
- else if (xtr.GetAttribute("size") != null)
- {
- Int64.TryParse(xtr.GetAttribute("size"), out size);
- }
-
- // If the rom is continue or ignore, add the size to the previous rom
- if (xtr.GetAttribute("loadflag") == "continue" || xtr.GetAttribute("loadflag") == "ignore")
- {
- int index = this[key].Count - 1;
- DatItem lastrom = this[key][index];
- if (lastrom.Type == ItemType.Rom)
- {
- ((Rom)lastrom).Size += size;
- }
- this[key].RemoveAt(index);
- this[key].Add(lastrom);
- continue;
- }
-
- Machine dir = new Machine();
-
- // Get the name of the game from the parent
- dir.Name = String.Join("\\", parent);
- dir.Description = dir.Name;
-
- // If we aren't keeping names, trim out the path
- if (!keep || !superdat)
- {
- string tempout = Regex.Match(dir.Name, @".*?\\(.*)").Groups[1].Value;
- if (!String.IsNullOrWhiteSpace(tempout))
- {
- dir.Name = tempout;
- }
- }
-
- DatItem rom;
- switch (xtr.GetAttribute("type").ToLowerInvariant())
- {
- case "disk":
- rom = new Disk
- {
- Name = xtr.GetAttribute("name"),
- MD5 = xtr.GetAttribute("md5")?.ToLowerInvariant(),
- SHA1 = xtr.GetAttribute("sha1")?.ToLowerInvariant(),
- SHA256 = xtr.GetAttribute("sha256")?.ToLowerInvariant(),
- SHA384 = xtr.GetAttribute("sha384")?.ToLowerInvariant(),
- SHA512 = xtr.GetAttribute("sha512")?.ToLowerInvariant(),
- ItemStatus = its,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- break;
- case "rom":
- default:
- rom = new Rom
- {
- Name = xtr.GetAttribute("name"),
- Size = size,
- CRC = xtr.GetAttribute("crc")?.ToLowerInvariant(),
- MD5 = xtr.GetAttribute("md5")?.ToLowerInvariant(),
- SHA1 = xtr.GetAttribute("sha1")?.ToLowerInvariant(),
- SHA256 = xtr.GetAttribute("sha256")?.ToLowerInvariant(),
- SHA384 = xtr.GetAttribute("sha384")?.ToLowerInvariant(),
- SHA512 = xtr.GetAttribute("sha512")?.ToLowerInvariant(),
- ItemStatus = its,
- Date = date,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- break;
- }
-
- rom.CopyMachineInformation(dir);
-
- // Now process and add the rom
- key = ParseAddHelper(rom, clean, remUnicode);
+ empty = ReadDirectory(xtr.ReadSubtree(), parent, filename, sysid, srcid, keep, clean, remUnicode);
+ // Skip the directory node now that we've processed it
xtr.Read();
break;
default:
@@ -1057,6 +153,402 @@ namespace SabreTools.Library.DatFiles
xtr.Dispose();
}
+ ///
+ /// Read header information
+ ///
+ /// XmlReader to use to parse the header
+ /// True if full pathnames are to be kept, false otherwise (default)
+ private void ReadHeader(XmlReader reader, bool keep)
+ {
+ bool superdat = false;
+
+ // If there's no subtree to the header, skip it
+ if (reader == null)
+ {
+ return;
+ }
+
+ // Otherwise, read what we can from the header
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element || reader.Name == "header")
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
+ string content = "";
+ switch (reader.Name)
+ {
+ case "name":
+ content = reader.ReadElementContentAsString(); ;
+ Name = (String.IsNullOrWhiteSpace(Name) ? content : Name);
+ superdat = superdat || content.Contains(" - SuperDAT");
+ if (keep && superdat)
+ {
+ Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
+ }
+ break;
+ case "description":
+ content = reader.ReadElementContentAsString();
+ Description = (String.IsNullOrWhiteSpace(Description) ? content : Description);
+ break;
+ case "rootdir":
+ content = reader.ReadElementContentAsString();
+ RootDir = (String.IsNullOrWhiteSpace(RootDir) ? content : RootDir);
+ break;
+ case "category":
+ content = reader.ReadElementContentAsString();
+ Category = (String.IsNullOrWhiteSpace(Category) ? content : Category);
+ break;
+ case "version":
+ content = reader.ReadElementContentAsString();
+ Version = (String.IsNullOrWhiteSpace(Version) ? content : Version);
+ break;
+ case "date":
+ content = reader.ReadElementContentAsString();
+ Date = (String.IsNullOrWhiteSpace(Date) ? content.Replace(".", "/") : Date);
+ break;
+ case "author":
+ content = reader.ReadElementContentAsString();
+ Author = (String.IsNullOrWhiteSpace(Author) ? content : Author);
+ Email = (String.IsNullOrWhiteSpace(Email) ? reader.GetAttribute("email") : Email);
+ Homepage = (String.IsNullOrWhiteSpace(Homepage) ? reader.GetAttribute("homepage") : Homepage);
+ Url = (String.IsNullOrWhiteSpace(Url) ? reader.GetAttribute("url") : Url);
+ break;
+ case "comment":
+ content = reader.ReadElementContentAsString();
+ Comment = (String.IsNullOrWhiteSpace(Comment) ? content : Comment);
+ break;
+ case "flags":
+ ReadFlags(reader.ReadSubtree(), superdat);
+
+ // Skip the flags node now that we've processed it
+ reader.Skip();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Read directory information
+ ///
+ /// XmlReader to use to parse the header
+ /// Name of the file to be parsed
+ /// System ID for the DAT
+ /// Source ID for the DAT
+ /// True if full pathnames are to be kept, false otherwise (default)
+ /// True if game names are sanitized, false otherwise (default)
+ /// True if we should remove non-ASCII characters from output, false otherwise (default)
+ private bool ReadDirectory(XmlReader reader,
+ List parent,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Prepare all internal variables
+ XmlReader flagreader;
+ bool empty = true;
+ string key = "", date = "";
+ long size = -1;
+ ItemStatus its = ItemStatus.None;
+
+ // If there's no subtree to the header, skip it
+ if (reader == null)
+ {
+ return empty;
+ }
+
+ string foldername = (reader.GetAttribute("name") ?? "");
+ if (!String.IsNullOrWhiteSpace(foldername))
+ {
+ parent.Add(foldername);
+ }
+
+ // Otherwise, read what we can from the directory
+ while (!reader.EOF)
+ {
+ // If we're ending a folder or game, take care of possibly empty games and removing from the parent
+ if (reader.NodeType == XmlNodeType.EndElement && (reader.Name == "directory" || reader.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, omitFromScan: Hash.DeepHashes); // TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually
+
+ // Now process and add the rom
+ key = ParseAddHelper(rom, clean, remUnicode);
+ }
+
+ // Regardless, end the current folder
+ int parentcount = parent.Count;
+ if (parentcount == 0)
+ {
+ Globals.Logger.Verbose("Empty parent '{0}' found in '{1}'", String.Join("\\", parent), filename);
+ 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.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
+ }
+ }
+ }
+
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get all directory items
+ string content = "";
+ switch (reader.Name)
+ {
+ // Directories can contain directories
+ case "dir":
+ case "directory":
+ ReadDirectory(reader.ReadSubtree(), parent, filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the directory node now that we've processed it
+ reader.Read();
+ break;
+ case "file":
+ empty = false;
+
+ // If the rom is itemStatus, flag it
+ its = ItemStatus.None;
+ flagreader = reader.ReadSubtree();
+
+ // If the subtree is empty, skip it
+ if (flagreader == null)
+ {
+ reader.Skip();
+ continue;
+ }
+
+ while (!flagreader.EOF)
+ {
+ // We only want elements
+ if (flagreader.NodeType != XmlNodeType.Element || flagreader.Name == "flags")
+ {
+ flagreader.Read();
+ continue;
+ }
+
+ switch (flagreader.Name)
+ {
+ case "flag":
+ if (flagreader.GetAttribute("name") != null && flagreader.GetAttribute("value") != null)
+ {
+ content = flagreader.GetAttribute("value");
+ its = Utilities.GetItemStatus(flagreader.GetAttribute("name"));
+ }
+ break;
+ }
+
+ flagreader.Read();
+ }
+
+ // If the rom has a Date attached, read it in and then sanitize it
+ date = Utilities.GetDate(reader.GetAttribute("date"));
+
+ // Take care of hex-sized files
+ size = Utilities.GetSize(reader.GetAttribute("size"));
+
+ Machine dir = new Machine();
+
+ // Get the name of the game from the parent
+ dir.Name = String.Join("\\", parent);
+ dir.Description = dir.Name;
+
+ DatItem datItem;
+ switch (reader.GetAttribute("type").ToLowerInvariant())
+ {
+ case "archive":
+ datItem = new Archive
+ {
+ Name = reader.GetAttribute("name"),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ break;
+ case "biosset":
+ datItem = new BiosSet
+ {
+ Name = reader.GetAttribute("name"),
+ Description = reader.GetAttribute("description"),
+ Default = Utilities.GetYesNo(reader.GetAttribute("default")),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ break;
+ case "disk":
+ datItem = new Disk
+ {
+ Name = reader.GetAttribute("name"),
+ MD5 = reader.GetAttribute("md5")?.ToLowerInvariant(),
+ SHA1 = reader.GetAttribute("sha1")?.ToLowerInvariant(),
+ SHA256 = reader.GetAttribute("sha256")?.ToLowerInvariant(),
+ SHA384 = reader.GetAttribute("sha384")?.ToLowerInvariant(),
+ SHA512 = reader.GetAttribute("sha512")?.ToLowerInvariant(),
+ ItemStatus = its,
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ break;
+ case "release":
+ datItem = new Release
+ {
+ Name = reader.GetAttribute("name"),
+ Region = reader.GetAttribute("region"),
+ Language = reader.GetAttribute("language"),
+ Date = reader.GetAttribute("date"),
+ Default = Utilities.GetYesNo(reader.GetAttribute("default")),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ break;
+ case "rom":
+ datItem = new Rom
+ {
+ Name = reader.GetAttribute("name"),
+ Size = size,
+ CRC = reader.GetAttribute("crc")?.ToLowerInvariant(),
+ MD5 = reader.GetAttribute("md5")?.ToLowerInvariant(),
+ SHA1 = reader.GetAttribute("sha1")?.ToLowerInvariant(),
+ SHA256 = reader.GetAttribute("sha256")?.ToLowerInvariant(),
+ SHA384 = reader.GetAttribute("sha384")?.ToLowerInvariant(),
+ SHA512 = reader.GetAttribute("sha512")?.ToLowerInvariant(),
+ ItemStatus = its,
+ Date = date,
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ break;
+ case "sample":
+ datItem = new Sample
+ {
+ Name = reader.GetAttribute("name"),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ break;
+ default:
+ // By default, create a new Blank, just in case
+ datItem = new Blank();
+ break;
+ }
+
+ datItem.CopyMachineInformation(dir);
+
+ // Now process and add the rom
+ key = ParseAddHelper(datItem, clean, remUnicode);
+
+ reader.Read();
+ break;
+ }
+ }
+
+ return empty;
+ }
+
+ ///
+ /// Read flags information
+ ///
+ /// XmlReader to use to parse the header
+ /// True if superdat has already been set externally, false otherwise
+ private void ReadFlags(XmlReader reader, bool superdat)
+ {
+ // Prepare all internal variables
+ string content = "";
+
+ // If we somehow have a null flag section, skip it
+ if (reader == null)
+ {
+ return;
+ }
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element || reader.Name == "flags")
+ {
+ reader.Read();
+ continue;
+ }
+
+ switch (reader.Name)
+ {
+ case "flag":
+ if (reader.GetAttribute("name") != null && reader.GetAttribute("value") != null)
+ {
+ content = reader.GetAttribute("value");
+ switch (reader.GetAttribute("name").ToLowerInvariant())
+ {
+ case "type":
+ Type = (String.IsNullOrWhiteSpace(Type) ? content : Type);
+ superdat = superdat || content.Contains("SuperDAT");
+ break;
+ case "forcemerging":
+ if (ForceMerging == ForceMerging.None)
+ {
+ ForceMerging = Utilities.GetForceMerging(content);
+ }
+ break;
+ case "forcenodump":
+ if (ForceNodump == ForceNodump.None)
+ {
+ ForceNodump = Utilities.GetForceNodump(content);
+ }
+ break;
+ case "forcepacking":
+ if (ForcePacking == ForcePacking.None)
+ {
+ ForcePacking = Utilities.GetForcePacking(content);
+ }
+ break;
+ }
+ }
+ reader.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
///
/// Create and open an output file for writing direct from a dictionary
///