From 94cff12d2886b0b51398e57a093d6056876cd4bd Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 15 Jan 2018 12:53:32 -0800 Subject: [PATCH] [Utilities] Fix OfflineList parsing (keep unhooked) --- SabreTools.Library/DatFiles/OfflineList.cs | 1354 ++++++-------------- SabreTools.Library/Tools/Utilities.cs | 6 +- 2 files changed, 411 insertions(+), 949 deletions(-) diff --git a/SabreTools.Library/DatFiles/OfflineList.cs b/SabreTools.Library/DatFiles/OfflineList.cs index 13829274..e8719954 100644 --- a/SabreTools.Library/DatFiles/OfflineList.cs +++ b/SabreTools.Library/DatFiles/OfflineList.cs @@ -63,14 +63,6 @@ namespace SabreTools.Library.DatFiles new Logiqx(this, false).ParseFile(filename, sysid, srcid, keep, clean, remUnicode); return; - // Prepare all internal variables - XmlReader subreader, headreader, flagreader; - bool superdat = false, empty = true; - string key = "", date = ""; - long size = -1; - ItemStatus its = ItemStatus.None; - List parent = new List(); - Encoding enc = Utilities.GetEncoding(filename); XmlReader xtr = Utilities.GetXmlTextReader(filename); @@ -86,39 +78,6 @@ namespace SabreTools.Library.DatFiles xtr.MoveToContent(); while (!xtr.EOF) { - // If we're ending a folder or game, take care of possibly empty games and removing from the parent - if (xtr.NodeType == XmlNodeType.EndElement && (xtr.Name == "directory" || xtr.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); - superdat = true; - } - } - } - // We only want elements if (xtr.NodeType != XmlNodeType.Element) { @@ -128,918 +87,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(); + ReadConfiguration(xtr.ReadSubtree(), keep); - // 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; - } - } - - // Skip the header node now that we've processed it + // Skip the configuration 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); - } + case "games": + ReadGames(xtr.ReadSubtree(), keep, clean, remUnicode); + // Skip the games node now that we've processed it 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); - - xtr.Read(); - break; default: xtr.Read(); break; @@ -1057,6 +116,409 @@ namespace SabreTools.Library.DatFiles xtr.Dispose(); } + /// + /// Read configuration information + /// + /// XmlReader to use to parse the header + /// True if full pathnames are to be kept, false otherwise (default) + private void ReadConfiguration(XmlReader reader, bool keep) + { + bool superdat = false; + + // If there's no subtree to the configuration, skip it + if (reader == null) + { + return; + } + + // Otherwise, add what is possible + reader.MoveToContent(); + + // Otherwise, read what we can from the header + while (!reader.EOF) + { + // We only want elements + if (reader.NodeType != XmlNodeType.Element) + { + reader.Read(); + continue; + } + + // Get all configuration items (ONLY OVERWRITE IF THERE'S NO DATA) + string content = ""; + switch (reader.Name.ToLowerInvariant()) + { + case "datname": + 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 "datversion": + content = reader.ReadElementContentAsString(); + Version = (String.IsNullOrWhiteSpace(Version) ? content : Version); + break; + case "system": + content = reader.ReadElementContentAsString(); + // string system = content; + break; + case "screenshotswidth": + content = reader.ReadElementContentAsString(); + // string screenshotsWidth = content; // Int32? + break; + case "screenshotsheight": + content = reader.ReadElementContentAsString(); + // string screenshotsHeight = content; // Int32? + break; + case "infos": + // // TODO: Technically, this needs to be in its own subreader + // string title_visible = reader.GetAttribute("visible"); // (true|false) + // string title_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string title_default = reader.GetAttribute("default"); // (true|false) + // string location_visible = reader.GetAttribute("visible"); // (true|false) + // string location_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string location_default = reader.GetAttribute("default"); // (true|false) + // string publisher_visible = reader.GetAttribute("visible"); // (true|false) + // string publisher_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string publisher_default = reader.GetAttribute("default"); // (true|false) + // string sourceRom_visible = reader.GetAttribute("visible"); // (true|false) + // string sourceRom_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string sourceRom_default = reader.GetAttribute("default"); // (true|false) + // string saveType_visible = reader.GetAttribute("visible"); // (true|false) + // string saveType_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string saveType_default = reader.GetAttribute("default"); // (true|false) + // string romSize_visible = reader.GetAttribute("visible"); // (true|false) + // string romSize_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string romSize_default = reader.GetAttribute("default"); // (true|false) + // string releaseNumber_visible = reader.GetAttribute("visible"); // (true|false) + // string releaseNumber_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string releaseNumber_default = reader.GetAttribute("default"); // (true|false) + // string languageNumber_visible = reader.GetAttribute("visible"); // (true|false) + // string languageNumber_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string languageNumber_default = reader.GetAttribute("default"); // (true|false) + // string comment_visible = reader.GetAttribute("visible"); // (true|false) + // string comment_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string comment_default = reader.GetAttribute("default"); // (true|false) + // string romCRC_visible = reader.GetAttribute("visible"); // (true|false) + // string romCRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string romCRC_default = reader.GetAttribute("default"); // (true|false) + // string im1CRC_visible = reader.GetAttribute("visible"); // (true|false) + // string im1CRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string im1CRC_default = reader.GetAttribute("default"); // (true|false) + // string im2CRC_visible = reader.GetAttribute("visible"); // (true|false) + // string im2CRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string im2CRC_default = reader.GetAttribute("default"); // (true|false) + // string languages_visible = reader.GetAttribute("visible"); // (true|false) + // string languages_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false) + // string languages_default = reader.GetAttribute("default"); // (true|false) + + reader.Skip(); + break; + case "canopen": + // // TODO: Technically, this needs to be in its own subreader + // List extensions = new List extensions; + // // For each extension element... + // extensions.Add(reader.ReadElementContentAsString()); + + reader.Skip(); + break; + case "newdat": + // // TODO: Technically, this needs to be in its own subreader + // // For the datVersionURL element... + // content = reader.ReadElementContentAsString(); + // Url = (String.IsNullOrWhiteSpace(Name) ? content : Url); + + // // For the datURL element... + // string fileName = reader.GetAttribute("fileName"); + // content = reader.ReadElementContentAsString(); + // string url = content; + + // // For the imURL element... + // content = reader.ReadElementContentAsString(); + // string url = content; + + reader.Skip(); + break; + case "search": + // // TODO: Technically, this needs to be in its own subreader + // // For each to element... + // string value = reader.GetAttribute("value"); + // string default = reader.GetAttribute("default"); (true|false) + // string auto = reader.GetAttribute("auto"); (true|false) + + // // Additionally, each to element can contain find elements... + // string operation = reader.GetAttribute("operation"); + // string value = reader.GetAttribute("value"); // Int32? + // content = reader.ReadElementContentAsString(); + // string findValue = content; + + reader.Skip(); + break; + case "romtitle": + content = reader.ReadElementContentAsString(); + // string romtitle = content; + + break; + default: + reader.Read(); + break; + } + } + } + + /// + /// Read games information + /// + /// XmlReader to use to parse the header + /// 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 void ReadGames(XmlReader reader, + + // Miscellaneous + bool keep, + bool clean, + bool remUnicode) + { + // If there's no subtree to the configuration, skip it + if (reader == null) + { + return; + } + + // Otherwise, add what is possible + reader.MoveToContent(); + + // Otherwise, read what we can from the header + while (!reader.EOF) + { + // We only want elements + if (reader.NodeType != XmlNodeType.Element) + { + reader.Read(); + continue; + } + + // Get all games items (ONLY OVERWRITE IF THERE'S NO DATA) + switch (reader.Name.ToLowerInvariant()) + { + case "game": + ReadGame(reader.ReadSubtree(), keep, clean, remUnicode); + + // Skip the game node now that we've processed it + reader.Skip(); + break; + default: + reader.Read(); + break; + } + } + } + + /// + /// Read game information + /// + /// XmlReader to use to parse the header + /// 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 void ReadGame(XmlReader reader, + + // Miscellaneous + bool keep, + bool clean, + bool remUnicode) + { + // Prepare all internal variables + string releaseNumber = "", key = "", publisher = ""; + long size = -1; + List roms = new List(); + Machine machine = new Machine(); + + // If there's no subtree to the configuration, skip it + if (reader == null) + { + return; + } + + // Otherwise, add what is possible + reader.MoveToContent(); + + // Otherwise, read what we can from the header + while (!reader.EOF) + { + // We only want elements + if (reader.NodeType != XmlNodeType.Element) + { + reader.Read(); + continue; + } + + // Get all games items + string content = ""; + switch (reader.Name.ToLowerInvariant()) + { + case "imagenumber": + content = reader.ReadElementContentAsString(); + // string imageNumber = content; + + break; + case "releasenumber": + releaseNumber = reader.ReadElementContentAsString(); + + break; + case "title": + content = reader.ReadElementContentAsString(); + machine.Name = content; + + break; + case "savetype": + content = reader.ReadElementContentAsString(); + // string saveType = content; + + break; + case "romsize": + if (!Int64.TryParse(reader.ReadElementContentAsString(), out size)) + { + size = -1; + } + + break; + case "publisher": + publisher = reader.ReadElementContentAsString(); + + break; + case "location": + content = reader.ReadElementContentAsString(); + // string location = content; + + break; + case "sourcerom": + content = reader.ReadElementContentAsString(); + // string sourceRom = content; + + break; + case "language": + content = reader.ReadElementContentAsString(); + // string language = content; + + break; + case "files": + roms = ReadFiles(reader.ReadSubtree(), releaseNumber, machine.Name, keep, clean, remUnicode); + + // Skip the files node now that we've processed it + reader.Skip(); + break; + case "im1crc": + content = reader.ReadElementContentAsString(); + // string im1crc = content; + + break; + case "im2crc": + content = reader.ReadElementContentAsString(); + // string im2crc = content; + + break; + case "comment": + machine.Comment = reader.ReadElementContentAsString(); + + break; + case "duplicateid": + machine.CloneOf = reader.ReadElementContentAsString(); + + break; + default: + reader.Read(); + break; + } + } + + // Add information accordingly for each rom + for (int i = 0; i < roms.Count; i++) + { + roms[i].Size = size; + roms[i].Publisher = publisher; + roms[i].CopyMachineInformation(machine); + + // Now process and add the rom + key = ParseAddHelper(roms[i], clean, remUnicode); + } + } + + /// + /// Read files information + /// + /// XmlReader to use to parse the header + /// Release number from the parent game + /// Name of the parent game to use + /// 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 List ReadFiles(XmlReader reader, + string releaseNumber, + string machineName, + + // Miscellaneous + bool keep, + bool clean, + bool remUnicode) + { + // Prepare all internal variables + List> extensionToCrc = new List>(); + List roms = new List(); + + // If there's no subtree to the configuration, skip it + if (reader == null) + { + return roms; + } + + // Otherwise, add what is possible + reader.MoveToContent(); + + // Otherwise, read what we can from the header + while (!reader.EOF) + { + // We only want elements + if (reader.NodeType != XmlNodeType.Element) + { + reader.Read(); + continue; + } + + // Get all romCRC items + switch (reader.Name.ToLowerInvariant()) + { + case "romcrc": + extensionToCrc.Add( + new Tuple( + reader.GetAttribute("extension") ?? "", + reader.ReadElementContentAsString().ToLowerInvariant())); + break; + default: + reader.Read(); + break; + } + } + + // Now process the roms with the proper information + foreach (Tuple pair in extensionToCrc) + { + roms.Add(new Rom() + { + Name = (releaseNumber != "0" ? releaseNumber + " - " : "") + machineName + pair.Item1, + CRC = pair.Item2, + + ItemStatus = ItemStatus.None, + }); + } + + return roms; + } + /// /// Create and open an output file for writing direct from a dictionary /// diff --git a/SabreTools.Library/Tools/Utilities.cs b/SabreTools.Library/Tools/Utilities.cs index 41fdf23b..416ce255 100644 --- a/SabreTools.Library/Tools/Utilities.cs +++ b/SabreTools.Library/Tools/Utilities.cs @@ -1095,15 +1095,15 @@ namespace SabreTools.Library.Tools // For everything else, we need to read it try { - // Get the first two lines to check + // Get the first two non-whitespace, non-comment lines to check StreamReader sr = File.OpenText(filename); string first = sr.ReadLine().ToLowerInvariant(); - while (String.IsNullOrWhiteSpace(first)) + while (String.IsNullOrWhiteSpace(first) || first.StartsWith("