diff --git a/SabreTools.Library/DatFiles/AttractMode.cs b/SabreTools.Library/DatFiles/AttractMode.cs
index 31f76f0b..1b554b25 100644
--- a/SabreTools.Library/DatFiles/AttractMode.cs
+++ b/SabreTools.Library/DatFiles/AttractMode.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -19,248 +18,248 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of an AttractMode DAT
- ///
- internal class AttractMode : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public AttractMode(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
+ ///
+ /// Represents parsing and writing of an AttractMode DAT
+ ///
+ internal class AttractMode : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public AttractMode(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
- ///
- /// Parse an AttractMode DAT and return all found games within
- ///
- /// 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)
- public override void ParseFile(
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
+ ///
+ /// Parse an AttractMode DAT and return all found games within
+ ///
+ /// 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)
+ public override void ParseFile(
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Open a file reader
- Encoding enc = Utilities.GetEncoding(filename);
- StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Open a file reader
+ Encoding enc = Utilities.GetEncoding(filename);
+ StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
- sr.ReadLine(); // Skip the first line since it's the header
- while (!sr.EndOfStream)
- {
- string line = sr.ReadLine();
+ sr.ReadLine(); // Skip the first line since it's the header
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine();
- /*
- The gameinfo order is as follows
- 0 - game name
- 1 - game description
- 2 - emulator name (filename)
- 3 - cloneof
- 4 - year
- 5 - manufacturer
- 6 - category
- 7 - players
- 8 - rotation
- 9 - control
- 10 - status
- 11 - displaycount
- 12 - displaytype
- 13 - alt romname
- 14 - alt title
- 15 - extra
- 16 - buttons
- */
+ /*
+ The gameinfo order is as follows
+ 0 - game name
+ 1 - game description
+ 2 - emulator name (filename)
+ 3 - cloneof
+ 4 - year
+ 5 - manufacturer
+ 6 - category
+ 7 - players
+ 8 - rotation
+ 9 - control
+ 10 - status
+ 11 - displaycount
+ 12 - displaytype
+ 13 - alt romname
+ 14 - alt title
+ 15 - extra
+ 16 - buttons
+ */
- string[] gameinfo = line.Split(';');
+ string[] gameinfo = line.Split(';');
- Rom rom = new Rom
- {
- Name = "-",
- Size = Constants.SizeZero,
- CRC = Constants.CRCZero,
- MD5 = Constants.MD5Zero,
- SHA1 = Constants.SHA1Zero,
- ItemStatus = ItemStatus.None,
+ Rom rom = new Rom
+ {
+ Name = "-",
+ Size = Constants.SizeZero,
+ CRC = Constants.CRCZero,
+ MD5 = Constants.MD5Zero,
+ SHA1 = Constants.SHA1Zero,
+ ItemStatus = ItemStatus.None,
- MachineName = gameinfo[0],
- MachineDescription = gameinfo[1],
- CloneOf = gameinfo[3],
- Year = gameinfo[4],
- Manufacturer = gameinfo[5],
- Comment = gameinfo[15],
- };
+ MachineName = gameinfo[0],
+ MachineDescription = gameinfo[1],
+ CloneOf = gameinfo[3],
+ Year = gameinfo[4],
+ Manufacturer = gameinfo[5],
+ Comment = gameinfo[15],
+ };
- // Now process and add the rom
- ParseAddHelper(rom, clean, remUnicode);
- }
+ // Now process and add the rom
+ ParseAddHelper(rom, clean, remUnicode);
+ }
- sr.Dispose();
- }
+ sr.Dispose();
+ }
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if the DAT was written correctly, false otherwise
- public bool WriteToFile(string outfile)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if the DAT was written correctly, false otherwise
+ public bool WriteToFile(string outfile)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
- // Write out the header
- WriteHeader(sw);
+ // Write out the header
+ WriteHeader(sw);
- // Write out each of the machines and roms
- string lastgame = null;
+ // Write out each of the machines and roms
+ string lastgame = null;
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
- foreach (string key in keys)
- {
- List roms = this[key];
+ foreach (string key in keys)
+ {
+ List roms = this[key];
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem item = roms[index];
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem item = roms[index];
- // There are apparently times when a null rom can skip by, skip them
- if (item.Name == null || item.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
+ // There are apparently times when a null rom can skip by, skip them
+ if (item.Name == null || item.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != item.MachineName.ToLowerInvariant())
- {
- WriteStartGame(sw, item);
- }
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != item.MachineName.ToLowerInvariant())
+ {
+ WriteStartGame(sw, item);
+ }
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (item.ItemType == ItemType.Rom
- && ((Rom)item).Size == -1
- && ((Rom)item).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", item.MachineName);
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (item.ItemType == ItemType.Rom
+ && ((Rom)item).Size == -1
+ && ((Rom)item).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", item.MachineName);
- item.Name = (item.Name == "null" ? "-" : item.Name);
- ((Rom)item).Size = Constants.SizeZero;
- }
+ item.Name = (item.Name == "null" ? "-" : item.Name);
+ ((Rom)item).Size = Constants.SizeZero;
+ }
- // Set the new data to compare against
- lastgame = item.MachineName;
- }
- }
+ // Set the new data to compare against
+ lastgame = item.MachineName;
+ }
+ }
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "#Title;Name;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons\n";
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "#Title;Name;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons\n";
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteStartGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteStartGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
- string state = (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName : "") + ";"
- + (!ExcludeFields[(int)Field.Description] ? rom.MachineDescription : "") + ";"
- + FileName + ";"
- + (!ExcludeFields[(int)Field.CloneOf] ? rom.CloneOf : "") + ";"
- + (!ExcludeFields[(int)Field.Year] ? rom.Year : "") + ";"
- + (!ExcludeFields[(int)Field.Manufacturer] ? rom.Manufacturer : "") + ";"
- /* + rom.Category */ + ";"
- /* + rom.Players */ + ";"
- /* + rom.Rotation */ + ";"
- /* + rom.Control */ + ";"
- /* + rom.Status */ + ";"
- /* + rom.DisplayCount */ + ";"
- /* + rom.DisplayType */ + ";"
- /* + rom.AltRomname */ + ";"
- /* + rom.AltTitle */ + ";"
- + (!ExcludeFields[(int)Field.Comment] ? rom.Comment : "") + ";"
- /* + rom.Buttons */ + "\n";
+ string state = (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName : "") + ";"
+ + (!ExcludeFields[(int)Field.Description] ? rom.MachineDescription : "") + ";"
+ + FileName + ";"
+ + (!ExcludeFields[(int)Field.CloneOf] ? rom.CloneOf : "") + ";"
+ + (!ExcludeFields[(int)Field.Year] ? rom.Year : "") + ";"
+ + (!ExcludeFields[(int)Field.Manufacturer] ? rom.Manufacturer : "") + ";"
+ /* + rom.Category */ + ";"
+ /* + rom.Players */ + ";"
+ /* + rom.Rotation */ + ";"
+ /* + rom.Control */ + ";"
+ /* + rom.Status */ + ";"
+ /* + rom.DisplayCount */ + ";"
+ /* + rom.DisplayType */ + ";"
+ /* + rom.AltRomname */ + ";"
+ /* + rom.AltTitle */ + ";"
+ + (!ExcludeFields[(int)Field.Comment] ? rom.Comment : "") + ";"
+ /* + rom.Buttons */ + "\n";
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
- }
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/ClrMamePro.cs b/SabreTools.Library/DatFiles/ClrMamePro.cs
index 5dd0c8c2..de359106 100644
--- a/SabreTools.Library/DatFiles/ClrMamePro.cs
+++ b/SabreTools.Library/DatFiles/ClrMamePro.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -20,968 +19,968 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a ClrMamePro DAT
- ///
- /// TODO: Verify that all write for this DatFile type is correct
- internal class ClrMamePro : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public ClrMamePro(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
-
- ///
- /// Parse a ClrMamePro DAT 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
- /// 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,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Open a file reader
- Encoding enc = Utilities.GetEncoding(filename);
- StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
-
- while (!sr.EndOfStream)
- {
- string line = sr.ReadLine();
-
- // Comments in CMP DATs start with a #
- if (line.Trim().StartsWith("#"))
- {
- continue;
- }
-
- // If the line is the header or a game
- if (Regex.IsMatch(line, Constants.HeaderPatternCMP))
- {
- GroupCollection gc = Regex.Match(line, Constants.HeaderPatternCMP).Groups;
- string normalizedValue = gc[1].Value.ToLowerInvariant();
-
- // If we have a known header
- if (normalizedValue == "clrmamepro"
- || normalizedValue == "romvault"
- || normalizedValue == "doscenter")
- {
- ReadHeader(sr, keep);
- }
- // If we have a known set type
- else if (normalizedValue == "set" // Used by the most ancient DATs
- || normalizedValue == "game" // Used by most CMP DATs
- || normalizedValue == "machine") // Possibly used by MAME CMP DATs
- {
- ReadSet(sr, false, filename, sysid, srcid, keep, clean, remUnicode);
- }
- else if (normalizedValue == "resource") // Used by some other DATs to denote a BIOS set
- {
- ReadSet(sr, true, filename, sysid, srcid, keep, clean, remUnicode);
- }
- }
- }
-
- sr.Dispose();
- }
-
- ///
- /// Read header information
- ///
- /// StreamReader to use to parse the header
- /// True if full pathnames are to be kept, false otherwise (default)
- private void ReadHeader(StreamReader reader, bool keep)
- {
- bool superdat = false;
-
- // If there's no subtree to the header, skip it
- if (reader == null || reader.EndOfStream)
- {
- return;
- }
-
- // Otherwise, add what is possible
- string line = reader.ReadLine();
- while (!Regex.IsMatch(line, Constants.EndPatternCMP))
- {
- // We only want elements
- if (line.Trim().StartsWith("#"))
- {
- line = reader.ReadLine();
- continue;
- }
-
- // Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
- GroupCollection gc = Regex.Match(line, Constants.ItemPatternCMP).Groups;
- string itemval = gc[2].Value.Replace("\"", "");
-
- if (line.Trim().StartsWith("Name:"))
- {
- Name = (String.IsNullOrWhiteSpace(Name) ? line.Substring(6) : Name);
- superdat = superdat || itemval.Contains(" - SuperDAT");
- if (keep && superdat)
- {
- Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
- }
-
- line = reader.ReadLine();
- continue;
- }
-
- switch (gc[1].Value)
- {
- case "name":
- case "Name:":
- Name = (String.IsNullOrWhiteSpace(Name) ? itemval : Name);
- superdat = superdat || itemval.Contains(" - SuperDAT");
- if (keep && superdat)
- {
- Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
- }
- break;
- case "description":
- case "Description:":
- Description = (String.IsNullOrWhiteSpace(Description) ? itemval : Description);
- break;
- case "rootdir":
- case "Rootdir:":
- RootDir = (String.IsNullOrWhiteSpace(RootDir) ? itemval : RootDir);
- break;
- case "category":
- case "Category:":
- Category = (String.IsNullOrWhiteSpace(Category) ? itemval : Category);
- break;
- case "version":
- case "Version:":
- Version = (String.IsNullOrWhiteSpace(Version) ? itemval : Version);
- break;
- case "date":
- case "Date:":
- Date = (String.IsNullOrWhiteSpace(Date) ? itemval : Date);
- break;
- case "author":
- case "Author:":
- Author = (String.IsNullOrWhiteSpace(Author) ? itemval : Author);
- break;
- case "email":
- case "Email:":
- Email = (String.IsNullOrWhiteSpace(Email) ? itemval : Email);
- break;
- case "homepage":
- case "Homepage:":
- Homepage = (String.IsNullOrWhiteSpace(Homepage) ? itemval : Homepage);
- break;
- case "url":
- case "Url:":
- Url = (String.IsNullOrWhiteSpace(Url) ? itemval : Url);
- break;
- case "comment":
- case "Comment:":
- Comment = (String.IsNullOrWhiteSpace(Comment) ? itemval : Comment);
- break;
- case "header":
- case "Header:":
- Header = (String.IsNullOrWhiteSpace(Header) ? itemval : Header);
- break;
- case "type":
- case "Type:":
- Type = (String.IsNullOrWhiteSpace(Type) ? itemval : Type);
- superdat = superdat || itemval.Contains("SuperDAT");
- break;
- case "forcemerging":
- if (ForceMerging == ForceMerging.None)
- {
- ForceMerging = Utilities.GetForceMerging(itemval);
- }
- break;
- case "forcezipping":
- if (ForcePacking == ForcePacking.None)
- {
- ForcePacking = Utilities.GetForcePacking(itemval);
- }
- break;
- case "forcepacking":
- if (ForcePacking == ForcePacking.None)
- {
- ForcePacking = Utilities.GetForcePacking(itemval);
- }
- break;
- }
-
- line = reader.ReadLine();
- }
- }
-
- ///
- /// Read set information
- ///
- /// StreamReader to use to parse the header
- /// True if the item is a resource (bios), false otherwise
- /// 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 void ReadSet(
- StreamReader reader,
- bool resource,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Prepare all internal variables
- bool containsItems = false;
- Machine machine = new Machine()
- {
- MachineType = (resource ? MachineType.Bios : MachineType.None),
- };
-
- // If there's no subtree to the header, skip it
- if (reader == null || reader.EndOfStream)
- {
- return;
- }
-
- // Otherwise, add what is possible
- string line = reader.ReadLine();
- while (!Regex.IsMatch(line, Constants.EndPatternCMP))
- {
- // We only want elements
- if (line.Trim().StartsWith("#"))
- {
- line = reader.ReadLine();
- continue;
- }
-
- // Item-specific lines have a known pattern
- string trimmedline = line.Trim();
- if (trimmedline.StartsWith("archive (")
- || trimmedline.StartsWith("biosset (")
- || trimmedline.StartsWith("disk (")
- || trimmedline.StartsWith("file (") // This is a DOSCenter file, not a SabreDAT file
- || trimmedline.StartsWith("release (")
- || trimmedline.StartsWith("rom (")
- || (trimmedline.StartsWith("sample") && !trimmedline.StartsWith("sampleof")))
- {
- containsItems = true;
- ItemType temptype = ItemType.Rom;
- if (line.Trim().StartsWith("rom ("))
- {
- temptype = ItemType.Rom;
- }
- else if (line.Trim().StartsWith("disk ("))
- {
- temptype = ItemType.Disk;
- }
- else if (line.Trim().StartsWith("file ("))
- {
- temptype = ItemType.Rom;
- }
- else if (line.Trim().StartsWith("sample"))
- {
- temptype = ItemType.Sample;
- }
-
- // Create the proper DatItem based on the type
- DatItem item = Utilities.GetDatItem(temptype);
-
- // Then populate it with information
- item.CopyMachineInformation(machine);
-
- item.SystemID = sysid;
- item.System = filename;
- item.SourceID = srcid;
-
- // If we have a sample, treat it special
- if (temptype == ItemType.Sample)
- {
- line = line.Trim().Remove(0, 6).Trim().Replace("\"", ""); // Remove "sample" from the input string
- item.Name = line;
-
- // Now process and add the sample
- ParseAddHelper(item, clean, remUnicode);
- line = reader.ReadLine();
- continue;
- }
-
- // Get the line split by spaces and quotes
- string[] linegc = Utilities.SplitLineAsCMP(line);
-
- // Special cases for DOSCenter DATs only because of how the lines are arranged
- if (line.Trim().StartsWith("file ("))
- {
- // Loop over the specifics
- for (int i = 0; i < linegc.Length; i++)
- {
- // Names are not quoted, for some stupid reason
- if (linegc[i] == "name")
- {
- // Get the name in order until we find the next flag
- while (++i < linegc.Length && linegc[i] != "size"
- && linegc[i] != "date"
- && linegc[i] != "crc"
- && linegc[i] != "md5"
- && linegc[i] != "sha1"
- && linegc[i] != "sha256"
- && linegc[i] != "sha384"
- && linegc[i] != "sha512")
- {
- item.Name += " " + linegc[i];
- }
-
- // Perform correction
- item.Name = item.Name.TrimStart();
- i--;
- }
-
- // Get the size from the next part
- else if (linegc[i] == "size")
- {
- long tempsize = -1;
- if (!Int64.TryParse(linegc[++i], out tempsize))
- {
- tempsize = 0;
- }
- ((Rom)item).Size = tempsize;
- }
-
- // Get the date from the next part
- else if (linegc[i] == "date")
- {
- ((Rom)item).Date = linegc[++i].Replace("\"", "") + " " + linegc[++i].Replace("\"", "");
- }
-
- // Get the CRC from the next part
- else if (linegc[i] == "crc")
- {
- ((Rom)item).CRC = linegc[++i].Replace("\"", "").ToLowerInvariant();
- }
-
- // Get the MD5 from the next part
- else if (linegc[i] == "md5")
- {
- ((Rom)item).MD5 = linegc[++i].Replace("\"", "").ToLowerInvariant();
- }
-
- // Get the SHA1 from the next part
- else if (linegc[i] == "sha1")
- {
- ((Rom)item).SHA1 = linegc[++i].Replace("\"", "").ToLowerInvariant();
- }
-
- // Get the SHA256 from the next part
- else if (linegc[i] == "sha256")
- {
- ((Rom)item).SHA256 = linegc[++i].Replace("\"", "").ToLowerInvariant();
- }
-
- // Get the SHA384 from the next part
- else if (linegc[i] == "sha384")
- {
- ((Rom)item).SHA384 = linegc[++i].Replace("\"", "").ToLowerInvariant();
- }
-
- // Get the SHA512 from the next part
- else if (linegc[i] == "sha512")
- {
- ((Rom)item).SHA512 = linegc[++i].Replace("\"", "").ToLowerInvariant();
- }
- }
-
- // Now process and add the rom
- ParseAddHelper(item, clean, remUnicode);
- line = reader.ReadLine();
- continue;
- }
-
- // Loop over all attributes normally and add them if possible
- for (int i = 0; i < linegc.Length; i++)
- {
- // Look at the current item and use it if possible
- string quoteless = linegc[i].Replace("\"", "");
- switch (quoteless)
- {
- //If the item is empty, we automatically skip it because it's a fluke
- case "":
- continue;
-
- // Special cases for standalone item statuses
- case "baddump":
- case "good":
- case "nodump":
- case "verified":
- ItemStatus tempStandaloneStatus = Utilities.GetItemStatus(quoteless);
- if (item.ItemType == ItemType.Rom)
- {
- ((Rom)item).ItemStatus = tempStandaloneStatus;
- }
- else if (item.ItemType == ItemType.Disk)
- {
- ((Disk)item).ItemStatus = tempStandaloneStatus;
- }
- break;
-
- // Regular attributes
- case "name":
- quoteless = linegc[++i].Replace("\"", "");
- item.Name = quoteless;
- break;
- case "size":
- if (item.ItemType == ItemType.Rom)
- {
- quoteless = linegc[++i].Replace("\"", "");
- if (Int64.TryParse(quoteless, out long size))
- {
- ((Rom)item).Size = size;
- }
- else
- {
- ((Rom)item).Size = -1;
- }
- }
- break;
- case "crc":
- if (item.ItemType == ItemType.Rom)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Rom)item).CRC = Utilities.CleanHashData(quoteless, Constants.CRCLength);
- }
- break;
- case "md5":
- if (item.ItemType == ItemType.Rom)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Rom)item).MD5 = Utilities.CleanHashData(quoteless, Constants.MD5Length);
- }
- else if (item.ItemType == ItemType.Disk)
- {
- i++;
- quoteless = linegc[i].Replace("\"", "");
- ((Disk)item).MD5 = Utilities.CleanHashData(quoteless, Constants.MD5Length);
- }
- break;
- case "sha1":
- if (item.ItemType == ItemType.Rom)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Rom)item).SHA1 = Utilities.CleanHashData(quoteless, Constants.SHA1Length);
- }
- else if (item.ItemType == ItemType.Disk)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Disk)item).SHA1 = Utilities.CleanHashData(quoteless, Constants.SHA1Length);
- }
- break;
- case "sha256":
- if (item.ItemType == ItemType.Rom)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Rom)item).SHA256 = Utilities.CleanHashData(quoteless, Constants.SHA256Length);
- }
- else if (item.ItemType == ItemType.Disk)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Disk)item).SHA256 = Utilities.CleanHashData(quoteless, Constants.SHA256Length);
- }
- break;
- case "sha384":
- if (item.ItemType == ItemType.Rom)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Rom)item).SHA384 = Utilities.CleanHashData(quoteless, Constants.SHA384Length);
- }
- else if (item.ItemType == ItemType.Disk)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Disk)item).SHA384 = Utilities.CleanHashData(quoteless, Constants.SHA384Length);
- }
- break;
- case "sha512":
- if (item.ItemType == ItemType.Rom)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Rom)item).SHA512 = Utilities.CleanHashData(quoteless, Constants.SHA512Length);
- }
- else if (item.ItemType == ItemType.Disk)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Disk)item).SHA512 = Utilities.CleanHashData(quoteless, Constants.SHA512Length);
- }
- break;
- case "status":
- case "flags":
- quoteless = linegc[++i].Replace("\"", "");
- ItemStatus tempFlagStatus = Utilities.GetItemStatus(quoteless);
- if (item.ItemType == ItemType.Rom)
- {
- ((Rom)item).ItemStatus = tempFlagStatus;
- }
- else if (item.ItemType == ItemType.Disk)
- {
- ((Disk)item).ItemStatus = tempFlagStatus;
- }
- break;
- case "date":
- if (item.ItemType == ItemType.Rom)
- {
- // If we have quotes in the next item, assume only one item
- if (linegc[i + 1].Contains("\""))
- {
- quoteless = linegc[++i].Replace("\"", "");
- }
- // Otherwise, we assume we need to read the next two items
- else
- {
- quoteless = linegc[++i].Replace("\"", "") + " " + linegc[++i].Replace("\"", "");
- }
- ((Rom)item).Date = quoteless;
- }
- else if (item.ItemType == ItemType.Release)
- {
- // If we have quotes in the next item, assume only one item
- if (linegc[i + 1].Contains("\""))
- {
- quoteless = linegc[++i].Replace("\"", "");
- }
- // Otherwise, we assume we need to read the next two items
- else
- {
- quoteless = linegc[++i].Replace("\"", "") + " " + linegc[++i].Replace("\"", "");
- }
- ((Release)item).Date = quoteless;
- }
- break;
- case "default":
- if (item.ItemType == ItemType.BiosSet)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((BiosSet)item).Default = Utilities.GetYesNo(quoteless.ToLowerInvariant());
- }
- else if (item.ItemType == ItemType.Release)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Release)item).Default = Utilities.GetYesNo(quoteless.ToLowerInvariant());
- }
- break;
- case "description":
- if (item.ItemType == ItemType.BiosSet)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((BiosSet)item).Description = quoteless.ToLowerInvariant();
- }
- break;
- case "region":
- if (item.ItemType == ItemType.Release)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Release)item).Region = quoteless.ToLowerInvariant();
- }
- break;
- case "language":
- if (item.ItemType == ItemType.Release)
- {
- quoteless = linegc[++i].Replace("\"", "");
- ((Release)item).Language = quoteless.ToLowerInvariant();
- }
- break;
- }
- }
-
- // Now process and add the rom
- ParseAddHelper(item, clean, remUnicode);
-
- line = reader.ReadLine();
- continue;
- }
-
- // Set-specific lines have a known pattern
- GroupCollection setgc = Regex.Match(line, Constants.ItemPatternCMP).Groups;
- string itemval = setgc[2].Value.Replace("\"", "");
-
- switch (setgc[1].Value)
- {
- case "name":
- machine.Name = (itemval.ToLowerInvariant().EndsWith(".zip") ? itemval.Remove(itemval.Length - 4) : itemval);
- machine.Description = (itemval.ToLowerInvariant().EndsWith(".zip") ? itemval.Remove(itemval.Length - 4) : itemval);
- break;
- case "description":
- machine.Description = itemval;
- break;
- case "year":
- machine.Year = itemval;
- break;
- case "manufacturer":
- machine.Manufacturer = itemval;
- break;
- case "cloneof":
- machine.CloneOf = itemval;
- break;
- case "romof":
- machine.RomOf = itemval;
- break;
- case "sampleof":
- machine.SampleOf = itemval;
- break;
- }
-
- line = reader.ReadLine();
- }
-
- // If no items were found for this machine, add a Blank placeholder
- if (!containsItems)
- {
- Blank blank = new Blank()
- {
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- blank.CopyMachineInformation(machine);
-
- // Now process and add the rom
- ParseAddHelper(blank, clean, remUnicode);
- }
- }
-
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
-
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
-
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
-
- // Write out the header
- WriteHeader(sw);
-
- // Write out each of the machines and roms
- string lastgame = null;
-
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
-
- foreach (string key in keys)
- {
- List roms = this[key];
-
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
-
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
-
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
-
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteEndGame(sw, rom);
- }
-
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteStartGame(sw, rom);
- }
-
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
-
- // If we're in a mode that doesn't allow for actual empty folders, add the blank info
- rom.Name = (rom.Name == "null" ? "-" : rom.Name);
- ((Rom)rom).Size = Constants.SizeZero;
- ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
- ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
- ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
- ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
- ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
- ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
- }
-
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
-
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
-
- // Write the file footer out
- WriteFooter(sw);
-
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "clrmamepro (\n" +
- "\tname \"" + Name + "\"\n" +
- "\tdescription \"" + Description + "\"\n" +
- (!String.IsNullOrWhiteSpace(Category) ? "\tcategory \"" + Category + "\"\n" : "") +
- "\tversion \"" + Version + "\"\n" +
- (!String.IsNullOrWhiteSpace(Date) ? "\tdate \"" + Date + "\"\n" : "") +
- "\tauthor \"" + Author + "\"\n" +
- (!String.IsNullOrWhiteSpace(Email) ? "\temail \"" + Email + "\"\n" : "") +
- (!String.IsNullOrWhiteSpace(Homepage) ? "\thomepage \"" + Homepage + "\"\n" : "") +
- (!String.IsNullOrWhiteSpace(Url) ? "\turl \"" + Url + "\"\n" : "") +
- (!String.IsNullOrWhiteSpace(Comment) ? "\tcomment \"" + Comment + "\"\n" : "") +
- (ForcePacking == ForcePacking.Unzip ? "\tforcezipping no\n" : "") +
- (ForcePacking == ForcePacking.Zip ? "\tforcezipping yes\n" : "") +
- (ForceMerging == ForceMerging.Full ? "\tforcemerging full\n" : "") +
- (ForceMerging == ForceMerging.Split ? "\tforcemerging split\n" : "") +
- (ForceMerging == ForceMerging.Merged ? "\tforcemerging merged\n" : "") +
- (ForceMerging == ForceMerging.NonMerged ? "\tforcemerging nonmerged\n" : "") +
- ")\n";
-
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteStartGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
-
- string state = (rom.MachineType == MachineType.Bios ? "resource" : "game") + " (\n\tname \"" + (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName : "") + "\"\n" +
- (!ExcludeFields[(int)Field.RomOf] && String.IsNullOrWhiteSpace(rom.RomOf) ? "" : "\tromof \"" + rom.RomOf + "\"\n") +
- (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? "" : "\tcloneof \"" + rom.CloneOf + "\"\n") +
- (!ExcludeFields[(int)Field.SampleOf] && String.IsNullOrWhiteSpace(rom.SampleOf) ? "" : "\tsampleof \"" + rom.SampleOf + "\"\n") +
- (!ExcludeFields[(int)Field.Description] ? "\tdescription \"" + (String.IsNullOrWhiteSpace(rom.MachineDescription) ? rom.MachineName : rom.MachineDescription) + "\"\n" : "") +
- (!ExcludeFields[(int)Field.Year] && String.IsNullOrWhiteSpace(rom.Year) ? "" : "\tyear " + rom.Year + "\n") +
- (!ExcludeFields[(int)Field.Manufacturer] && String.IsNullOrWhiteSpace(rom.Manufacturer) ? "" : "\tmanufacturer \"" + rom.Manufacturer + "\"\n");
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game end using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteEndGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- string state = (!ExcludeFields[(int)Field.SampleOf] && String.IsNullOrWhiteSpace(rom.SampleOf) ? "" : "\tsampleof \"" + rom.SampleOf + "\"\n") + ")\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// DatFile to write out from
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
-
- try
- {
- string state = "";
-
- // Pre-process the item name
- ProcessItemName(rom, true);
-
- switch (rom.ItemType)
- {
- case ItemType.Archive:
- state += "\tarchive ( name\"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
- + " )\n";
- break;
- case ItemType.BiosSet:
- state += "\tbiosset ( name\"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
- + (!ExcludeFields[(int)Field.Description] && !String.IsNullOrWhiteSpace(((BiosSet)rom).Description) ? " description \"" + ((BiosSet)rom).Description + "\"" : "")
- + (!ExcludeFields[(int)Field.Default] && ((BiosSet)rom).Default != null
- ? "default " + ((BiosSet)rom).Default.ToString().ToLowerInvariant()
- : "")
- + " )\n";
- break;
- case ItemType.Disk:
- state += "\tdisk ( name \"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
- + (!ExcludeFields[(int)Field.MD5] && !String.IsNullOrWhiteSpace(((Disk)rom).MD5) ? " md5 " + ((Disk)rom).MD5.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.SHA1] && !String.IsNullOrWhiteSpace(((Disk)rom).SHA1) ? " sha1 " + ((Disk)rom).SHA1.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.SHA256] && !String.IsNullOrWhiteSpace(((Disk)rom).SHA256) ? " sha256 " + ((Disk)rom).SHA256.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.SHA384] && !String.IsNullOrWhiteSpace(((Disk)rom).SHA384) ? " sha384 " + ((Disk)rom).SHA384.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.SHA512] && !String.IsNullOrWhiteSpace(((Disk)rom).SHA512) ? " sha512 " + ((Disk)rom).SHA512.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.Status] && ((Disk)rom).ItemStatus != ItemStatus.None ? " flags " + ((Disk)rom).ItemStatus.ToString().ToLowerInvariant() : "")
- + " )\n";
- break;
- case ItemType.Release:
- state += "\trelease ( name\"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
- + (!ExcludeFields[(int)Field.Region] && !String.IsNullOrWhiteSpace(((Release)rom).Region) ? " region \"" + ((Release)rom).Region + "\"" : "")
- + (!ExcludeFields[(int)Field.Language] && !String.IsNullOrWhiteSpace(((Release)rom).Language) ? " language \"" + ((Release)rom).Language + "\"" : "")
- + (!ExcludeFields[(int)Field.Date] && !String.IsNullOrWhiteSpace(((Release)rom).Date) ? " date \"" + ((Release)rom).Date + "\"" : "")
- + (!ExcludeFields[(int)Field.Default] && ((Release)rom).Default != null
- ? "default " + ((Release)rom).Default.ToString().ToLowerInvariant()
- : "")
- + " )\n";
- break;
- case ItemType.Rom:
- state += "\trom ( name \"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
- + (!ExcludeFields[(int)Field.Size] && ((Rom)rom).Size != -1 ? " size " + ((Rom)rom).Size : "")
- + (!ExcludeFields[(int)Field.CRC] && !String.IsNullOrWhiteSpace(((Rom)rom).CRC) ? " crc " + ((Rom)rom).CRC.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.MD5] && !String.IsNullOrWhiteSpace(((Rom)rom).MD5) ? " md5 " + ((Rom)rom).MD5.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.SHA1] && !String.IsNullOrWhiteSpace(((Rom)rom).SHA1) ? " sha1 " + ((Rom)rom).SHA1.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.SHA256] && !String.IsNullOrWhiteSpace(((Rom)rom).SHA256) ? " sha256 " + ((Rom)rom).SHA256.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.SHA384] && !String.IsNullOrWhiteSpace(((Rom)rom).SHA384) ? " sha384 " + ((Rom)rom).SHA384.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.SHA512] && !String.IsNullOrWhiteSpace(((Rom)rom).SHA512) ? " sha512 " + ((Rom)rom).SHA512.ToLowerInvariant() : "")
- + (!ExcludeFields[(int)Field.Date] && !String.IsNullOrWhiteSpace(((Rom)rom).Date) ? " date \"" + ((Rom)rom).Date + "\"" : "")
- + (!ExcludeFields[(int)Field.Status] && ((Rom)rom).ItemStatus != ItemStatus.None ? " flags " + ((Rom)rom).ItemStatus.ToString().ToLowerInvariant() : "")
- + " )\n";
- break;
- case ItemType.Sample:
- state += "\tsample ( name\"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
- + " )\n";
- break;
- }
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT footer using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteFooter(StreamWriter sw)
- {
- try
- {
- string footer = footer = ")\n";
-
- // Write the footer out
- sw.Write(footer);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
- }
+ ///
+ /// Represents parsing and writing of a ClrMamePro DAT
+ ///
+ /// TODO: Verify that all write for this DatFile type is correct
+ internal class ClrMamePro : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public ClrMamePro(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
+
+ ///
+ /// Parse a ClrMamePro DAT 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
+ /// 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,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Open a file reader
+ Encoding enc = Utilities.GetEncoding(filename);
+ StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
+
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine();
+
+ // Comments in CMP DATs start with a #
+ if (line.Trim().StartsWith("#"))
+ {
+ continue;
+ }
+
+ // If the line is the header or a game
+ if (Regex.IsMatch(line, Constants.HeaderPatternCMP))
+ {
+ GroupCollection gc = Regex.Match(line, Constants.HeaderPatternCMP).Groups;
+ string normalizedValue = gc[1].Value.ToLowerInvariant();
+
+ // If we have a known header
+ if (normalizedValue == "clrmamepro"
+ || normalizedValue == "romvault"
+ || normalizedValue == "doscenter")
+ {
+ ReadHeader(sr, keep);
+ }
+ // If we have a known set type
+ else if (normalizedValue == "set" // Used by the most ancient DATs
+ || normalizedValue == "game" // Used by most CMP DATs
+ || normalizedValue == "machine") // Possibly used by MAME CMP DATs
+ {
+ ReadSet(sr, false, filename, sysid, srcid, keep, clean, remUnicode);
+ }
+ else if (normalizedValue == "resource") // Used by some other DATs to denote a BIOS set
+ {
+ ReadSet(sr, true, filename, sysid, srcid, keep, clean, remUnicode);
+ }
+ }
+ }
+
+ sr.Dispose();
+ }
+
+ ///
+ /// Read header information
+ ///
+ /// StreamReader to use to parse the header
+ /// True if full pathnames are to be kept, false otherwise (default)
+ private void ReadHeader(StreamReader reader, bool keep)
+ {
+ bool superdat = false;
+
+ // If there's no subtree to the header, skip it
+ if (reader == null || reader.EndOfStream)
+ {
+ return;
+ }
+
+ // Otherwise, add what is possible
+ string line = reader.ReadLine();
+ while (!Regex.IsMatch(line, Constants.EndPatternCMP))
+ {
+ // We only want elements
+ if (line.Trim().StartsWith("#"))
+ {
+ line = reader.ReadLine();
+ continue;
+ }
+
+ // Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
+ GroupCollection gc = Regex.Match(line, Constants.ItemPatternCMP).Groups;
+ string itemval = gc[2].Value.Replace("\"", "");
+
+ if (line.Trim().StartsWith("Name:"))
+ {
+ Name = (String.IsNullOrWhiteSpace(Name) ? line.Substring(6) : Name);
+ superdat = superdat || itemval.Contains(" - SuperDAT");
+ if (keep && superdat)
+ {
+ Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
+ }
+
+ line = reader.ReadLine();
+ continue;
+ }
+
+ switch (gc[1].Value)
+ {
+ case "name":
+ case "Name:":
+ Name = (String.IsNullOrWhiteSpace(Name) ? itemval : Name);
+ superdat = superdat || itemval.Contains(" - SuperDAT");
+ if (keep && superdat)
+ {
+ Type = (String.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
+ }
+ break;
+ case "description":
+ case "Description:":
+ Description = (String.IsNullOrWhiteSpace(Description) ? itemval : Description);
+ break;
+ case "rootdir":
+ case "Rootdir:":
+ RootDir = (String.IsNullOrWhiteSpace(RootDir) ? itemval : RootDir);
+ break;
+ case "category":
+ case "Category:":
+ Category = (String.IsNullOrWhiteSpace(Category) ? itemval : Category);
+ break;
+ case "version":
+ case "Version:":
+ Version = (String.IsNullOrWhiteSpace(Version) ? itemval : Version);
+ break;
+ case "date":
+ case "Date:":
+ Date = (String.IsNullOrWhiteSpace(Date) ? itemval : Date);
+ break;
+ case "author":
+ case "Author:":
+ Author = (String.IsNullOrWhiteSpace(Author) ? itemval : Author);
+ break;
+ case "email":
+ case "Email:":
+ Email = (String.IsNullOrWhiteSpace(Email) ? itemval : Email);
+ break;
+ case "homepage":
+ case "Homepage:":
+ Homepage = (String.IsNullOrWhiteSpace(Homepage) ? itemval : Homepage);
+ break;
+ case "url":
+ case "Url:":
+ Url = (String.IsNullOrWhiteSpace(Url) ? itemval : Url);
+ break;
+ case "comment":
+ case "Comment:":
+ Comment = (String.IsNullOrWhiteSpace(Comment) ? itemval : Comment);
+ break;
+ case "header":
+ case "Header:":
+ Header = (String.IsNullOrWhiteSpace(Header) ? itemval : Header);
+ break;
+ case "type":
+ case "Type:":
+ Type = (String.IsNullOrWhiteSpace(Type) ? itemval : Type);
+ superdat = superdat || itemval.Contains("SuperDAT");
+ break;
+ case "forcemerging":
+ if (ForceMerging == ForceMerging.None)
+ {
+ ForceMerging = Utilities.GetForceMerging(itemval);
+ }
+ break;
+ case "forcezipping":
+ if (ForcePacking == ForcePacking.None)
+ {
+ ForcePacking = Utilities.GetForcePacking(itemval);
+ }
+ break;
+ case "forcepacking":
+ if (ForcePacking == ForcePacking.None)
+ {
+ ForcePacking = Utilities.GetForcePacking(itemval);
+ }
+ break;
+ }
+
+ line = reader.ReadLine();
+ }
+ }
+
+ ///
+ /// Read set information
+ ///
+ /// StreamReader to use to parse the header
+ /// True if the item is a resource (bios), false otherwise
+ /// 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 void ReadSet(
+ StreamReader reader,
+ bool resource,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Prepare all internal variables
+ bool containsItems = false;
+ Machine machine = new Machine()
+ {
+ MachineType = (resource ? MachineType.Bios : MachineType.None),
+ };
+
+ // If there's no subtree to the header, skip it
+ if (reader == null || reader.EndOfStream)
+ {
+ return;
+ }
+
+ // Otherwise, add what is possible
+ string line = reader.ReadLine();
+ while (!Regex.IsMatch(line, Constants.EndPatternCMP))
+ {
+ // We only want elements
+ if (line.Trim().StartsWith("#"))
+ {
+ line = reader.ReadLine();
+ continue;
+ }
+
+ // Item-specific lines have a known pattern
+ string trimmedline = line.Trim();
+ if (trimmedline.StartsWith("archive (")
+ || trimmedline.StartsWith("biosset (")
+ || trimmedline.StartsWith("disk (")
+ || trimmedline.StartsWith("file (") // This is a DOSCenter file, not a SabreDAT file
+ || trimmedline.StartsWith("release (")
+ || trimmedline.StartsWith("rom (")
+ || (trimmedline.StartsWith("sample") && !trimmedline.StartsWith("sampleof")))
+ {
+ containsItems = true;
+ ItemType temptype = ItemType.Rom;
+ if (line.Trim().StartsWith("rom ("))
+ {
+ temptype = ItemType.Rom;
+ }
+ else if (line.Trim().StartsWith("disk ("))
+ {
+ temptype = ItemType.Disk;
+ }
+ else if (line.Trim().StartsWith("file ("))
+ {
+ temptype = ItemType.Rom;
+ }
+ else if (line.Trim().StartsWith("sample"))
+ {
+ temptype = ItemType.Sample;
+ }
+
+ // Create the proper DatItem based on the type
+ DatItem item = Utilities.GetDatItem(temptype);
+
+ // Then populate it with information
+ item.CopyMachineInformation(machine);
+
+ item.SystemID = sysid;
+ item.System = filename;
+ item.SourceID = srcid;
+
+ // If we have a sample, treat it special
+ if (temptype == ItemType.Sample)
+ {
+ line = line.Trim().Remove(0, 6).Trim().Replace("\"", ""); // Remove "sample" from the input string
+ item.Name = line;
+
+ // Now process and add the sample
+ ParseAddHelper(item, clean, remUnicode);
+ line = reader.ReadLine();
+ continue;
+ }
+
+ // Get the line split by spaces and quotes
+ string[] linegc = Utilities.SplitLineAsCMP(line);
+
+ // Special cases for DOSCenter DATs only because of how the lines are arranged
+ if (line.Trim().StartsWith("file ("))
+ {
+ // Loop over the specifics
+ for (int i = 0; i < linegc.Length; i++)
+ {
+ // Names are not quoted, for some stupid reason
+ if (linegc[i] == "name")
+ {
+ // Get the name in order until we find the next flag
+ while (++i < linegc.Length && linegc[i] != "size"
+ && linegc[i] != "date"
+ && linegc[i] != "crc"
+ && linegc[i] != "md5"
+ && linegc[i] != "sha1"
+ && linegc[i] != "sha256"
+ && linegc[i] != "sha384"
+ && linegc[i] != "sha512")
+ {
+ item.Name += " " + linegc[i];
+ }
+
+ // Perform correction
+ item.Name = item.Name.TrimStart();
+ i--;
+ }
+
+ // Get the size from the next part
+ else if (linegc[i] == "size")
+ {
+ long tempsize = -1;
+ if (!Int64.TryParse(linegc[++i], out tempsize))
+ {
+ tempsize = 0;
+ }
+ ((Rom)item).Size = tempsize;
+ }
+
+ // Get the date from the next part
+ else if (linegc[i] == "date")
+ {
+ ((Rom)item).Date = linegc[++i].Replace("\"", "") + " " + linegc[++i].Replace("\"", "");
+ }
+
+ // Get the CRC from the next part
+ else if (linegc[i] == "crc")
+ {
+ ((Rom)item).CRC = linegc[++i].Replace("\"", "").ToLowerInvariant();
+ }
+
+ // Get the MD5 from the next part
+ else if (linegc[i] == "md5")
+ {
+ ((Rom)item).MD5 = linegc[++i].Replace("\"", "").ToLowerInvariant();
+ }
+
+ // Get the SHA1 from the next part
+ else if (linegc[i] == "sha1")
+ {
+ ((Rom)item).SHA1 = linegc[++i].Replace("\"", "").ToLowerInvariant();
+ }
+
+ // Get the SHA256 from the next part
+ else if (linegc[i] == "sha256")
+ {
+ ((Rom)item).SHA256 = linegc[++i].Replace("\"", "").ToLowerInvariant();
+ }
+
+ // Get the SHA384 from the next part
+ else if (linegc[i] == "sha384")
+ {
+ ((Rom)item).SHA384 = linegc[++i].Replace("\"", "").ToLowerInvariant();
+ }
+
+ // Get the SHA512 from the next part
+ else if (linegc[i] == "sha512")
+ {
+ ((Rom)item).SHA512 = linegc[++i].Replace("\"", "").ToLowerInvariant();
+ }
+ }
+
+ // Now process and add the rom
+ ParseAddHelper(item, clean, remUnicode);
+ line = reader.ReadLine();
+ continue;
+ }
+
+ // Loop over all attributes normally and add them if possible
+ for (int i = 0; i < linegc.Length; i++)
+ {
+ // Look at the current item and use it if possible
+ string quoteless = linegc[i].Replace("\"", "");
+ switch (quoteless)
+ {
+ //If the item is empty, we automatically skip it because it's a fluke
+ case "":
+ continue;
+
+ // Special cases for standalone item statuses
+ case "baddump":
+ case "good":
+ case "nodump":
+ case "verified":
+ ItemStatus tempStandaloneStatus = Utilities.GetItemStatus(quoteless);
+ if (item.ItemType == ItemType.Rom)
+ {
+ ((Rom)item).ItemStatus = tempStandaloneStatus;
+ }
+ else if (item.ItemType == ItemType.Disk)
+ {
+ ((Disk)item).ItemStatus = tempStandaloneStatus;
+ }
+ break;
+
+ // Regular attributes
+ case "name":
+ quoteless = linegc[++i].Replace("\"", "");
+ item.Name = quoteless;
+ break;
+ case "size":
+ if (item.ItemType == ItemType.Rom)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ if (Int64.TryParse(quoteless, out long size))
+ {
+ ((Rom)item).Size = size;
+ }
+ else
+ {
+ ((Rom)item).Size = -1;
+ }
+ }
+ break;
+ case "crc":
+ if (item.ItemType == ItemType.Rom)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Rom)item).CRC = Utilities.CleanHashData(quoteless, Constants.CRCLength);
+ }
+ break;
+ case "md5":
+ if (item.ItemType == ItemType.Rom)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Rom)item).MD5 = Utilities.CleanHashData(quoteless, Constants.MD5Length);
+ }
+ else if (item.ItemType == ItemType.Disk)
+ {
+ i++;
+ quoteless = linegc[i].Replace("\"", "");
+ ((Disk)item).MD5 = Utilities.CleanHashData(quoteless, Constants.MD5Length);
+ }
+ break;
+ case "sha1":
+ if (item.ItemType == ItemType.Rom)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Rom)item).SHA1 = Utilities.CleanHashData(quoteless, Constants.SHA1Length);
+ }
+ else if (item.ItemType == ItemType.Disk)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Disk)item).SHA1 = Utilities.CleanHashData(quoteless, Constants.SHA1Length);
+ }
+ break;
+ case "sha256":
+ if (item.ItemType == ItemType.Rom)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Rom)item).SHA256 = Utilities.CleanHashData(quoteless, Constants.SHA256Length);
+ }
+ else if (item.ItemType == ItemType.Disk)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Disk)item).SHA256 = Utilities.CleanHashData(quoteless, Constants.SHA256Length);
+ }
+ break;
+ case "sha384":
+ if (item.ItemType == ItemType.Rom)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Rom)item).SHA384 = Utilities.CleanHashData(quoteless, Constants.SHA384Length);
+ }
+ else if (item.ItemType == ItemType.Disk)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Disk)item).SHA384 = Utilities.CleanHashData(quoteless, Constants.SHA384Length);
+ }
+ break;
+ case "sha512":
+ if (item.ItemType == ItemType.Rom)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Rom)item).SHA512 = Utilities.CleanHashData(quoteless, Constants.SHA512Length);
+ }
+ else if (item.ItemType == ItemType.Disk)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Disk)item).SHA512 = Utilities.CleanHashData(quoteless, Constants.SHA512Length);
+ }
+ break;
+ case "status":
+ case "flags":
+ quoteless = linegc[++i].Replace("\"", "");
+ ItemStatus tempFlagStatus = Utilities.GetItemStatus(quoteless);
+ if (item.ItemType == ItemType.Rom)
+ {
+ ((Rom)item).ItemStatus = tempFlagStatus;
+ }
+ else if (item.ItemType == ItemType.Disk)
+ {
+ ((Disk)item).ItemStatus = tempFlagStatus;
+ }
+ break;
+ case "date":
+ if (item.ItemType == ItemType.Rom)
+ {
+ // If we have quotes in the next item, assume only one item
+ if (linegc[i + 1].Contains("\""))
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ }
+ // Otherwise, we assume we need to read the next two items
+ else
+ {
+ quoteless = linegc[++i].Replace("\"", "") + " " + linegc[++i].Replace("\"", "");
+ }
+ ((Rom)item).Date = quoteless;
+ }
+ else if (item.ItemType == ItemType.Release)
+ {
+ // If we have quotes in the next item, assume only one item
+ if (linegc[i + 1].Contains("\""))
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ }
+ // Otherwise, we assume we need to read the next two items
+ else
+ {
+ quoteless = linegc[++i].Replace("\"", "") + " " + linegc[++i].Replace("\"", "");
+ }
+ ((Release)item).Date = quoteless;
+ }
+ break;
+ case "default":
+ if (item.ItemType == ItemType.BiosSet)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((BiosSet)item).Default = Utilities.GetYesNo(quoteless.ToLowerInvariant());
+ }
+ else if (item.ItemType == ItemType.Release)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Release)item).Default = Utilities.GetYesNo(quoteless.ToLowerInvariant());
+ }
+ break;
+ case "description":
+ if (item.ItemType == ItemType.BiosSet)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((BiosSet)item).Description = quoteless.ToLowerInvariant();
+ }
+ break;
+ case "region":
+ if (item.ItemType == ItemType.Release)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Release)item).Region = quoteless.ToLowerInvariant();
+ }
+ break;
+ case "language":
+ if (item.ItemType == ItemType.Release)
+ {
+ quoteless = linegc[++i].Replace("\"", "");
+ ((Release)item).Language = quoteless.ToLowerInvariant();
+ }
+ break;
+ }
+ }
+
+ // Now process and add the rom
+ ParseAddHelper(item, clean, remUnicode);
+
+ line = reader.ReadLine();
+ continue;
+ }
+
+ // Set-specific lines have a known pattern
+ GroupCollection setgc = Regex.Match(line, Constants.ItemPatternCMP).Groups;
+ string itemval = setgc[2].Value.Replace("\"", "");
+
+ switch (setgc[1].Value)
+ {
+ case "name":
+ machine.Name = (itemval.ToLowerInvariant().EndsWith(".zip") ? itemval.Remove(itemval.Length - 4) : itemval);
+ machine.Description = (itemval.ToLowerInvariant().EndsWith(".zip") ? itemval.Remove(itemval.Length - 4) : itemval);
+ break;
+ case "description":
+ machine.Description = itemval;
+ break;
+ case "year":
+ machine.Year = itemval;
+ break;
+ case "manufacturer":
+ machine.Manufacturer = itemval;
+ break;
+ case "cloneof":
+ machine.CloneOf = itemval;
+ break;
+ case "romof":
+ machine.RomOf = itemval;
+ break;
+ case "sampleof":
+ machine.SampleOf = itemval;
+ break;
+ }
+
+ line = reader.ReadLine();
+ }
+
+ // If no items were found for this machine, add a Blank placeholder
+ if (!containsItems)
+ {
+ Blank blank = new Blank()
+ {
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ blank.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ ParseAddHelper(blank, clean, remUnicode);
+ }
+ }
+
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
+
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
+
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+
+ // Write out the header
+ WriteHeader(sw);
+
+ // Write out each of the machines and roms
+ string lastgame = null;
+
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
+
+ foreach (string key in keys)
+ {
+ List roms = this[key];
+
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
+
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
+
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
+
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteEndGame(sw, rom);
+ }
+
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteStartGame(sw, rom);
+ }
+
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+
+ // If we're in a mode that doesn't allow for actual empty folders, add the blank info
+ rom.Name = (rom.Name == "null" ? "-" : rom.Name);
+ ((Rom)rom).Size = Constants.SizeZero;
+ ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
+ ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
+ ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
+ ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
+ ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
+ ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
+ }
+
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
+
+ // Write the file footer out
+ WriteFooter(sw);
+
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "clrmamepro (\n" +
+ "\tname \"" + Name + "\"\n" +
+ "\tdescription \"" + Description + "\"\n" +
+ (!String.IsNullOrWhiteSpace(Category) ? "\tcategory \"" + Category + "\"\n" : "") +
+ "\tversion \"" + Version + "\"\n" +
+ (!String.IsNullOrWhiteSpace(Date) ? "\tdate \"" + Date + "\"\n" : "") +
+ "\tauthor \"" + Author + "\"\n" +
+ (!String.IsNullOrWhiteSpace(Email) ? "\temail \"" + Email + "\"\n" : "") +
+ (!String.IsNullOrWhiteSpace(Homepage) ? "\thomepage \"" + Homepage + "\"\n" : "") +
+ (!String.IsNullOrWhiteSpace(Url) ? "\turl \"" + Url + "\"\n" : "") +
+ (!String.IsNullOrWhiteSpace(Comment) ? "\tcomment \"" + Comment + "\"\n" : "") +
+ (ForcePacking == ForcePacking.Unzip ? "\tforcezipping no\n" : "") +
+ (ForcePacking == ForcePacking.Zip ? "\tforcezipping yes\n" : "") +
+ (ForceMerging == ForceMerging.Full ? "\tforcemerging full\n" : "") +
+ (ForceMerging == ForceMerging.Split ? "\tforcemerging split\n" : "") +
+ (ForceMerging == ForceMerging.Merged ? "\tforcemerging merged\n" : "") +
+ (ForceMerging == ForceMerging.NonMerged ? "\tforcemerging nonmerged\n" : "") +
+ ")\n";
+
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteStartGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
+
+ string state = (rom.MachineType == MachineType.Bios ? "resource" : "game") + " (\n\tname \"" + (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName : "") + "\"\n" +
+ (!ExcludeFields[(int)Field.RomOf] && String.IsNullOrWhiteSpace(rom.RomOf) ? "" : "\tromof \"" + rom.RomOf + "\"\n") +
+ (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? "" : "\tcloneof \"" + rom.CloneOf + "\"\n") +
+ (!ExcludeFields[(int)Field.SampleOf] && String.IsNullOrWhiteSpace(rom.SampleOf) ? "" : "\tsampleof \"" + rom.SampleOf + "\"\n") +
+ (!ExcludeFields[(int)Field.Description] ? "\tdescription \"" + (String.IsNullOrWhiteSpace(rom.MachineDescription) ? rom.MachineName : rom.MachineDescription) + "\"\n" : "") +
+ (!ExcludeFields[(int)Field.Year] && String.IsNullOrWhiteSpace(rom.Year) ? "" : "\tyear " + rom.Year + "\n") +
+ (!ExcludeFields[(int)Field.Manufacturer] && String.IsNullOrWhiteSpace(rom.Manufacturer) ? "" : "\tmanufacturer \"" + rom.Manufacturer + "\"\n");
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game end using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteEndGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ string state = (!ExcludeFields[(int)Field.SampleOf] && String.IsNullOrWhiteSpace(rom.SampleOf) ? "" : "\tsampleof \"" + rom.SampleOf + "\"\n") + ")\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// DatFile to write out from
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
+
+ try
+ {
+ string state = "";
+
+ // Pre-process the item name
+ ProcessItemName(rom, true);
+
+ switch (rom.ItemType)
+ {
+ case ItemType.Archive:
+ state += "\tarchive ( name\"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
+ + " )\n";
+ break;
+ case ItemType.BiosSet:
+ state += "\tbiosset ( name\"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
+ + (!ExcludeFields[(int)Field.Description] && !String.IsNullOrWhiteSpace(((BiosSet)rom).Description) ? " description \"" + ((BiosSet)rom).Description + "\"" : "")
+ + (!ExcludeFields[(int)Field.Default] && ((BiosSet)rom).Default != null
+ ? "default " + ((BiosSet)rom).Default.ToString().ToLowerInvariant()
+ : "")
+ + " )\n";
+ break;
+ case ItemType.Disk:
+ state += "\tdisk ( name \"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
+ + (!ExcludeFields[(int)Field.MD5] && !String.IsNullOrWhiteSpace(((Disk)rom).MD5) ? " md5 " + ((Disk)rom).MD5.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.SHA1] && !String.IsNullOrWhiteSpace(((Disk)rom).SHA1) ? " sha1 " + ((Disk)rom).SHA1.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.SHA256] && !String.IsNullOrWhiteSpace(((Disk)rom).SHA256) ? " sha256 " + ((Disk)rom).SHA256.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.SHA384] && !String.IsNullOrWhiteSpace(((Disk)rom).SHA384) ? " sha384 " + ((Disk)rom).SHA384.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.SHA512] && !String.IsNullOrWhiteSpace(((Disk)rom).SHA512) ? " sha512 " + ((Disk)rom).SHA512.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.Status] && ((Disk)rom).ItemStatus != ItemStatus.None ? " flags " + ((Disk)rom).ItemStatus.ToString().ToLowerInvariant() : "")
+ + " )\n";
+ break;
+ case ItemType.Release:
+ state += "\trelease ( name\"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
+ + (!ExcludeFields[(int)Field.Region] && !String.IsNullOrWhiteSpace(((Release)rom).Region) ? " region \"" + ((Release)rom).Region + "\"" : "")
+ + (!ExcludeFields[(int)Field.Language] && !String.IsNullOrWhiteSpace(((Release)rom).Language) ? " language \"" + ((Release)rom).Language + "\"" : "")
+ + (!ExcludeFields[(int)Field.Date] && !String.IsNullOrWhiteSpace(((Release)rom).Date) ? " date \"" + ((Release)rom).Date + "\"" : "")
+ + (!ExcludeFields[(int)Field.Default] && ((Release)rom).Default != null
+ ? "default " + ((Release)rom).Default.ToString().ToLowerInvariant()
+ : "")
+ + " )\n";
+ break;
+ case ItemType.Rom:
+ state += "\trom ( name \"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
+ + (!ExcludeFields[(int)Field.Size] && ((Rom)rom).Size != -1 ? " size " + ((Rom)rom).Size : "")
+ + (!ExcludeFields[(int)Field.CRC] && !String.IsNullOrWhiteSpace(((Rom)rom).CRC) ? " crc " + ((Rom)rom).CRC.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.MD5] && !String.IsNullOrWhiteSpace(((Rom)rom).MD5) ? " md5 " + ((Rom)rom).MD5.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.SHA1] && !String.IsNullOrWhiteSpace(((Rom)rom).SHA1) ? " sha1 " + ((Rom)rom).SHA1.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.SHA256] && !String.IsNullOrWhiteSpace(((Rom)rom).SHA256) ? " sha256 " + ((Rom)rom).SHA256.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.SHA384] && !String.IsNullOrWhiteSpace(((Rom)rom).SHA384) ? " sha384 " + ((Rom)rom).SHA384.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.SHA512] && !String.IsNullOrWhiteSpace(((Rom)rom).SHA512) ? " sha512 " + ((Rom)rom).SHA512.ToLowerInvariant() : "")
+ + (!ExcludeFields[(int)Field.Date] && !String.IsNullOrWhiteSpace(((Rom)rom).Date) ? " date \"" + ((Rom)rom).Date + "\"" : "")
+ + (!ExcludeFields[(int)Field.Status] && ((Rom)rom).ItemStatus != ItemStatus.None ? " flags " + ((Rom)rom).ItemStatus.ToString().ToLowerInvariant() : "")
+ + " )\n";
+ break;
+ case ItemType.Sample:
+ state += "\tsample ( name\"" + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\""
+ + " )\n";
+ break;
+ }
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT footer using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteFooter(StreamWriter sw)
+ {
+ try
+ {
+ string footer = footer = ")\n";
+
+ // Write the footer out
+ sw.Write(footer);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/DosCenter.cs b/SabreTools.Library/DatFiles/DosCenter.cs
index 5d475489..2c1b95e4 100644
--- a/SabreTools.Library/DatFiles/DosCenter.cs
+++ b/SabreTools.Library/DatFiles/DosCenter.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -19,313 +18,313 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a DosCenter DAT
- ///
- internal class DosCenter : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public DosCenter(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
+ ///
+ /// Represents parsing and writing of a DosCenter DAT
+ ///
+ internal class DosCenter : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public DosCenter(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
- ///
- /// Parse a DosCenter DAT 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
- /// 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)
- /// TODO: Pull parsing into this file instead of relying on CMP
- public override void ParseFile(
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
+ ///
+ /// Parse a DosCenter DAT 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
+ /// 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)
+ /// TODO: Pull parsing into this file instead of relying on CMP
+ public override void ParseFile(
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // ClrMamePro and DosCenter parsing are identical so it just calls one implementation
- new ClrMamePro(this).ParseFile(filename, sysid, srcid, keep, clean, remUnicode);
- }
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // ClrMamePro and DosCenter parsing are identical so it just calls one implementation
+ new ClrMamePro(this).ParseFile(filename, sysid, srcid, keep, clean, remUnicode);
+ }
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
- // Write out the header
- WriteHeader(sw);
+ // Write out the header
+ WriteHeader(sw);
- // Write out each of the machines and roms
- string lastgame = null;
+ // Write out each of the machines and roms
+ string lastgame = null;
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
- foreach (string key in keys)
- {
- List roms = this[key];
+ foreach (string key in keys)
+ {
+ List roms = this[key];
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
- List newsplit = rom.MachineName.Split('\\').ToList();
+ List newsplit = rom.MachineName.Split('\\').ToList();
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteEndGame(sw, rom);
- }
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteEndGame(sw, rom);
+ }
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteStartGame(sw, rom);
- }
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteStartGame(sw, rom);
+ }
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
- rom.Name = (rom.Name == "null" ? "-" : rom.Name);
- ((Rom)rom).Size = Constants.SizeZero;
- ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
- ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
- ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
- ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
- ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
- ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
- }
+ rom.Name = (rom.Name == "null" ? "-" : rom.Name);
+ ((Rom)rom).Size = Constants.SizeZero;
+ ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
+ ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
+ ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
+ ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
+ ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
+ ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
+ }
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
- // Write the file footer out
- WriteFooter(sw);
+ // Write the file footer out
+ WriteFooter(sw);
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "DOSCenter (\n" +
- "\tName: " + Name + "\n" +
- "\tDescription: " + Description + "\n" +
- "\tVersion: " + Version + "\n" +
- "\tDate: " + Date + "\n" +
- "\tAuthor: " + Author + "\n" +
- "\tHomepage: " + Homepage + "\n" +
- "\tComment: " + Comment + "\n" +
- ")\n";
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "DOSCenter (\n" +
+ "\tName: " + Name + "\n" +
+ "\tDescription: " + Description + "\n" +
+ "\tVersion: " + Version + "\n" +
+ "\tDate: " + Date + "\n" +
+ "\tAuthor: " + Author + "\n" +
+ "\tHomepage: " + Homepage + "\n" +
+ "\tComment: " + Comment + "\n" +
+ ")\n";
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteStartGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteStartGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
- string state = "game (\n\tname \"" + (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName + ".zip" : "") + "\"\n";
+ string state = "game (\n\tname \"" + (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName + ".zip" : "") + "\"\n";
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out Game end using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteEndGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- string state = (!ExcludeFields[(int)Field.SampleOf] && String.IsNullOrWhiteSpace(rom.SampleOf) ? "" : "\tsampleof \"" + rom.SampleOf + "\"\n") + ")\n";
+ ///
+ /// Write out Game end using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteEndGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ string state = (!ExcludeFields[(int)Field.SampleOf] && String.IsNullOrWhiteSpace(rom.SampleOf) ? "" : "\tsampleof \"" + rom.SampleOf + "\"\n") + ")\n";
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
- try
- {
- string state = "";
+ try
+ {
+ string state = "";
- // Pre-process the item name
- ProcessItemName(rom, true);
+ // Pre-process the item name
+ ProcessItemName(rom, true);
- switch (rom.ItemType)
- {
- case ItemType.Archive:
- case ItemType.BiosSet:
- case ItemType.Disk:
- case ItemType.Release:
- case ItemType.Sample:
- // We don't output these at all for DosCenter
- break;
- case ItemType.Rom:
- state += "\tfile ( name " + (!ExcludeFields[(int)Field.Name] ? ((Rom)rom).Name : "")
- + (!ExcludeFields[(int)Field.Size] && ((Rom)rom).Size != -1 ? " size " + ((Rom)rom).Size : "")
- + (!ExcludeFields[(int)Field.Date] && !String.IsNullOrWhiteSpace(((Rom)rom).Date) ? " date " + ((Rom)rom).Date : "")
- + (!ExcludeFields[(int)Field.CRC] && !String.IsNullOrWhiteSpace(((Rom)rom).CRC) ? " crc " + ((Rom)rom).CRC.ToLowerInvariant() : "")
- + " )\n";
- break;
- }
+ switch (rom.ItemType)
+ {
+ case ItemType.Archive:
+ case ItemType.BiosSet:
+ case ItemType.Disk:
+ case ItemType.Release:
+ case ItemType.Sample:
+ // We don't output these at all for DosCenter
+ break;
+ case ItemType.Rom:
+ state += "\tfile ( name " + (!ExcludeFields[(int)Field.Name] ? ((Rom)rom).Name : "")
+ + (!ExcludeFields[(int)Field.Size] && ((Rom)rom).Size != -1 ? " size " + ((Rom)rom).Size : "")
+ + (!ExcludeFields[(int)Field.Date] && !String.IsNullOrWhiteSpace(((Rom)rom).Date) ? " date " + ((Rom)rom).Date : "")
+ + (!ExcludeFields[(int)Field.CRC] && !String.IsNullOrWhiteSpace(((Rom)rom).CRC) ? " crc " + ((Rom)rom).CRC.ToLowerInvariant() : "")
+ + " )\n";
+ break;
+ }
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DAT footer using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteFooter(StreamWriter sw)
- {
- try
- {
- string footer = ")\n";
+ ///
+ /// Write out DAT footer using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteFooter(StreamWriter sw)
+ {
+ try
+ {
+ string footer = ")\n";
- // Write the footer out
- sw.Write(footer);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ // Write the footer out
+ sw.Write(footer);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
- }
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/Hashfile.cs b/SabreTools.Library/DatFiles/Hashfile.cs
index 0fa1920d..8c11d9bb 100644
--- a/SabreTools.Library/DatFiles/Hashfile.cs
+++ b/SabreTools.Library/DatFiles/Hashfile.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -19,282 +18,282 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a hashfile such as an SFV, MD5, or SHA-1 file
- ///
- internal class Hashfile : DatFile
- {
- // Private instance variables specific to Hashfile DATs
- Hash _hash;
+ ///
+ /// Represents parsing and writing of a hashfile such as an SFV, MD5, or SHA-1 file
+ ///
+ internal class Hashfile : DatFile
+ {
+ // Private instance variables specific to Hashfile DATs
+ Hash _hash;
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- /// Type of hash that is associated with this DAT
- public Hashfile(DatFile datFile, Hash hash)
- : base(datFile, cloneHeader: false)
- {
- _hash = hash;
- }
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ /// Type of hash that is associated with this DAT
+ public Hashfile(DatFile datFile, Hash hash)
+ : base(datFile, cloneHeader: false)
+ {
+ _hash = hash;
+ }
- ///
- /// Parse a hashfile or SFV 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
- /// 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,
- int sysid,
- int srcid,
+ ///
+ /// Parse a hashfile or SFV 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
+ /// 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,
+ int sysid,
+ int srcid,
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Open a file reader
- Encoding enc = Utilities.GetEncoding(filename);
- StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Open a file reader
+ Encoding enc = Utilities.GetEncoding(filename);
+ StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
- while (!sr.EndOfStream)
- {
- string line = sr.ReadLine();
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine();
- // Split the line and get the name and hash
- string[] split = line.Split(' ');
- string name = "";
- string hash = "";
+ // Split the line and get the name and hash
+ string[] split = line.Split(' ');
+ string name = "";
+ string hash = "";
- // If we have CRC, then it's an SFV file and the name is first are
- if ((_hash & Hash.CRC) != 0)
- {
- name = split[0].Replace("*", String.Empty);
- hash = split[1];
- }
- // Otherwise, the name is second
- else
- {
- name = split[1].Replace("*", String.Empty);
- hash = split[0];
- }
+ // If we have CRC, then it's an SFV file and the name is first are
+ if ((_hash & Hash.CRC) != 0)
+ {
+ name = split[0].Replace("*", String.Empty);
+ hash = split[1];
+ }
+ // Otherwise, the name is second
+ else
+ {
+ name = split[1].Replace("*", String.Empty);
+ hash = split[0];
+ }
- Rom rom = new Rom
- {
- Name = name,
- Size = -1,
- CRC = ((_hash & Hash.CRC) != 0 ? Utilities.CleanHashData(hash, Constants.CRCLength) : null),
- MD5 = ((_hash & Hash.MD5) != 0 ? Utilities.CleanHashData(hash, Constants.MD5Length) : null),
- SHA1 = ((_hash & Hash.SHA1) != 0 ? Utilities.CleanHashData(hash, Constants.SHA1Length) : null),
- SHA256 = ((_hash & Hash.SHA256) != 0 ? Utilities.CleanHashData(hash, Constants.SHA256Length) : null),
- SHA384 = ((_hash & Hash.SHA384) != 0 ? Utilities.CleanHashData(hash, Constants.SHA384Length) : null),
- SHA512 = ((_hash & Hash.SHA512) != 0 ? Utilities.CleanHashData(hash, Constants.SHA512Length) : null),
- ItemStatus = ItemStatus.None,
+ Rom rom = new Rom
+ {
+ Name = name,
+ Size = -1,
+ CRC = ((_hash & Hash.CRC) != 0 ? Utilities.CleanHashData(hash, Constants.CRCLength) : null),
+ MD5 = ((_hash & Hash.MD5) != 0 ? Utilities.CleanHashData(hash, Constants.MD5Length) : null),
+ SHA1 = ((_hash & Hash.SHA1) != 0 ? Utilities.CleanHashData(hash, Constants.SHA1Length) : null),
+ SHA256 = ((_hash & Hash.SHA256) != 0 ? Utilities.CleanHashData(hash, Constants.SHA256Length) : null),
+ SHA384 = ((_hash & Hash.SHA384) != 0 ? Utilities.CleanHashData(hash, Constants.SHA384Length) : null),
+ SHA512 = ((_hash & Hash.SHA512) != 0 ? Utilities.CleanHashData(hash, Constants.SHA512Length) : null),
+ ItemStatus = ItemStatus.None,
- MachineName = Path.GetFileNameWithoutExtension(filename),
+ MachineName = Path.GetFileNameWithoutExtension(filename),
- SystemID = sysid,
- SourceID = srcid,
- };
+ SystemID = sysid,
+ SourceID = srcid,
+ };
- // Now process and add the rom
- ParseAddHelper(rom, clean, remUnicode);
- }
+ // Now process and add the rom
+ ParseAddHelper(rom, clean, remUnicode);
+ }
- sr.Dispose();
- }
+ sr.Dispose();
+ }
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
- foreach (string key in keys)
- {
- List roms = this[key];
+ foreach (string key in keys)
+ {
+ List roms = this[key];
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
- }
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+ }
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
- }
- }
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+ }
+ }
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
- try
- {
- string state = "";
+ try
+ {
+ string state = "";
- // Pre-process the item name
- ProcessItemName(rom, true);
+ // Pre-process the item name
+ ProcessItemName(rom, true);
- switch (_hash)
- {
- case Hash.MD5:
- if (rom.ItemType == ItemType.Rom)
- {
- state += (!ExcludeFields[(int)Field.MD5] ? ((Rom)rom).MD5 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- else if (rom.ItemType == ItemType.Disk)
- {
- state += (!ExcludeFields[(int)Field.MD5] ? ((Disk)rom).MD5 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- break;
- case Hash.CRC:
- if (rom.ItemType == ItemType.Rom)
- {
- state += (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "")
- + " " + (!ExcludeFields[(int)Field.CRC] ? ((Rom)rom).CRC : "") + "\n";
- }
- break;
- case Hash.SHA1:
- if (rom.ItemType == ItemType.Rom)
- {
- state += (!ExcludeFields[(int)Field.SHA1] ? ((Rom)rom).SHA1 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- else if (rom.ItemType == ItemType.Disk)
- {
- state += (!ExcludeFields[(int)Field.SHA1] ? ((Disk)rom).SHA1 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- break;
- case Hash.SHA256:
- if (rom.ItemType == ItemType.Rom)
- {
- state += (!ExcludeFields[(int)Field.SHA256] ? ((Rom)rom).SHA256 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- else if (rom.ItemType == ItemType.Disk)
- {
- state += (!ExcludeFields[(int)Field.SHA256] ? ((Disk)rom).SHA256 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- break;
- case Hash.SHA384:
- if (rom.ItemType == ItemType.Rom)
- {
- state += (!ExcludeFields[(int)Field.SHA384] ? ((Rom)rom).SHA384 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- else if (rom.ItemType == ItemType.Disk)
- {
- state += (!ExcludeFields[(int)Field.SHA384] ? ((Disk)rom).SHA384 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- break;
- case Hash.SHA512:
- if (rom.ItemType == ItemType.Rom)
- {
- state += (!ExcludeFields[(int)Field.SHA512] ? ((Rom)rom).SHA512 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- else if (rom.ItemType == ItemType.Disk)
- {
- state += (!ExcludeFields[(int)Field.SHA512] ? ((Disk)rom).SHA512 : "")
- + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
- + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- break;
- }
+ switch (_hash)
+ {
+ case Hash.MD5:
+ if (rom.ItemType == ItemType.Rom)
+ {
+ state += (!ExcludeFields[(int)Field.MD5] ? ((Rom)rom).MD5 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ else if (rom.ItemType == ItemType.Disk)
+ {
+ state += (!ExcludeFields[(int)Field.MD5] ? ((Disk)rom).MD5 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ break;
+ case Hash.CRC:
+ if (rom.ItemType == ItemType.Rom)
+ {
+ state += (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "")
+ + " " + (!ExcludeFields[(int)Field.CRC] ? ((Rom)rom).CRC : "") + "\n";
+ }
+ break;
+ case Hash.SHA1:
+ if (rom.ItemType == ItemType.Rom)
+ {
+ state += (!ExcludeFields[(int)Field.SHA1] ? ((Rom)rom).SHA1 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ else if (rom.ItemType == ItemType.Disk)
+ {
+ state += (!ExcludeFields[(int)Field.SHA1] ? ((Disk)rom).SHA1 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ break;
+ case Hash.SHA256:
+ if (rom.ItemType == ItemType.Rom)
+ {
+ state += (!ExcludeFields[(int)Field.SHA256] ? ((Rom)rom).SHA256 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ else if (rom.ItemType == ItemType.Disk)
+ {
+ state += (!ExcludeFields[(int)Field.SHA256] ? ((Disk)rom).SHA256 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ break;
+ case Hash.SHA384:
+ if (rom.ItemType == ItemType.Rom)
+ {
+ state += (!ExcludeFields[(int)Field.SHA384] ? ((Rom)rom).SHA384 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ else if (rom.ItemType == ItemType.Disk)
+ {
+ state += (!ExcludeFields[(int)Field.SHA384] ? ((Disk)rom).SHA384 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ break;
+ case Hash.SHA512:
+ if (rom.ItemType == ItemType.Rom)
+ {
+ state += (!ExcludeFields[(int)Field.SHA512] ? ((Rom)rom).SHA512 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ else if (rom.ItemType == ItemType.Disk)
+ {
+ state += (!ExcludeFields[(int)Field.SHA512] ? ((Disk)rom).SHA512 : "")
+ + " *" + (!ExcludeFields[(int)Field.MachineName] && GameName ? rom.MachineName + Path.DirectorySeparatorChar : "")
+ + (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ break;
+ }
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
- }
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/Listrom.cs b/SabreTools.Library/DatFiles/Listrom.cs
index bf68455e..c123988d 100644
--- a/SabreTools.Library/DatFiles/Listrom.cs
+++ b/SabreTools.Library/DatFiles/Listrom.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -20,497 +19,497 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a MAME Listrom DAT
- ///
- internal class Listrom : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public Listrom(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
-
- ///
- /// Parse a MAME Listrom DAT 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
- /// 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)
- ///
- /// In a new style MAME listrom DAT, each game has the following format:
- ///
- /// ROMs required for driver "005".
- /// Name Size Checksum
- /// 1346b.cpu-u25 2048 CRC(8e68533e) SHA1(a257c556d31691068ed5c991f1fb2b51da4826db)
- /// 6331.sound-u8 32 BAD CRC(1d298cb0) SHA1(bb0bb62365402543e3154b9a77be9c75010e6abc) BAD_DUMP
- /// 16v8h-blue.u24 279 NO GOOD DUMP KNOWN
- ///
- public override void ParseFile(
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Open a file reader
- Encoding enc = Utilities.GetEncoding(filename);
- StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
-
- string gamename = "";
- while (!sr.EndOfStream)
- {
- string line = sr.ReadLine().Trim();
-
- // If we have a blank line, we just skip it
- if (String.IsNullOrWhiteSpace(line))
- {
- continue;
- }
-
- // If we have the descriptor line, ignore it
- else if (line == "Name Size Checksum")
- {
- continue;
- }
-
- // If we have the beginning of a game, set the name of the game
- else if (line.StartsWith("ROMs required for"))
- {
- gamename = Regex.Match(line, @"^ROMs required for \S*? ""(.*?)""\.").Groups[1].Value;
- }
-
- // If we have a machine with no required roms (usually internal devices), skip it
- else if (line.StartsWith("No ROMs required for"))
- {
- continue;
- }
-
- // Otherwise, we assume we have a rom that we need to add
- else
- {
- // First, we preprocess the line so that the rom name is consistently correct
- string romname = "";
- string[] split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
-
- // If the line doesn't have the 4 spaces of padding, check for 3
- if (split.Length == 1)
- {
- split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
- }
-
- // If the split is still unsuccessful, log it and skip
- if (split.Length == 1)
- {
- Globals.Logger.Warning("Possibly malformed line: '{0}'", line);
- }
-
- romname = split[0];
- line = line.Substring(romname.Length);
-
- // Next we separate the ROM into pieces
- split = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
-
- // Standard Disks have 2 pieces (name, sha1)
- if (split.Length == 1)
- {
- Disk disk = new Disk()
- {
- Name = romname,
- SHA1 = Utilities.CleanListromHashData(split[0]),
-
- MachineName = gamename,
- };
-
- ParseAddHelper(disk, clean, remUnicode);
- }
-
- // Baddump Disks have 4 pieces (name, BAD, sha1, BAD_DUMP)
- else if (split.Length == 3 && line.EndsWith("BAD_DUMP"))
- {
- Disk disk = new Disk()
- {
- Name = romname,
- SHA1 = Utilities.CleanListromHashData(split[1]),
- ItemStatus = ItemStatus.BadDump,
-
- MachineName = gamename,
- };
-
- ParseAddHelper(disk, clean, remUnicode);
- }
-
- // Standard ROMs have 4 pieces (name, size, crc, sha1)
- else if (split.Length == 3)
- {
- if (!Int64.TryParse(split[0], out long size))
- {
- size = 0;
- }
-
- Rom rom = new Rom()
- {
- Name = romname,
- Size = size,
- CRC = Utilities.CleanListromHashData(split[1]),
- SHA1 = Utilities.CleanListromHashData(split[2]),
-
- MachineName = gamename,
- };
-
- ParseAddHelper(rom, clean, remUnicode);
- }
-
- // Nodump Disks have 5 pieces (name, NO, GOOD, DUMP, KNOWN)
- else if (split.Length == 4 && line.EndsWith("NO GOOD DUMP KNOWN"))
- {
- Disk disk = new Disk()
- {
- Name = romname,
- ItemStatus = ItemStatus.Nodump,
-
- MachineName = gamename,
- };
-
- ParseAddHelper(disk, clean, remUnicode);
- }
-
- // Baddump ROMs have 6 pieces (name, size, BAD, crc, sha1, BAD_DUMP)
- else if (split.Length == 5 && line.EndsWith("BAD_DUMP"))
- {
- if (!Int64.TryParse(split[0], out long size))
- {
- size = 0;
- }
-
- Rom rom = new Rom()
- {
- Name = romname,
- Size = size,
- CRC = Utilities.CleanListromHashData(split[2]),
- SHA1 = Utilities.CleanListromHashData(split[3]),
- ItemStatus = ItemStatus.BadDump,
-
- MachineName = gamename,
- };
-
- ParseAddHelper(rom, clean, remUnicode);
- }
-
- // Nodump ROMs have 6 pieces (name, size, NO, GOOD, DUMP, KNOWN)
- else if (split.Length == 5 && line.EndsWith("NO GOOD DUMP KNOWN"))
- {
- if (!Int64.TryParse(split[0], out long size))
- {
- size = 0;
- }
-
- Rom rom = new Rom()
- {
- Name = romname,
- Size = size,
- ItemStatus = ItemStatus.Nodump,
-
- MachineName = gamename,
- };
-
- ParseAddHelper(rom, clean, remUnicode);
- }
-
- // If we have something else, it's invalid
- else
- {
- Globals.Logger.Warning("Invalid line detected: '{0} {1}'", romname, line);
- }
- }
- }
- }
-
-
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
-
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
-
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
-
- // Write out each of the machines and roms
- string lastgame = null;
-
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
-
- foreach (string key in keys)
- {
- List roms = this[key];
-
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
-
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
-
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
-
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteEndGame(sw);
- }
-
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteStartGame(sw, rom);
- }
-
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
-
- rom.Name = (rom.Name == "null" ? "-" : rom.Name);
- ((Rom)rom).Size = Constants.SizeZero;
- ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
- ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
- ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
- ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
- ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
- ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
- }
-
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
-
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
-
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteStartGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
-
- string state = "ROMs required for driver \"" + (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName : "") + "\".\n" +
- "Name Size Checksum\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game end using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteEndGame(StreamWriter sw)
- {
- try
- {
- string state = "\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
-
- try
- {
- string state = "";
-
- // Pre-process the item name
- ProcessItemName(rom, true);
-
- switch (rom.ItemType)
- {
- case ItemType.Archive:
- case ItemType.BiosSet:
- case ItemType.Release:
- case ItemType.Sample:
- // We don't output these at all
- break;
- case ItemType.Disk:
- // The name is padded out to a particular length
- if (rom.Name.Length < 43)
- {
- state += rom.Name.PadRight(43, ' ');
- }
- else
- {
- state += rom.Name + " ";
- }
-
- // If we have a baddump, put the first indicator
- if (!ExcludeFields[(int)Field.Status] && ((Disk)rom).ItemStatus == ItemStatus.BadDump)
- {
- state += " BAD";
- }
-
- // If we have a nodump, write out the indicator
- if (!ExcludeFields[(int)Field.Status] && ((Disk)rom).ItemStatus == ItemStatus.Nodump)
- {
- state += " NO GOOD DUMP KNOWN";
- }
- // Otherwise, write out the SHA-1 hash
- else if (!ExcludeFields[(int)Field.SHA1])
- {
- state += " SHA1(" + ((Disk)rom).SHA1 + ")";
- }
-
- // If we have a baddump, put the second indicator
- if (!ExcludeFields[(int)Field.Status] && ((Disk)rom).ItemStatus == ItemStatus.BadDump)
- {
- state += " BAD_DUMP";
- }
-
- state += "\n";
- break;
- case ItemType.Rom:
- // The name is padded out to a particular length
- if (rom.Name.Length < 40)
- {
- state += rom.Name.PadRight(43 - (((Rom)rom).Size.ToString().Length), ' ');
- }
- else
- {
- state += rom.Name + " ";
- }
-
- // If we don't have a nodump, write out the size
- if (((Rom)rom).ItemStatus != ItemStatus.Nodump)
- {
- state += ((Rom)rom).Size;
- }
-
- // If we have a baddump, put the first indicator
- if (!ExcludeFields[(int)Field.Status] && ((Rom)rom).ItemStatus == ItemStatus.BadDump)
- {
- state += " BAD";
- }
-
- // If we have a nodump, write out the indicator
- if (!ExcludeFields[(int)Field.Status] && ((Rom)rom).ItemStatus == ItemStatus.Nodump)
- {
- state += " NO GOOD DUMP KNOWN";
- }
- // Otherwise, write out the CRC and SHA-1 hashes
- else
- {
- state += (!ExcludeFields[(int)Field.CRC] ? " CRC(" + ((Rom)rom).CRC + ")" : "");
- state += (!ExcludeFields[(int)Field.SHA1] ? " SHA1(" + ((Rom)rom).SHA1 + ")" : "");
- }
-
- // If we have a baddump, put the second indicator
- if (!ExcludeFields[(int)Field.Status] && ((Rom)rom).ItemStatus == ItemStatus.BadDump)
- {
- state += " BAD_DUMP";
- }
-
- state += "\n";
- break;
- }
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
- }
+ ///
+ /// Represents parsing and writing of a MAME Listrom DAT
+ ///
+ internal class Listrom : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public Listrom(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
+
+ ///
+ /// Parse a MAME Listrom DAT 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
+ /// 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)
+ ///
+ /// In a new style MAME listrom DAT, each game has the following format:
+ ///
+ /// ROMs required for driver "005".
+ /// Name Size Checksum
+ /// 1346b.cpu-u25 2048 CRC(8e68533e) SHA1(a257c556d31691068ed5c991f1fb2b51da4826db)
+ /// 6331.sound-u8 32 BAD CRC(1d298cb0) SHA1(bb0bb62365402543e3154b9a77be9c75010e6abc) BAD_DUMP
+ /// 16v8h-blue.u24 279 NO GOOD DUMP KNOWN
+ ///
+ public override void ParseFile(
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Open a file reader
+ Encoding enc = Utilities.GetEncoding(filename);
+ StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
+
+ string gamename = "";
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine().Trim();
+
+ // If we have a blank line, we just skip it
+ if (String.IsNullOrWhiteSpace(line))
+ {
+ continue;
+ }
+
+ // If we have the descriptor line, ignore it
+ else if (line == "Name Size Checksum")
+ {
+ continue;
+ }
+
+ // If we have the beginning of a game, set the name of the game
+ else if (line.StartsWith("ROMs required for"))
+ {
+ gamename = Regex.Match(line, @"^ROMs required for \S*? ""(.*?)""\.").Groups[1].Value;
+ }
+
+ // If we have a machine with no required roms (usually internal devices), skip it
+ else if (line.StartsWith("No ROMs required for"))
+ {
+ continue;
+ }
+
+ // Otherwise, we assume we have a rom that we need to add
+ else
+ {
+ // First, we preprocess the line so that the rom name is consistently correct
+ string romname = "";
+ string[] split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+
+ // If the line doesn't have the 4 spaces of padding, check for 3
+ if (split.Length == 1)
+ {
+ split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+ }
+
+ // If the split is still unsuccessful, log it and skip
+ if (split.Length == 1)
+ {
+ Globals.Logger.Warning("Possibly malformed line: '{0}'", line);
+ }
+
+ romname = split[0];
+ line = line.Substring(romname.Length);
+
+ // Next we separate the ROM into pieces
+ split = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
+
+ // Standard Disks have 2 pieces (name, sha1)
+ if (split.Length == 1)
+ {
+ Disk disk = new Disk()
+ {
+ Name = romname,
+ SHA1 = Utilities.CleanListromHashData(split[0]),
+
+ MachineName = gamename,
+ };
+
+ ParseAddHelper(disk, clean, remUnicode);
+ }
+
+ // Baddump Disks have 4 pieces (name, BAD, sha1, BAD_DUMP)
+ else if (split.Length == 3 && line.EndsWith("BAD_DUMP"))
+ {
+ Disk disk = new Disk()
+ {
+ Name = romname,
+ SHA1 = Utilities.CleanListromHashData(split[1]),
+ ItemStatus = ItemStatus.BadDump,
+
+ MachineName = gamename,
+ };
+
+ ParseAddHelper(disk, clean, remUnicode);
+ }
+
+ // Standard ROMs have 4 pieces (name, size, crc, sha1)
+ else if (split.Length == 3)
+ {
+ if (!Int64.TryParse(split[0], out long size))
+ {
+ size = 0;
+ }
+
+ Rom rom = new Rom()
+ {
+ Name = romname,
+ Size = size,
+ CRC = Utilities.CleanListromHashData(split[1]),
+ SHA1 = Utilities.CleanListromHashData(split[2]),
+
+ MachineName = gamename,
+ };
+
+ ParseAddHelper(rom, clean, remUnicode);
+ }
+
+ // Nodump Disks have 5 pieces (name, NO, GOOD, DUMP, KNOWN)
+ else if (split.Length == 4 && line.EndsWith("NO GOOD DUMP KNOWN"))
+ {
+ Disk disk = new Disk()
+ {
+ Name = romname,
+ ItemStatus = ItemStatus.Nodump,
+
+ MachineName = gamename,
+ };
+
+ ParseAddHelper(disk, clean, remUnicode);
+ }
+
+ // Baddump ROMs have 6 pieces (name, size, BAD, crc, sha1, BAD_DUMP)
+ else if (split.Length == 5 && line.EndsWith("BAD_DUMP"))
+ {
+ if (!Int64.TryParse(split[0], out long size))
+ {
+ size = 0;
+ }
+
+ Rom rom = new Rom()
+ {
+ Name = romname,
+ Size = size,
+ CRC = Utilities.CleanListromHashData(split[2]),
+ SHA1 = Utilities.CleanListromHashData(split[3]),
+ ItemStatus = ItemStatus.BadDump,
+
+ MachineName = gamename,
+ };
+
+ ParseAddHelper(rom, clean, remUnicode);
+ }
+
+ // Nodump ROMs have 6 pieces (name, size, NO, GOOD, DUMP, KNOWN)
+ else if (split.Length == 5 && line.EndsWith("NO GOOD DUMP KNOWN"))
+ {
+ if (!Int64.TryParse(split[0], out long size))
+ {
+ size = 0;
+ }
+
+ Rom rom = new Rom()
+ {
+ Name = romname,
+ Size = size,
+ ItemStatus = ItemStatus.Nodump,
+
+ MachineName = gamename,
+ };
+
+ ParseAddHelper(rom, clean, remUnicode);
+ }
+
+ // If we have something else, it's invalid
+ else
+ {
+ Globals.Logger.Warning("Invalid line detected: '{0} {1}'", romname, line);
+ }
+ }
+ }
+ }
+
+
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
+
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
+
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+
+ // Write out each of the machines and roms
+ string lastgame = null;
+
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
+
+ foreach (string key in keys)
+ {
+ List roms = this[key];
+
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
+
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
+
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
+
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteEndGame(sw);
+ }
+
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteStartGame(sw, rom);
+ }
+
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+
+ rom.Name = (rom.Name == "null" ? "-" : rom.Name);
+ ((Rom)rom).Size = Constants.SizeZero;
+ ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
+ ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
+ ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
+ ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
+ ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
+ ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
+ }
+
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
+
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteStartGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
+
+ string state = "ROMs required for driver \"" + (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName : "") + "\".\n" +
+ "Name Size Checksum\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game end using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteEndGame(StreamWriter sw)
+ {
+ try
+ {
+ string state = "\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
+
+ try
+ {
+ string state = "";
+
+ // Pre-process the item name
+ ProcessItemName(rom, true);
+
+ switch (rom.ItemType)
+ {
+ case ItemType.Archive:
+ case ItemType.BiosSet:
+ case ItemType.Release:
+ case ItemType.Sample:
+ // We don't output these at all
+ break;
+ case ItemType.Disk:
+ // The name is padded out to a particular length
+ if (rom.Name.Length < 43)
+ {
+ state += rom.Name.PadRight(43, ' ');
+ }
+ else
+ {
+ state += rom.Name + " ";
+ }
+
+ // If we have a baddump, put the first indicator
+ if (!ExcludeFields[(int)Field.Status] && ((Disk)rom).ItemStatus == ItemStatus.BadDump)
+ {
+ state += " BAD";
+ }
+
+ // If we have a nodump, write out the indicator
+ if (!ExcludeFields[(int)Field.Status] && ((Disk)rom).ItemStatus == ItemStatus.Nodump)
+ {
+ state += " NO GOOD DUMP KNOWN";
+ }
+ // Otherwise, write out the SHA-1 hash
+ else if (!ExcludeFields[(int)Field.SHA1])
+ {
+ state += " SHA1(" + ((Disk)rom).SHA1 + ")";
+ }
+
+ // If we have a baddump, put the second indicator
+ if (!ExcludeFields[(int)Field.Status] && ((Disk)rom).ItemStatus == ItemStatus.BadDump)
+ {
+ state += " BAD_DUMP";
+ }
+
+ state += "\n";
+ break;
+ case ItemType.Rom:
+ // The name is padded out to a particular length
+ if (rom.Name.Length < 40)
+ {
+ state += rom.Name.PadRight(43 - (((Rom)rom).Size.ToString().Length), ' ');
+ }
+ else
+ {
+ state += rom.Name + " ";
+ }
+
+ // If we don't have a nodump, write out the size
+ if (((Rom)rom).ItemStatus != ItemStatus.Nodump)
+ {
+ state += ((Rom)rom).Size;
+ }
+
+ // If we have a baddump, put the first indicator
+ if (!ExcludeFields[(int)Field.Status] && ((Rom)rom).ItemStatus == ItemStatus.BadDump)
+ {
+ state += " BAD";
+ }
+
+ // If we have a nodump, write out the indicator
+ if (!ExcludeFields[(int)Field.Status] && ((Rom)rom).ItemStatus == ItemStatus.Nodump)
+ {
+ state += " NO GOOD DUMP KNOWN";
+ }
+ // Otherwise, write out the CRC and SHA-1 hashes
+ else
+ {
+ state += (!ExcludeFields[(int)Field.CRC] ? " CRC(" + ((Rom)rom).CRC + ")" : "");
+ state += (!ExcludeFields[(int)Field.SHA1] ? " SHA1(" + ((Rom)rom).SHA1 + ")" : "");
+ }
+
+ // If we have a baddump, put the second indicator
+ if (!ExcludeFields[(int)Field.Status] && ((Rom)rom).ItemStatus == ItemStatus.BadDump)
+ {
+ state += " BAD_DUMP";
+ }
+
+ state += "\n";
+ break;
+ }
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/Listxml.cs b/SabreTools.Library/DatFiles/Listxml.cs
index 0675d740..d10014a3 100644
--- a/SabreTools.Library/DatFiles/Listxml.cs
+++ b/SabreTools.Library/DatFiles/Listxml.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Xml;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -20,857 +19,857 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a MAME XML DAT
- ///
- /// TODO: Verify that all write for this DatFile type is correct
- internal class Listxml : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public Listxml(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
-
- ///
- /// Parse a MAME XML DAT 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
- /// 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,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Prepare all internal variables
- Encoding enc = Utilities.GetEncoding(filename);
- XmlReader xtr = Utilities.GetXmlTextReader(filename);
-
- // If we got a null reader, just return
- if (xtr == null)
- {
- return;
- }
-
- // Otherwise, read the file to the end
- try
- {
- xtr.MoveToContent();
- while (!xtr.EOF)
- {
- // We only want elements
- if (xtr.NodeType != XmlNodeType.Element)
- {
- xtr.Read();
- continue;
- }
-
- switch (xtr.Name)
- {
- case "mame":
- Name = (String.IsNullOrWhiteSpace(Name) ? xtr.GetAttribute("build") : Name);
- Description = (String.IsNullOrWhiteSpace(Description) ? Name : Name);
- // string mame_debug = xtr.GetAttribute("debug"); // (yes|no) "no"
- // string mame_mameconfig = xtr.GetAttribute("mameconfig"); CDATA
- 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);
- Version = (String.IsNullOrWhiteSpace(Version) ? xtr.GetAttribute("version") ?? "" : Version);
- xtr.Read();
- break;
- // We want to process the entire subtree of the machine
- case "game": // Some older DATs still use "game"
- case "machine":
- ReadMachine(xtr.ReadSubtree(), filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the machine now that we've processed it
- xtr.Skip();
- break;
- default:
- xtr.Read();
- break;
- }
- }
- }
- catch (Exception ex)
- {
- Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
-
- // For XML errors, just skip the affected node
- xtr?.Read();
- }
-
- xtr.Dispose();
- }
-
- ///
- /// Read machine information
- ///
- /// XmlReader representing a machine block
- /// 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 void ReadMachine(
- XmlReader reader,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // If we have an empty machine, skip it
- if (reader == null)
- {
- return;
- }
-
- // Otherwise, add what is possible
- reader.MoveToContent();
-
- string key = "";
- string temptype = reader.Name;
- bool containsItems = false;
-
- // Create a new machine
- MachineType machineType = MachineType.NULL;
- if (Utilities.GetYesNo(reader.GetAttribute("isbios")) == true)
- {
- machineType |= MachineType.Bios;
- }
- if (Utilities.GetYesNo(reader.GetAttribute("isdevice")) == true)
- {
- machineType |= MachineType.Device;
- }
- if (Utilities.GetYesNo(reader.GetAttribute("ismechanical")) == true)
- {
- machineType |= MachineType.Mechanical;
- }
-
- Machine machine = new Machine
- {
- Name = reader.GetAttribute("name"),
- Description = reader.GetAttribute("name"),
- SourceFile = reader.GetAttribute("sourcefile"),
- Runnable = Utilities.GetYesNo(reader.GetAttribute("runnable")),
-
- Comment = "",
-
- CloneOf = reader.GetAttribute("cloneof") ?? "",
- RomOf = reader.GetAttribute("romof") ?? "",
- SampleOf = reader.GetAttribute("sampleof") ?? "",
- Devices = new List(),
- SlotOptions = new List(),
-
- MachineType = (machineType == MachineType.NULL ? MachineType.None : machineType),
- };
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the roms from the machine
- switch (reader.Name)
- {
- case "description":
- machine.Description = reader.ReadElementContentAsString();
- break;
- case "year":
- machine.Year = reader.ReadElementContentAsString();
- break;
- case "manufacturer":
- machine.Manufacturer = reader.ReadElementContentAsString();
- break;
- case "biosset":
- containsItems = true;
-
- DatItem biosset = new BiosSet
- {
- Name = reader.GetAttribute("name"),
- Description = reader.GetAttribute("description"),
- Default = Utilities.GetYesNo(reader.GetAttribute("default")),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- biosset.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(biosset, clean, remUnicode);
-
- reader.Read();
- break;
- case "rom":
- containsItems = true;
-
- DatItem rom = new Rom
- {
- Name = reader.GetAttribute("name"),
- Bios = reader.GetAttribute("bios"),
- Size = Utilities.GetSize(reader.GetAttribute("size")),
- CRC = Utilities.CleanHashData(reader.GetAttribute("crc"), Constants.CRCLength),
- MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
- SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
- SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
- SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
- SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
- MergeTag = reader.GetAttribute("merge"),
- Region = reader.GetAttribute("region"),
- Offset = reader.GetAttribute("offset"),
- ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
- Optional = Utilities.GetYesNo(reader.GetAttribute("optional")),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- rom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(rom, clean, remUnicode);
-
- reader.Read();
- break;
- case "disk":
- containsItems = true;
-
- DatItem disk = new Disk
- {
- Name = reader.GetAttribute("name"),
- MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
- SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
- SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
- SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
- SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
- MergeTag = reader.GetAttribute("merge"),
- Region = reader.GetAttribute("region"),
- Index = reader.GetAttribute("index"),
- Writable = Utilities.GetYesNo(reader.GetAttribute("writable")),
- ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
- Optional = Utilities.GetYesNo(reader.GetAttribute("optional")),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- disk.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(disk, clean, remUnicode);
-
- reader.Read();
- break;
- case "device_ref":
- string device_ref_name = reader.GetAttribute("name");
- if (!machine.Devices.Contains(device_ref_name))
- {
- machine.Devices.Add(device_ref_name);
- }
-
- reader.Read();
- break;
- case "sample":
- containsItems = true;
-
- DatItem samplerom = new Sample
- {
- Name = reader.GetAttribute("name"),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- samplerom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(samplerom, clean, remUnicode);
-
- reader.Read();
- break;
- case "chip":
- // string chip_name = reader.GetAttribute("name");
- // string chip_tag = reader.GetAttribute("tag");
- // string chip_type = reader.GetAttribute("type"); // (cpu|audio)
- // string chip_clock = reader.GetAttribute("clock");
-
- reader.Read();
- break;
- case "display":
- // string display_tag = reader.GetAttribute("tag");
- // string display_type = reader.GetAttribute("type"); // (raster|vector|lcd|svg|unknown)
- // string display_rotate = reader.GetAttribute("rotate"); // (0|90|180|270)
- // bool? display_flipx = Utilities.GetYesNo(reader.GetAttribute("flipx"));
- // string display_width = reader.GetAttribute("width");
- // string display_height = reader.GetAttribute("height");
- // string display_refresh = reader.GetAttribute("refresh");
- // string display_pixclock = reader.GetAttribute("pixclock");
- // string display_htotal = reader.GetAttribute("htotal");
- // string display_hbend = reader.GetAttribute("hbend");
- // string display_hbstart = reader.GetAttribute("hbstart");
- // string display_vtotal = reader.GetAttribute("vtotal");
- // string display_vbend = reader.GetAttribute("vbend");
- // string display_vbstart = reader.GetAttribute("vbstart");
-
- reader.Read();
- break;
- case "sound":
- // string sound_channels = reader.GetAttribute("channels");
-
- reader.Read();
- break;
- case "condition":
- // string condition_tag = reader.GetAttribute("tag");
- // string condition_mask = reader.GetAttribute("mask");
- // string condition_relation = reader.GetAttribute("relation"); // (eq|ne|gt|le|lt|ge)
- // string condition_value = reader.GetAttribute("value");
-
- reader.Read();
- break;
- case "input":
- // bool? input_service = Utilities.GetYesNo(reader.GetAttribute("service"));
- // bool? input_tilt = Utilities.GetYesNo(reader.GetAttribute("tilt"));
- // string input_players = reader.GetAttribute("players");
- // string input_coins = reader.GetAttribute("coins");
-
- // // While the subtree contains elements...
- // string control_type = reader.GetAttribute("type");
- // string control_player = reader.GetAttribute("player");
- // string control_buttons = reader.GetAttribute("buttons");
- // string control_regbuttons = reader.GetAttribute("regbuttons");
- // string control_minimum = reader.GetAttribute("minimum");
- // string control_maximum = reader.GetAttribute("maximum");
- // string control_sensitivity = reader.GetAttribute("sensitivity");
- // string control_keydelta = reader.GetAttribute("keydelta");
- // bool? control_reverse = Utilities.GetYesNo(reader.GetAttribute("reverse"));
- // string control_ways = reader.GetAttribute("ways");
- // string control_ways2 = reader.GetAttribute("ways2");
- // string control_ways3 = reader.GetAttribute("ways3");
-
- reader.Skip();
- break;
- case "dipswitch":
- // string dipswitch_name = reader.GetAttribute("name");
- // string dipswitch_tag = reader.GetAttribute("tag");
- // string dipswitch_mask = reader.GetAttribute("mask");
-
- // // While the subtree contains elements...
- // string diplocation_name = reader.GetAttribute("name");
- // string diplocation_number = reader.GetAttribute("number");
- // bool? diplocation_inverted = Utilities.GetYesNo(reader.GetAttribute("inverted"));
-
- // // While the subtree contains elements...
- // string dipvalue_name = reader.GetAttribute("name");
- // string dipvalue_value = reader.GetAttribute("value");
- // bool? dipvalue_default = Utilities.GetYesNo(reader.GetAttribute("default"));
-
- reader.Skip();
- break;
- case "configuration":
- // string configuration_name = reader.GetAttribute("name");
- // string configuration_tag = reader.GetAttribute("tag");
- // string configuration_mask = reader.GetAttribute("mask");
-
- // // While the subtree contains elements...
- // string conflocation_name = reader.GetAttribute("name");
- // string conflocation_number = reader.GetAttribute("number");
- // bool? conflocation_inverted = Utilities.GetYesNo(reader.GetAttribute("inverted"));
-
- // // While the subtree contains elements...
- // string confsetting_name = reader.GetAttribute("name");
- // string confsetting_value = reader.GetAttribute("value");
- // bool? confsetting_default = Utilities.GetYesNo(reader.GetAttribute("default"));
-
- reader.Skip();
- break;
- case "port":
- // string port_tag = reader.GetAttribute("tag");
-
- // // While the subtree contains elements...
- // string analog_mask = reader.GetAttribute("mask");
-
- reader.Skip();
- break;
- case "adjuster":
- // string adjuster_name = reader.GetAttribute("name");
- // bool? adjuster_default = Utilities.GetYesNo(reader.GetAttribute("default"));
-
- // // For the one possible element...
- // string condition_tag = reader.GetAttribute("tag");
- // string condition_mask = reader.GetAttribute("mask");
- // string condition_relation = reader.GetAttribute("relation"); // (eq|ne|gt|le|lt|ge)
- // string condition_value = reader.GetAttribute("value");
-
- reader.Skip();
- break;
- case "driver":
- // string driver_status = reader.GetAttribute("status"); // (good|imperfect|preliminary)
- // string driver_emulation = reader.GetAttribute("emulation"); // (good|imperfect|preliminary)
- // string driver_cocktail = reader.GetAttribute("cocktail"); // (good|imperfect|preliminary)
- // string driver_savestate = reader.GetAttribute("savestate"); // (supported|unsupported)
-
- reader.Read();
- break;
- case "feature":
- // string feature_type = reader.GetAttribute("type"); // (protection|palette|graphics|sound|controls|keyboard|mouse|microphone|camera|disk|printer|lan|wan|timing)
- // string feature_status = reader.GetAttribute("status"); // (unemulated|imperfect)
- // string feature_overall = reader.GetAttribute("overall"); // (unemulated|imperfect)
-
- reader.Read();
- break;
- case "device":
- // string device_type = reader.GetAttribute("type");
- // string device_tag = reader.GetAttribute("tag");
- // string device_fixed_image = reader.GetAttribute("fixed_image");
- // string device_mandatory = reader.GetAttribute("mandatory");
- // string device_interface = reader.GetAttribute("interface");
-
- // // For the one possible element...
- // string instance_name = reader.GetAttribute("name");
- // string instance_briefname = reader.GetAttribute("briefname");
-
- // // While the subtree contains elements...
- // string extension_name = reader.GetAttribute("name");
-
- reader.Skip();
- break;
- case "slot":
- // string slot_name = reader.GetAttribute("name");
- ReadSlot(reader.ReadSubtree(), machine);
-
- // Skip the slot now that we've processed it
- reader.Skip();
- break;
- case "softwarelist":
- // string softwarelist_name = reader.GetAttribute("name");
- // string softwarelist_status = reader.GetAttribute("status"); // (original|compatible)
- // string softwarelist_filter = reader.GetAttribute("filter");
-
- reader.Read();
- break;
- case "ramoption":
- // string ramoption_default = reader.GetAttribute("default");
-
- reader.Read();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- // If no items were found for this machine, add a Blank placeholder
- if (!containsItems)
- {
- Blank blank = new Blank()
- {
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- blank.CopyMachineInformation(machine);
-
- // Now process and add the rom
- ParseAddHelper(blank, clean, remUnicode);
- }
- }
-
- ///
- /// Read slot information
- ///
- /// XmlReader representing a machine block
- /// Machine information to pass to contained items
- private void ReadSlot(XmlReader reader, Machine machine)
- {
- // If we have an empty machine, skip it
- if (reader == null)
- {
- return;
- }
-
- // Otherwise, add what is possible
- reader.MoveToContent();
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the roms from the machine
- switch (reader.Name)
- {
- case "slotoption":
- // string slotoption_name = reader.GetAttribute("name");
- string devname = reader.GetAttribute("devname");
- if (!machine.SlotOptions.Contains(devname))
- {
- machine.SlotOptions.Add(devname);
- }
- // bool? slotoption_default = Utilities.GetYesNo(reader.GetAttribute("default"));
- reader.Read();
- break;
- default:
- reader.Read();
- break;
- }
- }
- }
-
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
-
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
-
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
-
- // Write out the header
- WriteHeader(sw);
-
- // Write out each of the machines and roms
- string lastgame = null;
-
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
-
- foreach (string key in keys)
- {
- List roms = this[key];
-
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
-
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
-
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
-
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteEndGame(sw);
- }
-
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteStartGame(sw, rom);
- }
-
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
-
- lastgame = rom.MachineName;
- continue;
- }
-
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
-
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
-
- // Write the file footer out
- WriteFooter(sw);
-
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "\n" +
- "\n\n";
-
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteStartGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
-
- string state = "\t\n"
- + (!ExcludeFields[(int)Field.Description] ? "\t\t" + HttpUtility.HtmlEncode(rom.MachineDescription) + "\n" : "")
- + (!ExcludeFields[(int)Field.Year] && rom.Year != null ? "\t\t" + HttpUtility.HtmlEncode(rom.Year) + "\n" : "")
- + (!ExcludeFields[(int)Field.Publisher] && rom.Publisher != null ? "\t\t" + HttpUtility.HtmlEncode(rom.Publisher) + "\n" : "");
-
- if (!ExcludeFields[(int)Field.Infos] && rom.Infos != null && rom.Infos.Count > 0)
- {
- foreach (Tuple kvp in rom.Infos)
- {
- state += "\t\t\n";
- }
- }
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteEndGame(StreamWriter sw)
- {
- try
- {
- string state = "\t\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
-
- try
- {
- string state = "";
-
- // Pre-process the item name
- ProcessItemName(rom, true);
-
- switch (rom.ItemType)
- {
- case ItemType.Archive:
- break;
- case ItemType.BiosSet: // TODO: Separate out MachineDescription from Description
- state += "\t\t\n";
- break;
- case ItemType.Disk:
- state += "\t\t\n";
- break;
- case ItemType.Release:
- //TODO: Am I missing this?
- break;
- case ItemType.Rom:
- state += "\t\t\n";
- break;
- case ItemType.Sample:
- state += "\t\t\n";
- break;
- }
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT footer using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteFooter(StreamWriter sw)
- {
- try
- {
- string footer = "\t\n\n";
-
- // Write the footer out
- sw.Write(footer);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
- }
+ ///
+ /// Represents parsing and writing of a MAME XML DAT
+ ///
+ /// TODO: Verify that all write for this DatFile type is correct
+ internal class Listxml : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public Listxml(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
+
+ ///
+ /// Parse a MAME XML DAT 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
+ /// 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,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Prepare all internal variables
+ Encoding enc = Utilities.GetEncoding(filename);
+ XmlReader xtr = Utilities.GetXmlTextReader(filename);
+
+ // If we got a null reader, just return
+ if (xtr == null)
+ {
+ return;
+ }
+
+ // Otherwise, read the file to the end
+ try
+ {
+ xtr.MoveToContent();
+ while (!xtr.EOF)
+ {
+ // We only want elements
+ if (xtr.NodeType != XmlNodeType.Element)
+ {
+ xtr.Read();
+ continue;
+ }
+
+ switch (xtr.Name)
+ {
+ case "mame":
+ Name = (String.IsNullOrWhiteSpace(Name) ? xtr.GetAttribute("build") : Name);
+ Description = (String.IsNullOrWhiteSpace(Description) ? Name : Name);
+ // string mame_debug = xtr.GetAttribute("debug"); // (yes|no) "no"
+ // string mame_mameconfig = xtr.GetAttribute("mameconfig"); CDATA
+ 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);
+ Version = (String.IsNullOrWhiteSpace(Version) ? xtr.GetAttribute("version") ?? "" : Version);
+ xtr.Read();
+ break;
+ // We want to process the entire subtree of the machine
+ case "game": // Some older DATs still use "game"
+ case "machine":
+ ReadMachine(xtr.ReadSubtree(), filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the machine now that we've processed it
+ xtr.Skip();
+ break;
+ default:
+ xtr.Read();
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
+
+ // For XML errors, just skip the affected node
+ xtr?.Read();
+ }
+
+ xtr.Dispose();
+ }
+
+ ///
+ /// Read machine information
+ ///
+ /// XmlReader representing a machine block
+ /// 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 void ReadMachine(
+ XmlReader reader,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // If we have an empty machine, skip it
+ if (reader == null)
+ {
+ return;
+ }
+
+ // Otherwise, add what is possible
+ reader.MoveToContent();
+
+ string key = "";
+ string temptype = reader.Name;
+ bool containsItems = false;
+
+ // Create a new machine
+ MachineType machineType = MachineType.NULL;
+ if (Utilities.GetYesNo(reader.GetAttribute("isbios")) == true)
+ {
+ machineType |= MachineType.Bios;
+ }
+ if (Utilities.GetYesNo(reader.GetAttribute("isdevice")) == true)
+ {
+ machineType |= MachineType.Device;
+ }
+ if (Utilities.GetYesNo(reader.GetAttribute("ismechanical")) == true)
+ {
+ machineType |= MachineType.Mechanical;
+ }
+
+ Machine machine = new Machine
+ {
+ Name = reader.GetAttribute("name"),
+ Description = reader.GetAttribute("name"),
+ SourceFile = reader.GetAttribute("sourcefile"),
+ Runnable = Utilities.GetYesNo(reader.GetAttribute("runnable")),
+
+ Comment = "",
+
+ CloneOf = reader.GetAttribute("cloneof") ?? "",
+ RomOf = reader.GetAttribute("romof") ?? "",
+ SampleOf = reader.GetAttribute("sampleof") ?? "",
+ Devices = new List(),
+ SlotOptions = new List(),
+
+ MachineType = (machineType == MachineType.NULL ? MachineType.None : machineType),
+ };
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the roms from the machine
+ switch (reader.Name)
+ {
+ case "description":
+ machine.Description = reader.ReadElementContentAsString();
+ break;
+ case "year":
+ machine.Year = reader.ReadElementContentAsString();
+ break;
+ case "manufacturer":
+ machine.Manufacturer = reader.ReadElementContentAsString();
+ break;
+ case "biosset":
+ containsItems = true;
+
+ DatItem biosset = new BiosSet
+ {
+ Name = reader.GetAttribute("name"),
+ Description = reader.GetAttribute("description"),
+ Default = Utilities.GetYesNo(reader.GetAttribute("default")),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ biosset.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(biosset, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "rom":
+ containsItems = true;
+
+ DatItem rom = new Rom
+ {
+ Name = reader.GetAttribute("name"),
+ Bios = reader.GetAttribute("bios"),
+ Size = Utilities.GetSize(reader.GetAttribute("size")),
+ CRC = Utilities.CleanHashData(reader.GetAttribute("crc"), Constants.CRCLength),
+ MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
+ SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
+ SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
+ SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
+ SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
+ MergeTag = reader.GetAttribute("merge"),
+ Region = reader.GetAttribute("region"),
+ Offset = reader.GetAttribute("offset"),
+ ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
+ Optional = Utilities.GetYesNo(reader.GetAttribute("optional")),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ rom.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(rom, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "disk":
+ containsItems = true;
+
+ DatItem disk = new Disk
+ {
+ Name = reader.GetAttribute("name"),
+ MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
+ SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
+ SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
+ SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
+ SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
+ MergeTag = reader.GetAttribute("merge"),
+ Region = reader.GetAttribute("region"),
+ Index = reader.GetAttribute("index"),
+ Writable = Utilities.GetYesNo(reader.GetAttribute("writable")),
+ ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
+ Optional = Utilities.GetYesNo(reader.GetAttribute("optional")),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ disk.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(disk, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "device_ref":
+ string device_ref_name = reader.GetAttribute("name");
+ if (!machine.Devices.Contains(device_ref_name))
+ {
+ machine.Devices.Add(device_ref_name);
+ }
+
+ reader.Read();
+ break;
+ case "sample":
+ containsItems = true;
+
+ DatItem samplerom = new Sample
+ {
+ Name = reader.GetAttribute("name"),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ samplerom.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(samplerom, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "chip":
+ // string chip_name = reader.GetAttribute("name");
+ // string chip_tag = reader.GetAttribute("tag");
+ // string chip_type = reader.GetAttribute("type"); // (cpu|audio)
+ // string chip_clock = reader.GetAttribute("clock");
+
+ reader.Read();
+ break;
+ case "display":
+ // string display_tag = reader.GetAttribute("tag");
+ // string display_type = reader.GetAttribute("type"); // (raster|vector|lcd|svg|unknown)
+ // string display_rotate = reader.GetAttribute("rotate"); // (0|90|180|270)
+ // bool? display_flipx = Utilities.GetYesNo(reader.GetAttribute("flipx"));
+ // string display_width = reader.GetAttribute("width");
+ // string display_height = reader.GetAttribute("height");
+ // string display_refresh = reader.GetAttribute("refresh");
+ // string display_pixclock = reader.GetAttribute("pixclock");
+ // string display_htotal = reader.GetAttribute("htotal");
+ // string display_hbend = reader.GetAttribute("hbend");
+ // string display_hbstart = reader.GetAttribute("hbstart");
+ // string display_vtotal = reader.GetAttribute("vtotal");
+ // string display_vbend = reader.GetAttribute("vbend");
+ // string display_vbstart = reader.GetAttribute("vbstart");
+
+ reader.Read();
+ break;
+ case "sound":
+ // string sound_channels = reader.GetAttribute("channels");
+
+ reader.Read();
+ break;
+ case "condition":
+ // string condition_tag = reader.GetAttribute("tag");
+ // string condition_mask = reader.GetAttribute("mask");
+ // string condition_relation = reader.GetAttribute("relation"); // (eq|ne|gt|le|lt|ge)
+ // string condition_value = reader.GetAttribute("value");
+
+ reader.Read();
+ break;
+ case "input":
+ // bool? input_service = Utilities.GetYesNo(reader.GetAttribute("service"));
+ // bool? input_tilt = Utilities.GetYesNo(reader.GetAttribute("tilt"));
+ // string input_players = reader.GetAttribute("players");
+ // string input_coins = reader.GetAttribute("coins");
+
+ // // While the subtree contains elements...
+ // string control_type = reader.GetAttribute("type");
+ // string control_player = reader.GetAttribute("player");
+ // string control_buttons = reader.GetAttribute("buttons");
+ // string control_regbuttons = reader.GetAttribute("regbuttons");
+ // string control_minimum = reader.GetAttribute("minimum");
+ // string control_maximum = reader.GetAttribute("maximum");
+ // string control_sensitivity = reader.GetAttribute("sensitivity");
+ // string control_keydelta = reader.GetAttribute("keydelta");
+ // bool? control_reverse = Utilities.GetYesNo(reader.GetAttribute("reverse"));
+ // string control_ways = reader.GetAttribute("ways");
+ // string control_ways2 = reader.GetAttribute("ways2");
+ // string control_ways3 = reader.GetAttribute("ways3");
+
+ reader.Skip();
+ break;
+ case "dipswitch":
+ // string dipswitch_name = reader.GetAttribute("name");
+ // string dipswitch_tag = reader.GetAttribute("tag");
+ // string dipswitch_mask = reader.GetAttribute("mask");
+
+ // // While the subtree contains elements...
+ // string diplocation_name = reader.GetAttribute("name");
+ // string diplocation_number = reader.GetAttribute("number");
+ // bool? diplocation_inverted = Utilities.GetYesNo(reader.GetAttribute("inverted"));
+
+ // // While the subtree contains elements...
+ // string dipvalue_name = reader.GetAttribute("name");
+ // string dipvalue_value = reader.GetAttribute("value");
+ // bool? dipvalue_default = Utilities.GetYesNo(reader.GetAttribute("default"));
+
+ reader.Skip();
+ break;
+ case "configuration":
+ // string configuration_name = reader.GetAttribute("name");
+ // string configuration_tag = reader.GetAttribute("tag");
+ // string configuration_mask = reader.GetAttribute("mask");
+
+ // // While the subtree contains elements...
+ // string conflocation_name = reader.GetAttribute("name");
+ // string conflocation_number = reader.GetAttribute("number");
+ // bool? conflocation_inverted = Utilities.GetYesNo(reader.GetAttribute("inverted"));
+
+ // // While the subtree contains elements...
+ // string confsetting_name = reader.GetAttribute("name");
+ // string confsetting_value = reader.GetAttribute("value");
+ // bool? confsetting_default = Utilities.GetYesNo(reader.GetAttribute("default"));
+
+ reader.Skip();
+ break;
+ case "port":
+ // string port_tag = reader.GetAttribute("tag");
+
+ // // While the subtree contains elements...
+ // string analog_mask = reader.GetAttribute("mask");
+
+ reader.Skip();
+ break;
+ case "adjuster":
+ // string adjuster_name = reader.GetAttribute("name");
+ // bool? adjuster_default = Utilities.GetYesNo(reader.GetAttribute("default"));
+
+ // // For the one possible element...
+ // string condition_tag = reader.GetAttribute("tag");
+ // string condition_mask = reader.GetAttribute("mask");
+ // string condition_relation = reader.GetAttribute("relation"); // (eq|ne|gt|le|lt|ge)
+ // string condition_value = reader.GetAttribute("value");
+
+ reader.Skip();
+ break;
+ case "driver":
+ // string driver_status = reader.GetAttribute("status"); // (good|imperfect|preliminary)
+ // string driver_emulation = reader.GetAttribute("emulation"); // (good|imperfect|preliminary)
+ // string driver_cocktail = reader.GetAttribute("cocktail"); // (good|imperfect|preliminary)
+ // string driver_savestate = reader.GetAttribute("savestate"); // (supported|unsupported)
+
+ reader.Read();
+ break;
+ case "feature":
+ // string feature_type = reader.GetAttribute("type"); // (protection|palette|graphics|sound|controls|keyboard|mouse|microphone|camera|disk|printer|lan|wan|timing)
+ // string feature_status = reader.GetAttribute("status"); // (unemulated|imperfect)
+ // string feature_overall = reader.GetAttribute("overall"); // (unemulated|imperfect)
+
+ reader.Read();
+ break;
+ case "device":
+ // string device_type = reader.GetAttribute("type");
+ // string device_tag = reader.GetAttribute("tag");
+ // string device_fixed_image = reader.GetAttribute("fixed_image");
+ // string device_mandatory = reader.GetAttribute("mandatory");
+ // string device_interface = reader.GetAttribute("interface");
+
+ // // For the one possible element...
+ // string instance_name = reader.GetAttribute("name");
+ // string instance_briefname = reader.GetAttribute("briefname");
+
+ // // While the subtree contains elements...
+ // string extension_name = reader.GetAttribute("name");
+
+ reader.Skip();
+ break;
+ case "slot":
+ // string slot_name = reader.GetAttribute("name");
+ ReadSlot(reader.ReadSubtree(), machine);
+
+ // Skip the slot now that we've processed it
+ reader.Skip();
+ break;
+ case "softwarelist":
+ // string softwarelist_name = reader.GetAttribute("name");
+ // string softwarelist_status = reader.GetAttribute("status"); // (original|compatible)
+ // string softwarelist_filter = reader.GetAttribute("filter");
+
+ reader.Read();
+ break;
+ case "ramoption":
+ // string ramoption_default = reader.GetAttribute("default");
+
+ reader.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ // If no items were found for this machine, add a Blank placeholder
+ if (!containsItems)
+ {
+ Blank blank = new Blank()
+ {
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ blank.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ ParseAddHelper(blank, clean, remUnicode);
+ }
+ }
+
+ ///
+ /// Read slot information
+ ///
+ /// XmlReader representing a machine block
+ /// Machine information to pass to contained items
+ private void ReadSlot(XmlReader reader, Machine machine)
+ {
+ // If we have an empty machine, skip it
+ if (reader == null)
+ {
+ return;
+ }
+
+ // Otherwise, add what is possible
+ reader.MoveToContent();
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the roms from the machine
+ switch (reader.Name)
+ {
+ case "slotoption":
+ // string slotoption_name = reader.GetAttribute("name");
+ string devname = reader.GetAttribute("devname");
+ if (!machine.SlotOptions.Contains(devname))
+ {
+ machine.SlotOptions.Add(devname);
+ }
+ // bool? slotoption_default = Utilities.GetYesNo(reader.GetAttribute("default"));
+ reader.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
+
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
+
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+
+ // Write out the header
+ WriteHeader(sw);
+
+ // Write out each of the machines and roms
+ string lastgame = null;
+
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
+
+ foreach (string key in keys)
+ {
+ List roms = this[key];
+
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
+
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
+
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
+
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteEndGame(sw);
+ }
+
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteStartGame(sw, rom);
+ }
+
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+
+ lastgame = rom.MachineName;
+ continue;
+ }
+
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
+
+ // Write the file footer out
+ WriteFooter(sw);
+
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "\n" +
+ "\n\n";
+
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteStartGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
+
+ string state = "\t\n"
+ + (!ExcludeFields[(int)Field.Description] ? "\t\t" + HttpUtility.HtmlEncode(rom.MachineDescription) + "\n" : "")
+ + (!ExcludeFields[(int)Field.Year] && rom.Year != null ? "\t\t" + HttpUtility.HtmlEncode(rom.Year) + "\n" : "")
+ + (!ExcludeFields[(int)Field.Publisher] && rom.Publisher != null ? "\t\t" + HttpUtility.HtmlEncode(rom.Publisher) + "\n" : "");
+
+ if (!ExcludeFields[(int)Field.Infos] && rom.Infos != null && rom.Infos.Count > 0)
+ {
+ foreach (Tuple kvp in rom.Infos)
+ {
+ state += "\t\t\n";
+ }
+ }
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteEndGame(StreamWriter sw)
+ {
+ try
+ {
+ string state = "\t\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
+
+ try
+ {
+ string state = "";
+
+ // Pre-process the item name
+ ProcessItemName(rom, true);
+
+ switch (rom.ItemType)
+ {
+ case ItemType.Archive:
+ break;
+ case ItemType.BiosSet: // TODO: Separate out MachineDescription from Description
+ state += "\t\t\n";
+ break;
+ case ItemType.Disk:
+ state += "\t\t\n";
+ break;
+ case ItemType.Release:
+ //TODO: Am I missing this?
+ break;
+ case ItemType.Rom:
+ state += "\t\t\n";
+ break;
+ case ItemType.Sample:
+ state += "\t\t\n";
+ break;
+ }
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT footer using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteFooter(StreamWriter sw)
+ {
+ try
+ {
+ string footer = "\t\n\n";
+
+ // Write the footer out
+ sw.Write(footer);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/Logiqx.cs b/SabreTools.Library/DatFiles/Logiqx.cs
index dde0801b..39de4829 100644
--- a/SabreTools.Library/DatFiles/Logiqx.cs
+++ b/SabreTools.Library/DatFiles/Logiqx.cs
@@ -5,7 +5,6 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -22,963 +21,963 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a Logiqx-derived DAT
- ///
- /// TODO: Add XSD validation for all XML DAT types (maybe?)
- /// TODO: Verify that all write for this DatFile type is correct
- internal class Logiqx : DatFile
- {
- // Private instance variables specific to Logiqx DATs
- bool _depreciated;
-
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- /// True if the output uses "game", false if the output uses "machine"
- public Logiqx(DatFile datFile, bool depreciated)
- : base(datFile, cloneHeader: false)
- {
- _depreciated = depreciated;
- }
-
- ///
- /// Parse a Logiqx XML DAT 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
- /// 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,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Prepare all internal variables
- Encoding enc = Utilities.GetEncoding(filename);
- XmlReader xtr = Utilities.GetXmlTextReader(filename);
- List dirs = new List();
-
- // If we got a null reader, just return
- if (xtr == null)
- {
- return;
- }
-
- // Otherwise, read the file to the end
- try
- {
- xtr.MoveToContent();
- while (!xtr.EOF)
- {
- // We only want elements
- if (xtr.NodeType != XmlNodeType.Element)
- {
- // If we're ending a dir, remove the last item from the dirs list, if possible
- if (xtr.Name == "dir" && dirs.Count > 0)
- {
- dirs.RemoveAt(dirs.Count - 1);
- }
-
- xtr.Read();
- continue;
- }
-
- switch (xtr.Name)
- {
- // The datafile tag can have some attributes
- case "datafile":
- // string build = xtr.GetAttribute("build");
- // string debug = xtr.GetAttribute("debug"); // (yes|no) "no"
- xtr.Read();
- break;
- // We want to process the entire subtree of the header
- case "header":
- ReadHeader(xtr.ReadSubtree(), keep);
-
- // Skip the header node now that we've processed it
- xtr.Skip();
- break;
- // Unique to RomVault-created DATs
- case "dir":
- Type = "SuperDAT";
- dirs.Add(xtr.GetAttribute("name") ?? "");
- xtr.Read();
- break;
- // We want to process the entire subtree of the game
- case "machine": // New-style Logiqx
- case "game": // Old-style Logiqx
- ReadMachine(xtr.ReadSubtree(), dirs, filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the machine now that we've processed it
- xtr.Skip();
- break;
- default:
- xtr.Read();
- break;
- }
- }
- }
- catch (Exception ex)
- {
- Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
-
- // For XML errors, just skip the affected node
- xtr?.Read();
- }
-
- 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, add what is possible
- reader.MoveToContent();
-
- 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": // This is exclusive to TruRip XML
- 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);
- break;
- case "email":
- content = reader.ReadElementContentAsString();
- Email = (String.IsNullOrWhiteSpace(Email) ? content : Email);
- break;
- case "homepage":
- content = reader.ReadElementContentAsString();
- Homepage = (String.IsNullOrWhiteSpace(Homepage) ? content : Homepage);
- break;
- case "url":
- content = reader.ReadElementContentAsString();
- Url = (String.IsNullOrWhiteSpace(Url) ? content : Url);
- break;
- case "comment":
- content = reader.ReadElementContentAsString();
- Comment = (String.IsNullOrWhiteSpace(Comment) ? content : Comment);
- break;
- case "type": // This is exclusive to TruRip XML
- content = reader.ReadElementContentAsString();
- Type = (String.IsNullOrWhiteSpace(Type) ? content : Type);
- superdat = superdat || content.Contains("SuperDAT");
- break;
- case "clrmamepro":
- if (String.IsNullOrWhiteSpace(Header))
- {
- Header = reader.GetAttribute("header");
- }
- if (ForceMerging == ForceMerging.None)
- {
- ForceMerging = Utilities.GetForceMerging(reader.GetAttribute("forcemerging"));
- }
- if (ForceNodump == ForceNodump.None)
- {
- ForceNodump = Utilities.GetForceNodump(reader.GetAttribute("forcenodump"));
- }
- if (ForcePacking == ForcePacking.None)
- {
- ForcePacking = Utilities.GetForcePacking(reader.GetAttribute("forcepacking"));
- }
- reader.Read();
- break;
- case "romcenter":
- if (reader.GetAttribute("plugin") != null)
- {
- // CDATA
- }
- if (reader.GetAttribute("rommode") != null)
- {
- // (merged|split|unmerged) "split"
- }
- if (reader.GetAttribute("biosmode") != null)
- {
- // merged|split|unmerged) "split"
- }
- if (reader.GetAttribute("samplemode") != null)
- {
- // (merged|unmerged) "merged"
- }
- if (reader.GetAttribute("lockrommode") != null)
- {
- // (yes|no) "no"
- }
- if (reader.GetAttribute("lockbiosmode") != null)
- {
- // (yes|no) "no"
- }
- if (reader.GetAttribute("locksamplemode") != null)
- {
- // (yes|no) "no"
- }
- reader.Read();
- break;
- default:
- reader.Read();
- break;
- }
- }
- }
-
- ///
- /// Read game/machine information
- ///
- /// XmlReader to use to parse the machine
- /// List of dirs to prepend to the game name
- /// 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 void ReadMachine(
- XmlReader reader,
- List dirs,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // If we have an empty machine, skip it
- if (reader == null)
- {
- return;
- }
-
- // Otherwise, add what is possible
- reader.MoveToContent();
-
- string key = "";
- string temptype = reader.Name;
- bool containsItems = false;
-
- // Create a new machine
- MachineType machineType = MachineType.NULL;
- if (Utilities.GetYesNo(reader.GetAttribute("isbios")) == true)
- {
- machineType |= MachineType.Bios;
- }
- if (Utilities.GetYesNo(reader.GetAttribute("isdevice")) == true) // Listxml-specific, used by older DATs
- {
- machineType |= MachineType.Device;
- }
- if (Utilities.GetYesNo(reader.GetAttribute("ismechanical")) == true) // Listxml-specific, used by older DATs
- {
- machineType |= MachineType.Mechanical;
- }
-
- string dirsString = (dirs != null && dirs.Count() > 0 ? string.Join("/", dirs) + "/" : "");
- Machine machine = new Machine
- {
- Name = dirsString + reader.GetAttribute("name"),
- Description = dirsString + reader.GetAttribute("name"),
- SourceFile = reader.GetAttribute("sourcefile"),
- Board = reader.GetAttribute("board"),
- RebuildTo = reader.GetAttribute("rebuildto"),
- Runnable = Utilities.GetYesNo(reader.GetAttribute("runnable")), // Listxml-specific, used by older DATs
-
- Comment = "",
-
- CloneOf = reader.GetAttribute("cloneof") ?? "",
- RomOf = reader.GetAttribute("romof") ?? "",
- SampleOf = reader.GetAttribute("sampleof") ?? "",
-
- MachineType = (machineType == MachineType.NULL ? MachineType.None : machineType),
- };
-
- if (Type == "SuperDAT" && !keep)
- {
- string tempout = Regex.Match(machine.Name, @".*?\\(.*)").Groups[1].Value;
- if (!String.IsNullOrWhiteSpace(tempout))
- {
- machine.Name = tempout;
- }
- }
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the roms from the machine
- switch (reader.Name)
- {
- case "comment": // There can be multiple comments by spec
- machine.Comment += reader.ReadElementContentAsString();
- break;
- case "description":
- machine.Description = reader.ReadElementContentAsString();
- break;
- case "year":
- machine.Year = reader.ReadElementContentAsString();
- break;
- case "manufacturer":
- machine.Manufacturer = reader.ReadElementContentAsString();
- break;
- case "publisher": // Not technically supported but used by some legacy DATs
- machine.Publisher = reader.ReadElementContentAsString();
- break;
- case "trurip": // This is special metadata unique to TruRip
- ReadTruRip(reader.ReadSubtree(), machine);
-
- // Skip the trurip node now that we've processed it
- reader.Skip();
- break;
- case "release":
- containsItems = true;
-
- DatItem release = new Release
- {
- Name = reader.GetAttribute("name"),
- Region = reader.GetAttribute("region"),
- Language = reader.GetAttribute("language"),
- Date = reader.GetAttribute("date"),
- Default = Utilities.GetYesNo(reader.GetAttribute("default")),
- };
-
- release.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(release, clean, remUnicode);
-
- reader.Read();
- break;
- case "biosset":
- containsItems = true;
-
- DatItem biosset = new BiosSet
- {
- Name = reader.GetAttribute("name"),
- Description = reader.GetAttribute("description"),
- Default = Utilities.GetYesNo(reader.GetAttribute("default")),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- biosset.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(biosset, clean, remUnicode);
-
- reader.Read();
- break;
- case "rom":
- containsItems = true;
-
- DatItem rom = new Rom
- {
- Name = reader.GetAttribute("name"),
- Size = Utilities.GetSize(reader.GetAttribute("size")),
- CRC = Utilities.CleanHashData(reader.GetAttribute("crc"), Constants.CRCLength),
- MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
- SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
- SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
- SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
- SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
- MergeTag = reader.GetAttribute("merge"),
- ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
- Date = Utilities.GetDate(reader.GetAttribute("date")),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- rom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(rom, clean, remUnicode);
-
- reader.Read();
- break;
- case "disk":
- containsItems = true;
-
- DatItem disk = new Disk
- {
- Name = reader.GetAttribute("name"),
- MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
- SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
- SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
- SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
- SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
- MergeTag = reader.GetAttribute("merge"),
- ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- disk.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(disk, clean, remUnicode);
-
- reader.Read();
- break;
- case "sample":
- containsItems = true;
-
- DatItem samplerom = new Sample
- {
- Name = reader.GetAttribute("name"),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- samplerom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(samplerom, clean, remUnicode);
-
- reader.Read();
- break;
- case "archive":
- containsItems = true;
-
- DatItem archiverom = new Archive
- {
- Name = reader.GetAttribute("name"),
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- archiverom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(archiverom, clean, remUnicode);
-
- reader.Read();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- // If no items were found for this machine, add a Blank placeholder
- if (!containsItems)
- {
- Blank blank = new Blank()
- {
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- blank.CopyMachineInformation(machine);
-
- // Now process and add the rom
- ParseAddHelper(blank, clean, remUnicode);
- }
- }
-
- ///
- /// Read TruRip information
- ///
- /// True if full pathnames are to be kept, false otherwise (default)
- /// Machine information to pass to contained items
- private void ReadTruRip(XmlReader reader, Machine machine)
- {
- // If we have an empty trurip, skip it
- if (reader == null)
- {
- return;
- }
-
- // Otherwise, add what is possible
- reader.MoveToContent();
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the information from the trurip
- string content = "";
- switch (reader.Name)
- {
- case "titleid":
- content = reader.ReadElementContentAsString();
- // string titleid = content;
- break;
- case "publisher":
- machine.Publisher = reader.ReadElementContentAsString();
- break;
- case "developer": // Manufacturer is as close as this gets
- machine.Manufacturer = reader.ReadElementContentAsString();
- break;
- case "year":
- machine.Year = reader.ReadElementContentAsString();
- break;
- case "genre":
- content = reader.ReadElementContentAsString();
- // string genre = content;
- break;
- case "subgenre":
- content = reader.ReadElementContentAsString();
- // string subgenre = content;
- break;
- case "ratings":
- content = reader.ReadElementContentAsString();
- // string ratings = content;
- break;
- case "score":
- content = reader.ReadElementContentAsString();
- // string score = content;
- break;
- case "players":
- content = reader.ReadElementContentAsString();
- // string players = content;
- break;
- case "enabled":
- content = reader.ReadElementContentAsString();
- // string enabled = content;
- break;
- case "crc":
- content = reader.ReadElementContentAsString();
- // string crc = Utilities.GetYesNo(content);
- break;
- case "source":
- machine.SourceFile = reader.ReadElementContentAsString();
- break;
- case "cloneof":
- machine.CloneOf = reader.ReadElementContentAsString();
- break;
- case "relatedto":
- content = reader.ReadElementContentAsString();
- // string relatedto = content;
- break;
- default:
- reader.Read();
- break;
- }
- }
- }
-
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
-
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
-
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
-
- // Write out the header
- WriteHeader(sw);
-
- // Write out each of the machines and roms
- string lastgame = null;
-
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
-
- foreach (string key in keys)
- {
- List roms = this[key];
-
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
-
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
-
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
-
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteEndGame(sw);
- }
-
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteStartGame(sw, rom);
- }
-
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
-
- rom.Name = (rom.Name == "null" ? "-" : rom.Name);
- ((Rom)rom).Size = Constants.SizeZero;
- ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
- ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
- ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
- ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
- ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
- ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
- }
-
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
-
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
-
- // Write the file footer out
- WriteFooter(sw);
-
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "\n" +
- "\n\n" +
- "\n" +
- "\t\n" +
- "\t\t" + HttpUtility.HtmlEncode(Name) + "\n" +
- "\t\t" + HttpUtility.HtmlEncode(Description) + "\n" +
- (!String.IsNullOrWhiteSpace(RootDir) ? "\t\t" + HttpUtility.HtmlEncode(RootDir) + "\n" : "") +
- (!String.IsNullOrWhiteSpace(Category) ? "\t\t" + HttpUtility.HtmlEncode(Category) + "\n" : "") +
- "\t\t" + HttpUtility.HtmlEncode(Version) + "\n" +
- (!String.IsNullOrWhiteSpace(Date) ? "\t\t" + HttpUtility.HtmlEncode(Date) + "\n" : "") +
- "\t\t" + HttpUtility.HtmlEncode(Author) + "\n" +
- (!String.IsNullOrWhiteSpace(Email) ? "\t\t" + HttpUtility.HtmlEncode(Email) + "\n" : "") +
- (!String.IsNullOrWhiteSpace(Homepage) ? "\t\t" + HttpUtility.HtmlEncode(Homepage) + "\n" : "") +
- (!String.IsNullOrWhiteSpace(Url) ? "\t\t" + HttpUtility.HtmlEncode(Url) + "\n" : "") +
- (!String.IsNullOrWhiteSpace(Comment) ? "\t\t" + HttpUtility.HtmlEncode(Comment) + "\n" : "") +
- (!String.IsNullOrWhiteSpace(Type) ? "\t\t" + HttpUtility.HtmlEncode(Type) + "\n" : "") +
- (ForcePacking != ForcePacking.None || ForceMerging != ForceMerging.None || ForceNodump != ForceNodump.None || !String.IsNullOrWhiteSpace(Header) ?
- "\t\t\n"
- : "") +
- "\t\n";
-
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteStartGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
-
- string state = "\t<" + (_depreciated ? "game" : "machine") + " name=\"" + (!ExcludeFields[(int)Field.MachineName] ? HttpUtility.HtmlEncode(rom.MachineName) : "") + "\""
- + (!ExcludeFields[(int)Field.MachineType] && (rom.MachineType & MachineType.Bios) != 0 ? " isbios=\"yes\"" : "")
- + (!ExcludeFields[(int)Field.MachineType] && (rom.MachineType & MachineType.Device) != 0 ? " isdevice=\"yes\"" : "")
- + (!ExcludeFields[(int)Field.MachineType] && (rom.MachineType & MachineType.Mechanical) != 0 ? " ismechanical=\"yes\"" : "")
- + (!ExcludeFields[(int)Field.Runnable] && rom.Runnable == true
- ? " runnable=\"yes\""
- : (!ExcludeFields[(int)Field.Runnable] && rom.Runnable == false ? " runnable=\"no\"" : ""))
- + (!ExcludeFields[(int)Field.CloneOf] && !String.IsNullOrWhiteSpace(rom.CloneOf) && (rom.MachineName.ToLowerInvariant() != rom.CloneOf.ToLowerInvariant())
- ? " cloneof=\"" + HttpUtility.HtmlEncode(rom.CloneOf) + "\""
- : "")
- + (!ExcludeFields[(int)Field.RomOf] && !String.IsNullOrWhiteSpace(rom.RomOf) && (rom.MachineName.ToLowerInvariant() != rom.RomOf.ToLowerInvariant())
- ? " romof=\"" + HttpUtility.HtmlEncode(rom.RomOf) + "\""
- : "")
- + (!ExcludeFields[(int)Field.SampleOf] && !String.IsNullOrWhiteSpace(rom.SampleOf) && (rom.MachineName.ToLowerInvariant() != rom.SampleOf.ToLowerInvariant())
- ? " sampleof=\"" + HttpUtility.HtmlEncode(rom.SampleOf) + "\""
- : "")
- + ">\n"
- + (!ExcludeFields[(int)Field.Comment] && !String.IsNullOrWhiteSpace(rom.Comment) ? "\t\t" + HttpUtility.HtmlEncode(rom.Comment) + "\n" : "")
- + (!ExcludeFields[(int)Field.Description] ? "\t\t" + HttpUtility.HtmlEncode((String.IsNullOrWhiteSpace(rom.MachineDescription) ? rom.MachineName : rom.MachineDescription)) + "\n" : "")
- + (!ExcludeFields[(int)Field.Year] && !String.IsNullOrWhiteSpace(rom.Year) ? "\t\t" + HttpUtility.HtmlEncode(rom.Year) + "\n" : "")
- + (!ExcludeFields[(int)Field.Publisher] && !String.IsNullOrWhiteSpace(rom.Publisher) ? "\t\t" + HttpUtility.HtmlEncode(rom.Publisher) + "\n" : "")
- + (!ExcludeFields[(int)Field.Manufacturer] && !String.IsNullOrWhiteSpace(rom.Manufacturer) ? "\t\t" + HttpUtility.HtmlEncode(rom.Manufacturer) + "\n" : "");
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game end using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteEndGame(StreamWriter sw)
- {
- try
- {
- string state = "\t" + (_depreciated ? "game" : "machine") + ">\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
-
- try
- {
- string state = "";
-
- // Pre-process the item name
- ProcessItemName(rom, true);
-
- switch (rom.ItemType)
- {
- case ItemType.Archive:
- state += "\t\t\n";
- break;
- case ItemType.BiosSet:
- state += "\t\t\n";
- break;
- case ItemType.Disk:
- state += "\t\t\n";
- break;
- case ItemType.Release:
- state += "\t\t\n";
- break;
- case ItemType.Rom:
- state += "\t\t\n";
- break;
- case ItemType.Sample:
- state += "\t\t\n";
- break;
- }
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT footer using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteFooter(StreamWriter sw)
- {
- try
- {
- string footer = "\t" + (_depreciated ? "game" : "machine") + ">\n\n";
-
- // Write the footer out
- sw.Write(footer);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
- }
+ ///
+ /// Represents parsing and writing of a Logiqx-derived DAT
+ ///
+ /// TODO: Add XSD validation for all XML DAT types (maybe?)
+ /// TODO: Verify that all write for this DatFile type is correct
+ internal class Logiqx : DatFile
+ {
+ // Private instance variables specific to Logiqx DATs
+ bool _depreciated;
+
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ /// True if the output uses "game", false if the output uses "machine"
+ public Logiqx(DatFile datFile, bool depreciated)
+ : base(datFile, cloneHeader: false)
+ {
+ _depreciated = depreciated;
+ }
+
+ ///
+ /// Parse a Logiqx XML DAT 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
+ /// 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,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Prepare all internal variables
+ Encoding enc = Utilities.GetEncoding(filename);
+ XmlReader xtr = Utilities.GetXmlTextReader(filename);
+ List dirs = new List();
+
+ // If we got a null reader, just return
+ if (xtr == null)
+ {
+ return;
+ }
+
+ // Otherwise, read the file to the end
+ try
+ {
+ xtr.MoveToContent();
+ while (!xtr.EOF)
+ {
+ // We only want elements
+ if (xtr.NodeType != XmlNodeType.Element)
+ {
+ // If we're ending a dir, remove the last item from the dirs list, if possible
+ if (xtr.Name == "dir" && dirs.Count > 0)
+ {
+ dirs.RemoveAt(dirs.Count - 1);
+ }
+
+ xtr.Read();
+ continue;
+ }
+
+ switch (xtr.Name)
+ {
+ // The datafile tag can have some attributes
+ case "datafile":
+ // string build = xtr.GetAttribute("build");
+ // string debug = xtr.GetAttribute("debug"); // (yes|no) "no"
+ xtr.Read();
+ break;
+ // We want to process the entire subtree of the header
+ case "header":
+ ReadHeader(xtr.ReadSubtree(), keep);
+
+ // Skip the header node now that we've processed it
+ xtr.Skip();
+ break;
+ // Unique to RomVault-created DATs
+ case "dir":
+ Type = "SuperDAT";
+ dirs.Add(xtr.GetAttribute("name") ?? "");
+ xtr.Read();
+ break;
+ // We want to process the entire subtree of the game
+ case "machine": // New-style Logiqx
+ case "game": // Old-style Logiqx
+ ReadMachine(xtr.ReadSubtree(), dirs, filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the machine now that we've processed it
+ xtr.Skip();
+ break;
+ default:
+ xtr.Read();
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
+
+ // For XML errors, just skip the affected node
+ xtr?.Read();
+ }
+
+ 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, add what is possible
+ reader.MoveToContent();
+
+ 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": // This is exclusive to TruRip XML
+ 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);
+ break;
+ case "email":
+ content = reader.ReadElementContentAsString();
+ Email = (String.IsNullOrWhiteSpace(Email) ? content : Email);
+ break;
+ case "homepage":
+ content = reader.ReadElementContentAsString();
+ Homepage = (String.IsNullOrWhiteSpace(Homepage) ? content : Homepage);
+ break;
+ case "url":
+ content = reader.ReadElementContentAsString();
+ Url = (String.IsNullOrWhiteSpace(Url) ? content : Url);
+ break;
+ case "comment":
+ content = reader.ReadElementContentAsString();
+ Comment = (String.IsNullOrWhiteSpace(Comment) ? content : Comment);
+ break;
+ case "type": // This is exclusive to TruRip XML
+ content = reader.ReadElementContentAsString();
+ Type = (String.IsNullOrWhiteSpace(Type) ? content : Type);
+ superdat = superdat || content.Contains("SuperDAT");
+ break;
+ case "clrmamepro":
+ if (String.IsNullOrWhiteSpace(Header))
+ {
+ Header = reader.GetAttribute("header");
+ }
+ if (ForceMerging == ForceMerging.None)
+ {
+ ForceMerging = Utilities.GetForceMerging(reader.GetAttribute("forcemerging"));
+ }
+ if (ForceNodump == ForceNodump.None)
+ {
+ ForceNodump = Utilities.GetForceNodump(reader.GetAttribute("forcenodump"));
+ }
+ if (ForcePacking == ForcePacking.None)
+ {
+ ForcePacking = Utilities.GetForcePacking(reader.GetAttribute("forcepacking"));
+ }
+ reader.Read();
+ break;
+ case "romcenter":
+ if (reader.GetAttribute("plugin") != null)
+ {
+ // CDATA
+ }
+ if (reader.GetAttribute("rommode") != null)
+ {
+ // (merged|split|unmerged) "split"
+ }
+ if (reader.GetAttribute("biosmode") != null)
+ {
+ // merged|split|unmerged) "split"
+ }
+ if (reader.GetAttribute("samplemode") != null)
+ {
+ // (merged|unmerged) "merged"
+ }
+ if (reader.GetAttribute("lockrommode") != null)
+ {
+ // (yes|no) "no"
+ }
+ if (reader.GetAttribute("lockbiosmode") != null)
+ {
+ // (yes|no) "no"
+ }
+ if (reader.GetAttribute("locksamplemode") != null)
+ {
+ // (yes|no) "no"
+ }
+ reader.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Read game/machine information
+ ///
+ /// XmlReader to use to parse the machine
+ /// List of dirs to prepend to the game name
+ /// 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 void ReadMachine(
+ XmlReader reader,
+ List dirs,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // If we have an empty machine, skip it
+ if (reader == null)
+ {
+ return;
+ }
+
+ // Otherwise, add what is possible
+ reader.MoveToContent();
+
+ string key = "";
+ string temptype = reader.Name;
+ bool containsItems = false;
+
+ // Create a new machine
+ MachineType machineType = MachineType.NULL;
+ if (Utilities.GetYesNo(reader.GetAttribute("isbios")) == true)
+ {
+ machineType |= MachineType.Bios;
+ }
+ if (Utilities.GetYesNo(reader.GetAttribute("isdevice")) == true) // Listxml-specific, used by older DATs
+ {
+ machineType |= MachineType.Device;
+ }
+ if (Utilities.GetYesNo(reader.GetAttribute("ismechanical")) == true) // Listxml-specific, used by older DATs
+ {
+ machineType |= MachineType.Mechanical;
+ }
+
+ string dirsString = (dirs != null && dirs.Count() > 0 ? string.Join("/", dirs) + "/" : "");
+ Machine machine = new Machine
+ {
+ Name = dirsString + reader.GetAttribute("name"),
+ Description = dirsString + reader.GetAttribute("name"),
+ SourceFile = reader.GetAttribute("sourcefile"),
+ Board = reader.GetAttribute("board"),
+ RebuildTo = reader.GetAttribute("rebuildto"),
+ Runnable = Utilities.GetYesNo(reader.GetAttribute("runnable")), // Listxml-specific, used by older DATs
+
+ Comment = "",
+
+ CloneOf = reader.GetAttribute("cloneof") ?? "",
+ RomOf = reader.GetAttribute("romof") ?? "",
+ SampleOf = reader.GetAttribute("sampleof") ?? "",
+
+ MachineType = (machineType == MachineType.NULL ? MachineType.None : machineType),
+ };
+
+ if (Type == "SuperDAT" && !keep)
+ {
+ string tempout = Regex.Match(machine.Name, @".*?\\(.*)").Groups[1].Value;
+ if (!String.IsNullOrWhiteSpace(tempout))
+ {
+ machine.Name = tempout;
+ }
+ }
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the roms from the machine
+ switch (reader.Name)
+ {
+ case "comment": // There can be multiple comments by spec
+ machine.Comment += reader.ReadElementContentAsString();
+ break;
+ case "description":
+ machine.Description = reader.ReadElementContentAsString();
+ break;
+ case "year":
+ machine.Year = reader.ReadElementContentAsString();
+ break;
+ case "manufacturer":
+ machine.Manufacturer = reader.ReadElementContentAsString();
+ break;
+ case "publisher": // Not technically supported but used by some legacy DATs
+ machine.Publisher = reader.ReadElementContentAsString();
+ break;
+ case "trurip": // This is special metadata unique to TruRip
+ ReadTruRip(reader.ReadSubtree(), machine);
+
+ // Skip the trurip node now that we've processed it
+ reader.Skip();
+ break;
+ case "release":
+ containsItems = true;
+
+ DatItem release = new Release
+ {
+ Name = reader.GetAttribute("name"),
+ Region = reader.GetAttribute("region"),
+ Language = reader.GetAttribute("language"),
+ Date = reader.GetAttribute("date"),
+ Default = Utilities.GetYesNo(reader.GetAttribute("default")),
+ };
+
+ release.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(release, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "biosset":
+ containsItems = true;
+
+ DatItem biosset = new BiosSet
+ {
+ Name = reader.GetAttribute("name"),
+ Description = reader.GetAttribute("description"),
+ Default = Utilities.GetYesNo(reader.GetAttribute("default")),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ biosset.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(biosset, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "rom":
+ containsItems = true;
+
+ DatItem rom = new Rom
+ {
+ Name = reader.GetAttribute("name"),
+ Size = Utilities.GetSize(reader.GetAttribute("size")),
+ CRC = Utilities.CleanHashData(reader.GetAttribute("crc"), Constants.CRCLength),
+ MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
+ SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
+ SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
+ SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
+ SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
+ MergeTag = reader.GetAttribute("merge"),
+ ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
+ Date = Utilities.GetDate(reader.GetAttribute("date")),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ rom.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(rom, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "disk":
+ containsItems = true;
+
+ DatItem disk = new Disk
+ {
+ Name = reader.GetAttribute("name"),
+ MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
+ SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
+ SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
+ SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
+ SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
+ MergeTag = reader.GetAttribute("merge"),
+ ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ disk.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(disk, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "sample":
+ containsItems = true;
+
+ DatItem samplerom = new Sample
+ {
+ Name = reader.GetAttribute("name"),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ samplerom.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(samplerom, clean, remUnicode);
+
+ reader.Read();
+ break;
+ case "archive":
+ containsItems = true;
+
+ DatItem archiverom = new Archive
+ {
+ Name = reader.GetAttribute("name"),
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ archiverom.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(archiverom, clean, remUnicode);
+
+ reader.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ // If no items were found for this machine, add a Blank placeholder
+ if (!containsItems)
+ {
+ Blank blank = new Blank()
+ {
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ blank.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ ParseAddHelper(blank, clean, remUnicode);
+ }
+ }
+
+ ///
+ /// Read TruRip information
+ ///
+ /// True if full pathnames are to be kept, false otherwise (default)
+ /// Machine information to pass to contained items
+ private void ReadTruRip(XmlReader reader, Machine machine)
+ {
+ // If we have an empty trurip, skip it
+ if (reader == null)
+ {
+ return;
+ }
+
+ // Otherwise, add what is possible
+ reader.MoveToContent();
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the information from the trurip
+ string content = "";
+ switch (reader.Name)
+ {
+ case "titleid":
+ content = reader.ReadElementContentAsString();
+ // string titleid = content;
+ break;
+ case "publisher":
+ machine.Publisher = reader.ReadElementContentAsString();
+ break;
+ case "developer": // Manufacturer is as close as this gets
+ machine.Manufacturer = reader.ReadElementContentAsString();
+ break;
+ case "year":
+ machine.Year = reader.ReadElementContentAsString();
+ break;
+ case "genre":
+ content = reader.ReadElementContentAsString();
+ // string genre = content;
+ break;
+ case "subgenre":
+ content = reader.ReadElementContentAsString();
+ // string subgenre = content;
+ break;
+ case "ratings":
+ content = reader.ReadElementContentAsString();
+ // string ratings = content;
+ break;
+ case "score":
+ content = reader.ReadElementContentAsString();
+ // string score = content;
+ break;
+ case "players":
+ content = reader.ReadElementContentAsString();
+ // string players = content;
+ break;
+ case "enabled":
+ content = reader.ReadElementContentAsString();
+ // string enabled = content;
+ break;
+ case "crc":
+ content = reader.ReadElementContentAsString();
+ // string crc = Utilities.GetYesNo(content);
+ break;
+ case "source":
+ machine.SourceFile = reader.ReadElementContentAsString();
+ break;
+ case "cloneof":
+ machine.CloneOf = reader.ReadElementContentAsString();
+ break;
+ case "relatedto":
+ content = reader.ReadElementContentAsString();
+ // string relatedto = content;
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
+
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
+
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+
+ // Write out the header
+ WriteHeader(sw);
+
+ // Write out each of the machines and roms
+ string lastgame = null;
+
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
+
+ foreach (string key in keys)
+ {
+ List roms = this[key];
+
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
+
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
+
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
+
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteEndGame(sw);
+ }
+
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteStartGame(sw, rom);
+ }
+
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+
+ rom.Name = (rom.Name == "null" ? "-" : rom.Name);
+ ((Rom)rom).Size = Constants.SizeZero;
+ ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
+ ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
+ ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
+ ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
+ ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
+ ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
+ }
+
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
+
+ // Write the file footer out
+ WriteFooter(sw);
+
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "\n" +
+ "\n\n" +
+ "\n" +
+ "\t\n" +
+ "\t\t" + HttpUtility.HtmlEncode(Name) + "\n" +
+ "\t\t" + HttpUtility.HtmlEncode(Description) + "\n" +
+ (!String.IsNullOrWhiteSpace(RootDir) ? "\t\t" + HttpUtility.HtmlEncode(RootDir) + "\n" : "") +
+ (!String.IsNullOrWhiteSpace(Category) ? "\t\t" + HttpUtility.HtmlEncode(Category) + "\n" : "") +
+ "\t\t" + HttpUtility.HtmlEncode(Version) + "\n" +
+ (!String.IsNullOrWhiteSpace(Date) ? "\t\t" + HttpUtility.HtmlEncode(Date) + "\n" : "") +
+ "\t\t" + HttpUtility.HtmlEncode(Author) + "\n" +
+ (!String.IsNullOrWhiteSpace(Email) ? "\t\t" + HttpUtility.HtmlEncode(Email) + "\n" : "") +
+ (!String.IsNullOrWhiteSpace(Homepage) ? "\t\t" + HttpUtility.HtmlEncode(Homepage) + "\n" : "") +
+ (!String.IsNullOrWhiteSpace(Url) ? "\t\t" + HttpUtility.HtmlEncode(Url) + "\n" : "") +
+ (!String.IsNullOrWhiteSpace(Comment) ? "\t\t" + HttpUtility.HtmlEncode(Comment) + "\n" : "") +
+ (!String.IsNullOrWhiteSpace(Type) ? "\t\t" + HttpUtility.HtmlEncode(Type) + "\n" : "") +
+ (ForcePacking != ForcePacking.None || ForceMerging != ForceMerging.None || ForceNodump != ForceNodump.None || !String.IsNullOrWhiteSpace(Header) ?
+ "\t\t\n"
+ : "") +
+ "\t\n";
+
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteStartGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
+
+ string state = "\t<" + (_depreciated ? "game" : "machine") + " name=\"" + (!ExcludeFields[(int)Field.MachineName] ? HttpUtility.HtmlEncode(rom.MachineName) : "") + "\""
+ + (!ExcludeFields[(int)Field.MachineType] && (rom.MachineType & MachineType.Bios) != 0 ? " isbios=\"yes\"" : "")
+ + (!ExcludeFields[(int)Field.MachineType] && (rom.MachineType & MachineType.Device) != 0 ? " isdevice=\"yes\"" : "")
+ + (!ExcludeFields[(int)Field.MachineType] && (rom.MachineType & MachineType.Mechanical) != 0 ? " ismechanical=\"yes\"" : "")
+ + (!ExcludeFields[(int)Field.Runnable] && rom.Runnable == true
+ ? " runnable=\"yes\""
+ : (!ExcludeFields[(int)Field.Runnable] && rom.Runnable == false ? " runnable=\"no\"" : ""))
+ + (!ExcludeFields[(int)Field.CloneOf] && !String.IsNullOrWhiteSpace(rom.CloneOf) && (rom.MachineName.ToLowerInvariant() != rom.CloneOf.ToLowerInvariant())
+ ? " cloneof=\"" + HttpUtility.HtmlEncode(rom.CloneOf) + "\""
+ : "")
+ + (!ExcludeFields[(int)Field.RomOf] && !String.IsNullOrWhiteSpace(rom.RomOf) && (rom.MachineName.ToLowerInvariant() != rom.RomOf.ToLowerInvariant())
+ ? " romof=\"" + HttpUtility.HtmlEncode(rom.RomOf) + "\""
+ : "")
+ + (!ExcludeFields[(int)Field.SampleOf] && !String.IsNullOrWhiteSpace(rom.SampleOf) && (rom.MachineName.ToLowerInvariant() != rom.SampleOf.ToLowerInvariant())
+ ? " sampleof=\"" + HttpUtility.HtmlEncode(rom.SampleOf) + "\""
+ : "")
+ + ">\n"
+ + (!ExcludeFields[(int)Field.Comment] && !String.IsNullOrWhiteSpace(rom.Comment) ? "\t\t" + HttpUtility.HtmlEncode(rom.Comment) + "\n" : "")
+ + (!ExcludeFields[(int)Field.Description] ? "\t\t" + HttpUtility.HtmlEncode((String.IsNullOrWhiteSpace(rom.MachineDescription) ? rom.MachineName : rom.MachineDescription)) + "\n" : "")
+ + (!ExcludeFields[(int)Field.Year] && !String.IsNullOrWhiteSpace(rom.Year) ? "\t\t" + HttpUtility.HtmlEncode(rom.Year) + "\n" : "")
+ + (!ExcludeFields[(int)Field.Publisher] && !String.IsNullOrWhiteSpace(rom.Publisher) ? "\t\t" + HttpUtility.HtmlEncode(rom.Publisher) + "\n" : "")
+ + (!ExcludeFields[(int)Field.Manufacturer] && !String.IsNullOrWhiteSpace(rom.Manufacturer) ? "\t\t" + HttpUtility.HtmlEncode(rom.Manufacturer) + "\n" : "");
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game end using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteEndGame(StreamWriter sw)
+ {
+ try
+ {
+ string state = "\t" + (_depreciated ? "game" : "machine") + ">\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
+
+ try
+ {
+ string state = "";
+
+ // Pre-process the item name
+ ProcessItemName(rom, true);
+
+ switch (rom.ItemType)
+ {
+ case ItemType.Archive:
+ state += "\t\t\n";
+ break;
+ case ItemType.BiosSet:
+ state += "\t\t\n";
+ break;
+ case ItemType.Disk:
+ state += "\t\t\n";
+ break;
+ case ItemType.Release:
+ state += "\t\t\n";
+ break;
+ case ItemType.Rom:
+ state += "\t\t\n";
+ break;
+ case ItemType.Sample:
+ state += "\t\t\n";
+ break;
+ }
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT footer using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteFooter(StreamWriter sw)
+ {
+ try
+ {
+ string footer = "\t" + (_depreciated ? "game" : "machine") + ">\n\n";
+
+ // Write the footer out
+ sw.Write(footer);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/Missfile.cs b/SabreTools.Library/DatFiles/Missfile.cs
index 0e15b70b..778ddc46 100644
--- a/SabreTools.Library/DatFiles/Missfile.cs
+++ b/SabreTools.Library/DatFiles/Missfile.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -18,176 +17,176 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a Missfile
- ///
- internal class Missfile : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public Missfile(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
+ ///
+ /// Represents parsing and writing of a Missfile
+ ///
+ internal class Missfile : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public Missfile(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
- ///
- /// Parse a Missfile 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
- /// 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,
- int sysid,
- int srcid,
+ ///
+ /// Parse a Missfile 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
+ /// 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,
+ int sysid,
+ int srcid,
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // There is no consistent way to parse a missfile...
- throw new NotImplementedException();
- }
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // There is no consistent way to parse a missfile...
+ throw new NotImplementedException();
+ }
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
- // Write out each of the machines and roms
- string lastgame = null;
+ // Write out each of the machines and roms
+ string lastgame = null;
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
- foreach (string key in keys)
- {
- List roms = this[key];
+ foreach (string key in keys)
+ {
+ List roms = this[key];
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
- lastgame = rom.MachineName;
- continue;
- }
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+ lastgame = rom.MachineName;
+ continue;
+ }
- // Now, output the rom data
- WriteDatItem(sw, rom, lastgame, ignoreblanks);
+ // Now, output the rom data
+ WriteDatItem(sw, rom, lastgame, ignoreblanks);
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// The name of the last game to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, string lastgame, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// The name of the last game to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, string lastgame, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
- try
- {
- string state = "";
+ try
+ {
+ string state = "";
- // Process the item name
- ProcessItemName(rom, false, forceRomName: false);
+ // Process the item name
+ ProcessItemName(rom, false, forceRomName: false);
- // If we're in Romba mode, the state is consistent
- if (Romba)
- {
- state += (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- // Otherwise, use any flags
- else
- {
- if (!UseRomName && rom.MachineName != lastgame)
- {
- state += (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- lastgame = rom.MachineName;
- }
- else if (UseRomName)
- {
- state += (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
- }
- }
+ // If we're in Romba mode, the state is consistent
+ if (Romba)
+ {
+ state += (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ // Otherwise, use any flags
+ else
+ {
+ if (!UseRomName && rom.MachineName != lastgame)
+ {
+ state += (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ lastgame = rom.MachineName;
+ }
+ else if (UseRomName)
+ {
+ state += (!ExcludeFields[(int)Field.Name] ? rom.Name : "") + "\n";
+ }
+ }
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
- }
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/OfflineList.cs b/SabreTools.Library/DatFiles/OfflineList.cs
index fa0da19b..9730e1d2 100644
--- a/SabreTools.Library/DatFiles/OfflineList.cs
+++ b/SabreTools.Library/DatFiles/OfflineList.cs
@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
-using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -21,1028 +19,1028 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of an OfflineList XML DAT
- ///
- /// TODO: Verify that all write for this DatFile type is correct
- internal class OfflineList : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public OfflineList(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
-
- ///
- /// Parse an OfflineList XML DAT 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
- /// 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,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- Encoding enc = Utilities.GetEncoding(filename);
- XmlReader xtr = Utilities.GetXmlTextReader(filename);
-
- // If we got a null reader, just return
- if (xtr == null)
- {
- return;
- }
-
- // Otherwise, read the file to the end
- try
- {
- xtr.MoveToContent();
- while (!xtr.EOF)
- {
- // We only want elements
- if (xtr.NodeType != XmlNodeType.Element)
- {
- xtr.Read();
- continue;
- }
-
- switch (xtr.Name)
- {
- case "configuration":
- ReadConfiguration(xtr.ReadSubtree(), keep);
-
- // Skip the configuration node now that we've processed it
- xtr.Skip();
- break;
- case "games":
- ReadGames(xtr.ReadSubtree(), keep, clean, remUnicode);
-
- // Skip the games node now that we've processed it
- xtr.Skip();
- break;
- default:
- xtr.Read();
- break;
- }
- }
- }
- catch (Exception ex)
- {
- Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
-
- // For XML errors, just skip the affected node
- xtr?.Read();
- }
-
- 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":
- ReadInfos(reader.ReadSubtree());
-
- // Skip the infos node now that we've processed it
- reader.Skip();
- break;
- case "canopen":
- ReadCanOpen(reader.ReadSubtree());
-
- // Skip the canopen node now that we've processed it
- reader.Skip();
- break;
- case "newdat":
- ReadNewDat(reader.ReadSubtree());
-
- // Skip the newdat node now that we've processed it
- reader.Skip();
- break;
- case "search":
- ReadSearch(reader.ReadSubtree());
-
- // Skip the search node now that we've processed it
- reader.Skip();
- break;
- case "romtitle":
- content = reader.ReadElementContentAsString();
- // string romtitle = content;
-
- break;
- default:
- reader.Read();
- break;
- }
- }
- }
-
- ///
- /// Read infos information
- ///
- /// XmlReader to use to parse the header
- private void ReadInfos(XmlReader reader)
- {
- // 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 infos items
- switch (reader.Name.ToLowerInvariant())
- {
- case "title":
- // string title_visible = reader.GetAttribute("visible"); // (true|false)
- // string title_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string title_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "location":
- // string location_visible = reader.GetAttribute("visible"); // (true|false)
- // string location_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string location_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "publisher":
- // string publisher_visible = reader.GetAttribute("visible"); // (true|false)
- // string publisher_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string publisher_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "sourcerom":
- // string sourceRom_visible = reader.GetAttribute("visible"); // (true|false)
- // string sourceRom_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string sourceRom_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "savetype":
- // string saveType_visible = reader.GetAttribute("visible"); // (true|false)
- // string saveType_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string saveType_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "romsize":
- // string romSize_visible = reader.GetAttribute("visible"); // (true|false)
- // string romSize_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string romSize_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "releasenumber":
- // string releaseNumber_visible = reader.GetAttribute("visible"); // (true|false)
- // string releaseNumber_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string releaseNumber_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "languagenumber":
- // string languageNumber_visible = reader.GetAttribute("visible"); // (true|false)
- // string languageNumber_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string languageNumber_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "comment":
- // string comment_visible = reader.GetAttribute("visible"); // (true|false)
- // string comment_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string comment_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "romcrc":
- // string romCRC_visible = reader.GetAttribute("visible"); // (true|false)
- // string romCRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string romCRC_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "im1crc":
- // string im1CRC_visible = reader.GetAttribute("visible"); // (true|false)
- // string im1CRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string im1CRC_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "im2crc":
- // string im2CRC_visible = reader.GetAttribute("visible"); // (true|false)
- // string im2CRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
- // string im2CRC_default = reader.GetAttribute("default"); // (true|false)
- reader.Read();
- break;
- case "languages":
- // 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.Read();
- break;
- default:
- reader.Read();
- break;
- }
- }
- }
-
- ///
- /// Read canopen information
- ///
- /// XmlReader to use to parse the header
- private void ReadCanOpen(XmlReader reader)
- {
- // Prepare all internal variables
- List extensions = new List();
-
- // 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 canopen items
- switch (reader.Name.ToLowerInvariant())
- {
- case "extension":
- extensions.Add(reader.ReadElementContentAsString());
- break;
- default:
- reader.Read();
- break;
- }
- }
- }
-
- ///
- /// Read newdat information
- ///
- /// XmlReader to use to parse the header
- private void ReadNewDat(XmlReader reader)
- {
- // 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 newdat items
- string content = "";
- switch (reader.Name.ToLowerInvariant())
- {
- case "datversionurl":
- content = reader.ReadElementContentAsString();
- Url = (String.IsNullOrWhiteSpace(Name) ? content : Url);
- break;
- case "daturl":
- // string fileName = reader.GetAttribute("fileName");
- content = reader.ReadElementContentAsString();
- // string url = content;
- break;
- case "imurl":
- content = reader.ReadElementContentAsString();
- // string url = content;
- break;
- default:
- reader.Read();
- break;
- }
- }
- }
-
- ///
- /// Read search information
- ///
- /// XmlReader to use to parse the header
- private void ReadSearch(XmlReader reader)
- {
- // 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 search items
- string content = "";
- switch (reader.Name.ToLowerInvariant())
- {
- case "to":
- // string value = reader.GetAttribute("value");
- // string default = reader.GetAttribute("default"); (true|false)
- // string auto = reader.GetAttribute("auto"); (true|false)
-
- ReadTo(reader.ReadSubtree());
-
- // Skip the to node now that we've processed it
- reader.Skip();
- break;
- default:
- reader.Read();
- break;
- }
- }
- }
-
- ///
- /// Read to information
- ///
- /// XmlReader to use to parse the header
- private void ReadTo(XmlReader reader)
- {
- // 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 search items
- string content = "";
- switch (reader.Name.ToLowerInvariant())
- {
- case "find":
- // string operation = reader.GetAttribute("operation");
- // string value = reader.GetAttribute("value"); // Int32?
- content = reader.ReadElementContentAsString();
- // string findValue = 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 = "", duplicateid = "";
- 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":
- duplicateid = reader.ReadElementContentAsString();
- if (duplicateid != "0")
- {
- machine.CloneOf = duplicateid;
- }
-
- 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 = Utilities.CleanHashData(pair.Item2, Constants.CRCLength),
-
- ItemStatus = ItemStatus.None,
- });
- }
-
- return roms;
- }
-
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
-
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
-
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
-
- // Write out the header
- WriteHeader(sw);
-
- // Write out each of the machines and roms
- string lastgame = null;
-
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
-
- foreach (string key in keys)
- {
- List roms = this[key];
-
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
-
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
-
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
-
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteEndGame(sw);
- }
-
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
-
- rom.Name = (rom.Name == "null" ? "-" : rom.Name);
- ((Rom)rom).Size = Constants.SizeZero;
- ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
- ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
- ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
- ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
- ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
- ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
- }
-
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
-
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
-
- // Write the file footer out
- WriteFooter(sw);
-
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "\n"
- + "\n"
- + "\t\n"
- + "\t\t" + HttpUtility.HtmlEncode(Name) + "\n"
- + "\t\t" + Count + "\n"
- + "\t\tnone\n"
- + "\t\t240\n"
- + "\t\t160\n"
- + "\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\n"
- + "\t\t\n"
- + "\t\t\t.bin\n"
- + "\t\t\n"
- + "\t\t\n"
- + "\t\t\t" + HttpUtility.HtmlEncode(Url) + "\n"
- + "\t\t\t" + HttpUtility.HtmlEncode(Url) + "\n"
- + "\t\t\t" + HttpUtility.HtmlEncode(Url) + "\n"
- + "\t\t\n"
- + "\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\n"
- + "\t\t%u - %n\n"
- + "\t\n"
- + "\t\n";
-
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteEndGame(StreamWriter sw)
- {
- try
- {
- string state = "\t\t\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
-
- try
- {
- string state = "";
-
- // Pre-process the item name
- ProcessItemName(rom, true);
-
- state += "\t\t\n"
- + "\t\t\t1\n"
- + "\t\t\t1\n"
- + "\t\t\t" + (!ExcludeFields[(int)Field.Name] ? HttpUtility.HtmlEncode(rom.Name) : "") + "\n"
- + "\t\t\tNone\n";
-
- if (rom.ItemType == ItemType.Rom)
- {
- state += "\t\t\t" + (!ExcludeFields[(int)Field.Size] ? ((Rom)rom).Size.ToString() : "") + "\n";
- }
-
- state += "\t\t\tNone\n"
- + "\t\t\t0\n"
- + "\t\t\tNone\n"
- + "\t\t\t0\n";
-
- if (rom.ItemType == ItemType.Disk)
- {
- state += "\t\t\t\n"
- + (((Disk)rom).MD5 != null
- ? "\t\t\t\t" + (!ExcludeFields[(int)Field.MD5] ? ((Disk)rom).MD5.ToUpperInvariant() : "") + "\n"
- : "\t\t\t\t" + (!ExcludeFields[(int)Field.SHA1] ? ((Disk)rom).SHA1.ToUpperInvariant() : "") + "\n")
- + "\t\t\t\n";
- }
- else if (rom.ItemType == ItemType.Rom)
- {
- string tempext = "." + Utilities.GetExtension(((Rom)rom).Name);
-
- state += "\t\t\t\n"
- + (((Rom)rom).CRC != null
- ? "\t\t\t\t" + (!ExcludeFields[(int)Field.CRC] ? ((Rom)rom).CRC.ToUpperInvariant() : "") + "\n"
- : ((Rom)rom).MD5 != null
- ? "\t\t\t\t" + (!ExcludeFields[(int)Field.MD5] ? ((Rom)rom).MD5.ToUpperInvariant() : "") + "\n"
- : "\t\t\t\t" + (!ExcludeFields[(int)Field.SHA1] ? ((Rom)rom).SHA1.ToUpperInvariant() : "") + "\n")
- + "\t\t\t\n";
- }
-
- state += "\t\t\t00000000\n"
- + "\t\t\t00000000\n"
- + "\t\t\t\n"
- + "\t\t\t0\n"
- + "\t\t\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT footer using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteFooter(StreamWriter sw)
- {
- try
- {
- string footer = "\t\t"
- + "\t\n"
- + "\t\n"
- + "\t\t\n"
- + "\t\t\t\n"
- + "\t\t\t\n"
- + "\t\t\n"
- + "\t\n"
- + "";
-
- // Write the footer out
- sw.Write(footer);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
- }
+ ///
+ /// Represents parsing and writing of an OfflineList XML DAT
+ ///
+ /// TODO: Verify that all write for this DatFile type is correct
+ internal class OfflineList : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public OfflineList(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
+
+ ///
+ /// Parse an OfflineList XML DAT 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
+ /// 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,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ Encoding enc = Utilities.GetEncoding(filename);
+ XmlReader xtr = Utilities.GetXmlTextReader(filename);
+
+ // If we got a null reader, just return
+ if (xtr == null)
+ {
+ return;
+ }
+
+ // Otherwise, read the file to the end
+ try
+ {
+ xtr.MoveToContent();
+ while (!xtr.EOF)
+ {
+ // We only want elements
+ if (xtr.NodeType != XmlNodeType.Element)
+ {
+ xtr.Read();
+ continue;
+ }
+
+ switch (xtr.Name)
+ {
+ case "configuration":
+ ReadConfiguration(xtr.ReadSubtree(), keep);
+
+ // Skip the configuration node now that we've processed it
+ xtr.Skip();
+ break;
+ case "games":
+ ReadGames(xtr.ReadSubtree(), keep, clean, remUnicode);
+
+ // Skip the games node now that we've processed it
+ xtr.Skip();
+ break;
+ default:
+ xtr.Read();
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
+
+ // For XML errors, just skip the affected node
+ xtr?.Read();
+ }
+
+ 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":
+ ReadInfos(reader.ReadSubtree());
+
+ // Skip the infos node now that we've processed it
+ reader.Skip();
+ break;
+ case "canopen":
+ ReadCanOpen(reader.ReadSubtree());
+
+ // Skip the canopen node now that we've processed it
+ reader.Skip();
+ break;
+ case "newdat":
+ ReadNewDat(reader.ReadSubtree());
+
+ // Skip the newdat node now that we've processed it
+ reader.Skip();
+ break;
+ case "search":
+ ReadSearch(reader.ReadSubtree());
+
+ // Skip the search node now that we've processed it
+ reader.Skip();
+ break;
+ case "romtitle":
+ content = reader.ReadElementContentAsString();
+ // string romtitle = content;
+
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Read infos information
+ ///
+ /// XmlReader to use to parse the header
+ private void ReadInfos(XmlReader reader)
+ {
+ // 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 infos items
+ switch (reader.Name.ToLowerInvariant())
+ {
+ case "title":
+ // string title_visible = reader.GetAttribute("visible"); // (true|false)
+ // string title_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string title_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "location":
+ // string location_visible = reader.GetAttribute("visible"); // (true|false)
+ // string location_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string location_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "publisher":
+ // string publisher_visible = reader.GetAttribute("visible"); // (true|false)
+ // string publisher_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string publisher_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "sourcerom":
+ // string sourceRom_visible = reader.GetAttribute("visible"); // (true|false)
+ // string sourceRom_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string sourceRom_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "savetype":
+ // string saveType_visible = reader.GetAttribute("visible"); // (true|false)
+ // string saveType_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string saveType_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "romsize":
+ // string romSize_visible = reader.GetAttribute("visible"); // (true|false)
+ // string romSize_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string romSize_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "releasenumber":
+ // string releaseNumber_visible = reader.GetAttribute("visible"); // (true|false)
+ // string releaseNumber_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string releaseNumber_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "languagenumber":
+ // string languageNumber_visible = reader.GetAttribute("visible"); // (true|false)
+ // string languageNumber_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string languageNumber_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "comment":
+ // string comment_visible = reader.GetAttribute("visible"); // (true|false)
+ // string comment_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string comment_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "romcrc":
+ // string romCRC_visible = reader.GetAttribute("visible"); // (true|false)
+ // string romCRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string romCRC_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "im1crc":
+ // string im1CRC_visible = reader.GetAttribute("visible"); // (true|false)
+ // string im1CRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string im1CRC_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "im2crc":
+ // string im2CRC_visible = reader.GetAttribute("visible"); // (true|false)
+ // string im2CRC_inNamingOption = reader.GetAttribute("inNamingOption"); // (true|false)
+ // string im2CRC_default = reader.GetAttribute("default"); // (true|false)
+ reader.Read();
+ break;
+ case "languages":
+ // 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.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Read canopen information
+ ///
+ /// XmlReader to use to parse the header
+ private void ReadCanOpen(XmlReader reader)
+ {
+ // Prepare all internal variables
+ List extensions = new List();
+
+ // 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 canopen items
+ switch (reader.Name.ToLowerInvariant())
+ {
+ case "extension":
+ extensions.Add(reader.ReadElementContentAsString());
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Read newdat information
+ ///
+ /// XmlReader to use to parse the header
+ private void ReadNewDat(XmlReader reader)
+ {
+ // 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 newdat items
+ string content = "";
+ switch (reader.Name.ToLowerInvariant())
+ {
+ case "datversionurl":
+ content = reader.ReadElementContentAsString();
+ Url = (String.IsNullOrWhiteSpace(Name) ? content : Url);
+ break;
+ case "daturl":
+ // string fileName = reader.GetAttribute("fileName");
+ content = reader.ReadElementContentAsString();
+ // string url = content;
+ break;
+ case "imurl":
+ content = reader.ReadElementContentAsString();
+ // string url = content;
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Read search information
+ ///
+ /// XmlReader to use to parse the header
+ private void ReadSearch(XmlReader reader)
+ {
+ // 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 search items
+ string content = "";
+ switch (reader.Name.ToLowerInvariant())
+ {
+ case "to":
+ // string value = reader.GetAttribute("value");
+ // string default = reader.GetAttribute("default"); (true|false)
+ // string auto = reader.GetAttribute("auto"); (true|false)
+
+ ReadTo(reader.ReadSubtree());
+
+ // Skip the to node now that we've processed it
+ reader.Skip();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Read to information
+ ///
+ /// XmlReader to use to parse the header
+ private void ReadTo(XmlReader reader)
+ {
+ // 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 search items
+ string content = "";
+ switch (reader.Name.ToLowerInvariant())
+ {
+ case "find":
+ // string operation = reader.GetAttribute("operation");
+ // string value = reader.GetAttribute("value"); // Int32?
+ content = reader.ReadElementContentAsString();
+ // string findValue = 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 = "", duplicateid = "";
+ 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":
+ duplicateid = reader.ReadElementContentAsString();
+ if (duplicateid != "0")
+ {
+ machine.CloneOf = duplicateid;
+ }
+
+ 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 = Utilities.CleanHashData(pair.Item2, Constants.CRCLength),
+
+ ItemStatus = ItemStatus.None,
+ });
+ }
+
+ return roms;
+ }
+
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
+
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
+
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+
+ // Write out the header
+ WriteHeader(sw);
+
+ // Write out each of the machines and roms
+ string lastgame = null;
+
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
+
+ foreach (string key in keys)
+ {
+ List roms = this[key];
+
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
+
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
+
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
+
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteEndGame(sw);
+ }
+
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+
+ rom.Name = (rom.Name == "null" ? "-" : rom.Name);
+ ((Rom)rom).Size = Constants.SizeZero;
+ ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
+ ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
+ ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
+ ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
+ ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
+ ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
+ }
+
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
+
+ // Write the file footer out
+ WriteFooter(sw);
+
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "\n"
+ + "\n"
+ + "\t\n"
+ + "\t\t" + HttpUtility.HtmlEncode(Name) + "\n"
+ + "\t\t" + Count + "\n"
+ + "\t\tnone\n"
+ + "\t\t240\n"
+ + "\t\t160\n"
+ + "\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\n"
+ + "\t\t\n"
+ + "\t\t\t.bin\n"
+ + "\t\t\n"
+ + "\t\t\n"
+ + "\t\t\t" + HttpUtility.HtmlEncode(Url) + "\n"
+ + "\t\t\t" + HttpUtility.HtmlEncode(Url) + "\n"
+ + "\t\t\t" + HttpUtility.HtmlEncode(Url) + "\n"
+ + "\t\t\n"
+ + "\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\n"
+ + "\t\t%u - %n\n"
+ + "\t\n"
+ + "\t\n";
+
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteEndGame(StreamWriter sw)
+ {
+ try
+ {
+ string state = "\t\t\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
+
+ try
+ {
+ string state = "";
+
+ // Pre-process the item name
+ ProcessItemName(rom, true);
+
+ state += "\t\t\n"
+ + "\t\t\t1\n"
+ + "\t\t\t1\n"
+ + "\t\t\t" + (!ExcludeFields[(int)Field.Name] ? HttpUtility.HtmlEncode(rom.Name) : "") + "\n"
+ + "\t\t\tNone\n";
+
+ if (rom.ItemType == ItemType.Rom)
+ {
+ state += "\t\t\t" + (!ExcludeFields[(int)Field.Size] ? ((Rom)rom).Size.ToString() : "") + "\n";
+ }
+
+ state += "\t\t\tNone\n"
+ + "\t\t\t0\n"
+ + "\t\t\tNone\n"
+ + "\t\t\t0\n";
+
+ if (rom.ItemType == ItemType.Disk)
+ {
+ state += "\t\t\t\n"
+ + (((Disk)rom).MD5 != null
+ ? "\t\t\t\t" + (!ExcludeFields[(int)Field.MD5] ? ((Disk)rom).MD5.ToUpperInvariant() : "") + "\n"
+ : "\t\t\t\t" + (!ExcludeFields[(int)Field.SHA1] ? ((Disk)rom).SHA1.ToUpperInvariant() : "") + "\n")
+ + "\t\t\t\n";
+ }
+ else if (rom.ItemType == ItemType.Rom)
+ {
+ string tempext = "." + Utilities.GetExtension(((Rom)rom).Name);
+
+ state += "\t\t\t\n"
+ + (((Rom)rom).CRC != null
+ ? "\t\t\t\t" + (!ExcludeFields[(int)Field.CRC] ? ((Rom)rom).CRC.ToUpperInvariant() : "") + "\n"
+ : ((Rom)rom).MD5 != null
+ ? "\t\t\t\t" + (!ExcludeFields[(int)Field.MD5] ? ((Rom)rom).MD5.ToUpperInvariant() : "") + "\n"
+ : "\t\t\t\t" + (!ExcludeFields[(int)Field.SHA1] ? ((Rom)rom).SHA1.ToUpperInvariant() : "") + "\n")
+ + "\t\t\t\n";
+ }
+
+ state += "\t\t\t00000000\n"
+ + "\t\t\t00000000\n"
+ + "\t\t\t\n"
+ + "\t\t\t0\n"
+ + "\t\t\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT footer using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteFooter(StreamWriter sw)
+ {
+ try
+ {
+ string footer = "\t\t"
+ + "\t\n"
+ + "\t\n"
+ + "\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\t\n"
+ + "\t\t\n"
+ + "\t\n"
+ + "";
+
+ // Write the footer out
+ sw.Write(footer);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/OpenMSX.cs b/SabreTools.Library/DatFiles/OpenMSX.cs
index 3d0f30b5..ba2d176e 100644
--- a/SabreTools.Library/DatFiles/OpenMSX.cs
+++ b/SabreTools.Library/DatFiles/OpenMSX.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Xml;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -20,607 +19,607 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a openMSX softawre list XML DAT
- ///
- /// TODO: Verify that all write for this DatFile type is correct
- internal class OpenMSX : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public OpenMSX(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
-
- ///
- /// Parse a openMSX softawre list XML DAT 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
- /// 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,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Prepare all internal variables
- Encoding enc = Utilities.GetEncoding(filename);
- XmlReader xtr = Utilities.GetXmlTextReader(filename);
-
- // If we got a null reader, just return
- if (xtr == null)
- {
- return;
- }
-
- // Otherwise, read the file to the end
- try
- {
- xtr.MoveToContent();
- while (!xtr.EOF)
- {
- // We only want elements
- if (xtr.NodeType != XmlNodeType.Element)
- {
- xtr.Read();
- continue;
- }
-
- switch (xtr.Name)
- {
- case "softwaredb":
- Name = (String.IsNullOrWhiteSpace(Name) ? "openMSX Software List" : Name);
- Description = (String.IsNullOrWhiteSpace(Description) ? Name : Name);
- // string timestamp = xtr.GetAttribute("timestamp"); // CDATA
- xtr.Read();
- break;
- // We want to process the entire subtree of the software
- case "software":
- ReadSoftware(xtr.ReadSubtree(), filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the software now that we've processed it
- xtr.Skip();
- break;
- default:
- xtr.Read();
- break;
- }
- }
- }
- catch (Exception ex)
- {
- Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
-
- // For XML errors, just skip the affected node
- xtr?.Read();
- }
-
- xtr.Dispose();
- }
-
- ///
- /// Read software information
- ///
- /// XmlReader representing a machine block
- /// 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 void ReadSoftware(
- XmlReader reader,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // If we have an empty machine, skip it
- if (reader == null)
- {
- return;
- }
-
- // Otherwise, add what is possible
- reader.MoveToContent();
-
- int diskno = 0;
- bool containsItems = false;
-
- // Create a new machine
- Machine machine = new Machine();
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the roms from the machine
- switch (reader.Name)
- {
- case "title":
- machine.Name = reader.ReadElementContentAsString();
- break;
- case "genmsxid":
- // string id = reader.ReadElementContentAsString();
- reader.Read();
- break;
- case "system":
- // string system = reader.ReadElementContentAsString();
- reader.Read();
- break;
- case "company":
- machine.Manufacturer = reader.ReadElementContentAsString();
- break;
- case "year":
- machine.Year = reader.ReadElementContentAsString();
- break;
- case "country":
- // string country = reader.ReadElementContentAsString();
- reader.Read();
- break;
- case "dump":
- containsItems = ReadDump(reader.ReadSubtree(), machine, diskno, filename, sysid, srcid, keep, clean, remUnicode);
- diskno++;
-
- // Skip the dump now that we've processed it
- reader.Skip();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- // If no items were found for this machine, add a Blank placeholder
- if (!containsItems)
- {
- Blank blank = new Blank()
- {
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- blank.CopyMachineInformation(machine);
-
- // Now process and add the rom
- ParseAddHelper(blank, clean, remUnicode);
- }
- }
-
- ///
- /// Read dump information
- ///
- /// XmlReader representing a part block
- /// Machine information to pass to contained items
- /// Disk number to use when outputting to other DAT formats
- /// Name of the file to be parsed
- /// 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 ReadDump(
- XmlReader reader,
- Machine machine,
- int diskno,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- bool containsItems = false;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the dump
- switch (reader.Name)
- {
- case "rom":
- containsItems = ReadRom(reader.ReadSubtree(), machine, diskno, filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the rom now that we've processed it
- reader.Skip();
- break;
- case "megarom":
- containsItems = ReadMegaRom(reader.ReadSubtree(), machine, diskno, filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the megarom now that we've processed it
- reader.Skip();
- break;
- case "sccpluscart":
- containsItems = ReadSccPlusCart(reader.ReadSubtree(), machine, diskno, filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the sccpluscart now that we've processed it
- reader.Skip();
- break;
- case "original":
- // bool value = Utilities.GetYesNo(reader.GetAttribute("value");
- // string original = reader.ReadElementContentAsString();
- reader.Read();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- return containsItems;
- }
-
- ///
- /// Read rom information
- ///
- /// XmlReader representing a rom block
- /// Machine information to pass to contained items
- /// Disk number to use when outputting to other DAT formats
- /// Name of the file to be parsed
- /// 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 ReadRom(
- XmlReader reader,
- Machine machine,
- int diskno,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- string hash = "", offset = "", type = "", remark = "";
- bool containsItems = false;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the rom
- switch (reader.Name)
- {
- case "hash":
- containsItems = true;
- hash = reader.ReadElementContentAsString();
- break;
- case "start":
- offset = reader.ReadElementContentAsString();
- break;
- case "type":
- type = reader.ReadElementContentAsString();
- break;
- case "remark":
- remark = reader.ReadElementContentAsString();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- // Create and add the new rom
- Rom rom = new Rom
- {
- Name = machine.Name + "_" + diskno + (!String.IsNullOrWhiteSpace(remark) ? " " + remark : ""),
- Offset = offset,
- Size = -1,
- SHA1 = Utilities.CleanHashData(hash, Constants.SHA1Length),
- };
-
- rom.CopyMachineInformation(machine);
- ParseAddHelper(rom, clean, remUnicode);
-
- return containsItems;
- }
-
- ///
- /// Read megarom information
- ///
- /// XmlReader representing a megarom block
- /// Machine information to pass to contained items
- /// Disk number to use when outputting to other DAT formats
- /// Name of the file to be parsed
- /// 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 ReadMegaRom(
- XmlReader reader,
- Machine machine,
- int diskno,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- string hash = "", offset = "", type = "", remark = "";
- bool containsItems = false;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the dump
- switch (reader.Name)
- {
- case "hash":
- containsItems = true;
- hash = reader.ReadElementContentAsString();
- break;
- case "start":
- offset = reader.ReadElementContentAsString();
- break;
- case "type":
- type = reader.ReadElementContentAsString();
- break;
- case "remark":
- remark = reader.ReadElementContentAsString();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- // Create and add the new rom
- Rom rom = new Rom
- {
- Name = machine.Name + "_" + diskno + (!String.IsNullOrWhiteSpace(remark) ? " " + remark : ""),
- Offset = offset,
- Size = -1,
- SHA1 = Utilities.CleanHashData(hash, Constants.SHA1Length),
- };
-
- rom.CopyMachineInformation(machine);
- ParseAddHelper(rom, clean, remUnicode);
-
- return containsItems;
- }
-
- ///
- /// Read sccpluscart information
- ///
- /// XmlReader representing a sccpluscart block
- /// Machine information to pass to contained items
- /// Disk number to use when outputting to other DAT formats
- /// Name of the file to be parsed
- /// 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 ReadSccPlusCart(
- XmlReader reader,
- Machine machine,
- int diskno,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- string hash = "", boot = "", remark = "";
- bool containsItems = false;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the dump
- switch (reader.Name)
- {
- case "boot":
- boot = reader.ReadElementContentAsString();
- break;
- case "hash":
- containsItems = true;
- hash = reader.ReadElementContentAsString();
- break;
- case "remark":
- remark = reader.ReadElementContentAsString();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- // Create and add the new rom
- Rom rom = new Rom
- {
- Name = machine.Name + "_" + diskno + (!String.IsNullOrWhiteSpace(remark) ? " " + remark : ""),
- Size = -1,
- SHA1 = Utilities.CleanHashData(hash, Constants.SHA1Length),
- };
-
- rom.CopyMachineInformation(machine);
- ParseAddHelper(rom, clean, remUnicode);
-
- return containsItems;
- }
-
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
-
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
-
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
-
- // Write out the header
- WriteHeader(sw);
-
- // Write out each of the machines and roms
- string lastgame = null;
-
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
-
- foreach (string key in keys)
- {
- List roms = this[key];
-
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
-
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
-
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
-
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteEndGame(sw);
- }
-
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteStartGame(sw, rom);
- }
-
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
-
- lastgame = rom.MachineName;
- continue;
- }
-
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
-
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
-
- // Write the file footer out
- WriteFooter(sw);
-
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "\n" +
- "\n" +
- "\n" +
- @"
+ ///
+ /// Represents parsing and writing of a openMSX softawre list XML DAT
+ ///
+ /// TODO: Verify that all write for this DatFile type is correct
+ internal class OpenMSX : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public OpenMSX(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
+
+ ///
+ /// Parse a openMSX softawre list XML DAT 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
+ /// 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,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Prepare all internal variables
+ Encoding enc = Utilities.GetEncoding(filename);
+ XmlReader xtr = Utilities.GetXmlTextReader(filename);
+
+ // If we got a null reader, just return
+ if (xtr == null)
+ {
+ return;
+ }
+
+ // Otherwise, read the file to the end
+ try
+ {
+ xtr.MoveToContent();
+ while (!xtr.EOF)
+ {
+ // We only want elements
+ if (xtr.NodeType != XmlNodeType.Element)
+ {
+ xtr.Read();
+ continue;
+ }
+
+ switch (xtr.Name)
+ {
+ case "softwaredb":
+ Name = (String.IsNullOrWhiteSpace(Name) ? "openMSX Software List" : Name);
+ Description = (String.IsNullOrWhiteSpace(Description) ? Name : Name);
+ // string timestamp = xtr.GetAttribute("timestamp"); // CDATA
+ xtr.Read();
+ break;
+ // We want to process the entire subtree of the software
+ case "software":
+ ReadSoftware(xtr.ReadSubtree(), filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the software now that we've processed it
+ xtr.Skip();
+ break;
+ default:
+ xtr.Read();
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
+
+ // For XML errors, just skip the affected node
+ xtr?.Read();
+ }
+
+ xtr.Dispose();
+ }
+
+ ///
+ /// Read software information
+ ///
+ /// XmlReader representing a machine block
+ /// 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 void ReadSoftware(
+ XmlReader reader,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // If we have an empty machine, skip it
+ if (reader == null)
+ {
+ return;
+ }
+
+ // Otherwise, add what is possible
+ reader.MoveToContent();
+
+ int diskno = 0;
+ bool containsItems = false;
+
+ // Create a new machine
+ Machine machine = new Machine();
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the roms from the machine
+ switch (reader.Name)
+ {
+ case "title":
+ machine.Name = reader.ReadElementContentAsString();
+ break;
+ case "genmsxid":
+ // string id = reader.ReadElementContentAsString();
+ reader.Read();
+ break;
+ case "system":
+ // string system = reader.ReadElementContentAsString();
+ reader.Read();
+ break;
+ case "company":
+ machine.Manufacturer = reader.ReadElementContentAsString();
+ break;
+ case "year":
+ machine.Year = reader.ReadElementContentAsString();
+ break;
+ case "country":
+ // string country = reader.ReadElementContentAsString();
+ reader.Read();
+ break;
+ case "dump":
+ containsItems = ReadDump(reader.ReadSubtree(), machine, diskno, filename, sysid, srcid, keep, clean, remUnicode);
+ diskno++;
+
+ // Skip the dump now that we've processed it
+ reader.Skip();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ // If no items were found for this machine, add a Blank placeholder
+ if (!containsItems)
+ {
+ Blank blank = new Blank()
+ {
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ blank.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ ParseAddHelper(blank, clean, remUnicode);
+ }
+ }
+
+ ///
+ /// Read dump information
+ ///
+ /// XmlReader representing a part block
+ /// Machine information to pass to contained items
+ /// Disk number to use when outputting to other DAT formats
+ /// Name of the file to be parsed
+ /// 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 ReadDump(
+ XmlReader reader,
+ Machine machine,
+ int diskno,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ bool containsItems = false;
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the elements from the dump
+ switch (reader.Name)
+ {
+ case "rom":
+ containsItems = ReadRom(reader.ReadSubtree(), machine, diskno, filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the rom now that we've processed it
+ reader.Skip();
+ break;
+ case "megarom":
+ containsItems = ReadMegaRom(reader.ReadSubtree(), machine, diskno, filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the megarom now that we've processed it
+ reader.Skip();
+ break;
+ case "sccpluscart":
+ containsItems = ReadSccPlusCart(reader.ReadSubtree(), machine, diskno, filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the sccpluscart now that we've processed it
+ reader.Skip();
+ break;
+ case "original":
+ // bool value = Utilities.GetYesNo(reader.GetAttribute("value");
+ // string original = reader.ReadElementContentAsString();
+ reader.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ return containsItems;
+ }
+
+ ///
+ /// Read rom information
+ ///
+ /// XmlReader representing a rom block
+ /// Machine information to pass to contained items
+ /// Disk number to use when outputting to other DAT formats
+ /// Name of the file to be parsed
+ /// 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 ReadRom(
+ XmlReader reader,
+ Machine machine,
+ int diskno,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ string hash = "", offset = "", type = "", remark = "";
+ bool containsItems = false;
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the elements from the rom
+ switch (reader.Name)
+ {
+ case "hash":
+ containsItems = true;
+ hash = reader.ReadElementContentAsString();
+ break;
+ case "start":
+ offset = reader.ReadElementContentAsString();
+ break;
+ case "type":
+ type = reader.ReadElementContentAsString();
+ break;
+ case "remark":
+ remark = reader.ReadElementContentAsString();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ // Create and add the new rom
+ Rom rom = new Rom
+ {
+ Name = machine.Name + "_" + diskno + (!String.IsNullOrWhiteSpace(remark) ? " " + remark : ""),
+ Offset = offset,
+ Size = -1,
+ SHA1 = Utilities.CleanHashData(hash, Constants.SHA1Length),
+ };
+
+ rom.CopyMachineInformation(machine);
+ ParseAddHelper(rom, clean, remUnicode);
+
+ return containsItems;
+ }
+
+ ///
+ /// Read megarom information
+ ///
+ /// XmlReader representing a megarom block
+ /// Machine information to pass to contained items
+ /// Disk number to use when outputting to other DAT formats
+ /// Name of the file to be parsed
+ /// 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 ReadMegaRom(
+ XmlReader reader,
+ Machine machine,
+ int diskno,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ string hash = "", offset = "", type = "", remark = "";
+ bool containsItems = false;
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the elements from the dump
+ switch (reader.Name)
+ {
+ case "hash":
+ containsItems = true;
+ hash = reader.ReadElementContentAsString();
+ break;
+ case "start":
+ offset = reader.ReadElementContentAsString();
+ break;
+ case "type":
+ type = reader.ReadElementContentAsString();
+ break;
+ case "remark":
+ remark = reader.ReadElementContentAsString();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ // Create and add the new rom
+ Rom rom = new Rom
+ {
+ Name = machine.Name + "_" + diskno + (!String.IsNullOrWhiteSpace(remark) ? " " + remark : ""),
+ Offset = offset,
+ Size = -1,
+ SHA1 = Utilities.CleanHashData(hash, Constants.SHA1Length),
+ };
+
+ rom.CopyMachineInformation(machine);
+ ParseAddHelper(rom, clean, remUnicode);
+
+ return containsItems;
+ }
+
+ ///
+ /// Read sccpluscart information
+ ///
+ /// XmlReader representing a sccpluscart block
+ /// Machine information to pass to contained items
+ /// Disk number to use when outputting to other DAT formats
+ /// Name of the file to be parsed
+ /// 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 ReadSccPlusCart(
+ XmlReader reader,
+ Machine machine,
+ int diskno,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ string hash = "", boot = "", remark = "";
+ bool containsItems = false;
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the elements from the dump
+ switch (reader.Name)
+ {
+ case "boot":
+ boot = reader.ReadElementContentAsString();
+ break;
+ case "hash":
+ containsItems = true;
+ hash = reader.ReadElementContentAsString();
+ break;
+ case "remark":
+ remark = reader.ReadElementContentAsString();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ // Create and add the new rom
+ Rom rom = new Rom
+ {
+ Name = machine.Name + "_" + diskno + (!String.IsNullOrWhiteSpace(remark) ? " " + remark : ""),
+ Size = -1,
+ SHA1 = Utilities.CleanHashData(hash, Constants.SHA1Length),
+ };
+
+ rom.CopyMachineInformation(machine);
+ ParseAddHelper(rom, clean, remUnicode);
+
+ return containsItems;
+ }
+
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
+
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
+
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+
+ // Write out the header
+ WriteHeader(sw);
+
+ // Write out each of the machines and roms
+ string lastgame = null;
+
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
+
+ foreach (string key in keys)
+ {
+ List roms = this[key];
+
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
+
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
+
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
+
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteEndGame(sw);
+ }
+
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteStartGame(sw, rom);
+ }
+
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+
+ lastgame = rom.MachineName;
+ continue;
+ }
+
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
+
+ // Write the file footer out
+ WriteFooter(sw);
+
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "\n" +
+ "\n" +
+ "\n" +
+ @"
";
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteStartGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteStartGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
- string state = "\n"
- + "\t" + (!ExcludeFields[(int)Field.MachineName] ? HttpUtility.HtmlEncode(rom.MachineName) : "") + "\n"
- // + "\t" + msxid + "\n"
- // + "\t" + system + "\n"
- + "\t" + (!ExcludeFields[(int)Field.Manufacturer] ? rom.Manufacturer : "") + "\n"
- + "\t" + (!ExcludeFields[(int)Field.Year] ? rom.Year : "") + "\n";
- // + "\t" + country + "\n";
+ string state = "\n"
+ + "\t" + (!ExcludeFields[(int)Field.MachineName] ? HttpUtility.HtmlEncode(rom.MachineName) : "") + "\n"
+ // + "\t" + msxid + "\n"
+ // + "\t" + system + "\n"
+ + "\t" + (!ExcludeFields[(int)Field.Manufacturer] ? rom.Manufacturer : "") + "\n"
+ + "\t" + (!ExcludeFields[(int)Field.Year] ? rom.Year : "") + "\n";
+ // + "\t" + country + "\n";
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteEndGame(StreamWriter sw)
- {
- try
- {
- string state = "\n";
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteEndGame(StreamWriter sw)
+ {
+ try
+ {
+ string state = "\n";
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
- try
- {
- string state = "";
+ try
+ {
+ string state = "";
- // Pre-process the item name
- ProcessItemName(rom, true);
+ // Pre-process the item name
+ ProcessItemName(rom, true);
- switch (rom.ItemType)
- {
- case ItemType.Archive:
- break;
- case ItemType.BiosSet:
- break;
- case ItemType.Disk:
- break;
- case ItemType.Release:
- break;
- case ItemType.Rom: // Currently this encapsulates rom, megarom, and sccpluscart
- state += "\t\t"
- // + "GoodMSX"
- + ""
- + (!ExcludeFields[(int)Field.Offset] && !String.IsNullOrWhiteSpace(((Rom)rom).Offset) ? "" + ((Rom)rom).Offset + "" : "")
- // + "Normal"
- + "" + (!ExcludeFields[(int)Field.SHA1] ? ((Rom)rom).SHA1 : "") + ""
- // + ""
- + "\n";
- break;
- case ItemType.Sample:
- break;
- }
+ switch (rom.ItemType)
+ {
+ case ItemType.Archive:
+ break;
+ case ItemType.BiosSet:
+ break;
+ case ItemType.Disk:
+ break;
+ case ItemType.Release:
+ break;
+ case ItemType.Rom: // Currently this encapsulates rom, megarom, and sccpluscart
+ state += "\t\t"
+ // + "GoodMSX"
+ + ""
+ + (!ExcludeFields[(int)Field.Offset] && !String.IsNullOrWhiteSpace(((Rom)rom).Offset) ? "" + ((Rom)rom).Offset + "" : "")
+ // + "Normal"
+ + "" + (!ExcludeFields[(int)Field.SHA1] ? ((Rom)rom).SHA1 : "") + ""
+ // + ""
+ + "\n";
+ break;
+ case ItemType.Sample:
+ break;
+ }
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DAT footer using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteFooter(StreamWriter sw)
- {
- try
- {
- string footer = "\n\n";
+ ///
+ /// Write out DAT footer using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteFooter(StreamWriter sw)
+ {
+ try
+ {
+ string footer = "\n\n";
- // Write the footer out
- sw.Write(footer);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ // Write the footer out
+ sw.Write(footer);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
- }
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/RomCenter.cs b/SabreTools.Library/DatFiles/RomCenter.cs
index 107e2fd7..43f7afb5 100644
--- a/SabreTools.Library/DatFiles/RomCenter.cs
+++ b/SabreTools.Library/DatFiles/RomCenter.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Text;
using System.Web;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -20,359 +19,359 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a RomCenter DAT
- ///
- internal class RomCenter : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public RomCenter(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
+ ///
+ /// Represents parsing and writing of a RomCenter DAT
+ ///
+ internal class RomCenter : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public RomCenter(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
- ///
- /// Parse a RomCenter DAT 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
- /// 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,
- int sysid,
- int srcid,
+ ///
+ /// Parse a RomCenter DAT 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
+ /// 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,
+ int sysid,
+ int srcid,
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Open a file reader
- Encoding enc = Utilities.GetEncoding(filename);
- StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Open a file reader
+ Encoding enc = Utilities.GetEncoding(filename);
+ StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
- string blocktype = "";
- while (!sr.EndOfStream)
- {
- string line = sr.ReadLine();
+ string blocktype = "";
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine();
- // If the line is the start of the credits section
- if (line.ToLowerInvariant().StartsWith("[credits]"))
- {
- blocktype = "credits";
- }
- // If the line is the start of the dat section
- else if (line.ToLowerInvariant().StartsWith("[dat]"))
- {
- blocktype = "dat";
- }
- // If the line is the start of the emulator section
- else if (line.ToLowerInvariant().StartsWith("[emulator]"))
- {
- blocktype = "emulator";
- }
- // If the line is the start of the game section
- else if (line.ToLowerInvariant().StartsWith("[games]"))
- {
- blocktype = "games";
- }
- // Otherwise, it's not a section and it's data, so get out all data
- else
- {
- // If we have an author
- if (line.ToLowerInvariant().StartsWith("author="))
- {
- Author = (String.IsNullOrWhiteSpace(Author) ? line.Split('=')[1] : Author);
- }
- // If we have one of the three version tags
- else if (line.ToLowerInvariant().StartsWith("version="))
- {
- switch (blocktype)
- {
- case "credits":
- Version = (String.IsNullOrWhiteSpace(Version) ? line.Split('=')[1] : Version);
- break;
- case "emulator":
- Description = (String.IsNullOrWhiteSpace(Description) ? line.Split('=')[1] : Description);
- break;
- }
- }
- // If we have a URL
- else if (line.ToLowerInvariant().StartsWith("url="))
- {
- Url = (String.IsNullOrWhiteSpace(Url) ? line.Split('=')[1] : Url);
- }
- // If we have a comment
- else if (line.ToLowerInvariant().StartsWith("comment="))
- {
- Comment = (String.IsNullOrWhiteSpace(Comment) ? line.Split('=')[1] : Comment);
- }
- // If we have the split flag
- else if (line.ToLowerInvariant().StartsWith("split="))
- {
- if (Int32.TryParse(line.Split('=')[1], out int split))
- {
- if (split == 1 && ForceMerging == ForceMerging.None)
- {
- ForceMerging = ForceMerging.Split;
- }
- }
- }
- // If we have the merge tag
- else if (line.ToLowerInvariant().StartsWith("merge="))
- {
- if (Int32.TryParse(line.Split('=')[1], out int merge))
- {
- if (merge == 1 && ForceMerging == ForceMerging.None)
- {
- ForceMerging = ForceMerging.Full;
- }
- }
- }
- // If we have the refname tag
- else if (line.ToLowerInvariant().StartsWith("refname="))
- {
- Name = (String.IsNullOrWhiteSpace(Name) ? line.Split('=')[1] : Name);
- }
- // If we have a rom
- else if (line.StartsWith("¬"))
- {
- // Some old RC DATs have this behavior
- if (line.Contains("¬N¬O"))
- {
- line = line.Replace("¬N¬O", "") + "¬¬";
- }
+ // If the line is the start of the credits section
+ if (line.ToLowerInvariant().StartsWith("[credits]"))
+ {
+ blocktype = "credits";
+ }
+ // If the line is the start of the dat section
+ else if (line.ToLowerInvariant().StartsWith("[dat]"))
+ {
+ blocktype = "dat";
+ }
+ // If the line is the start of the emulator section
+ else if (line.ToLowerInvariant().StartsWith("[emulator]"))
+ {
+ blocktype = "emulator";
+ }
+ // If the line is the start of the game section
+ else if (line.ToLowerInvariant().StartsWith("[games]"))
+ {
+ blocktype = "games";
+ }
+ // Otherwise, it's not a section and it's data, so get out all data
+ else
+ {
+ // If we have an author
+ if (line.ToLowerInvariant().StartsWith("author="))
+ {
+ Author = (String.IsNullOrWhiteSpace(Author) ? line.Split('=')[1] : Author);
+ }
+ // If we have one of the three version tags
+ else if (line.ToLowerInvariant().StartsWith("version="))
+ {
+ switch (blocktype)
+ {
+ case "credits":
+ Version = (String.IsNullOrWhiteSpace(Version) ? line.Split('=')[1] : Version);
+ break;
+ case "emulator":
+ Description = (String.IsNullOrWhiteSpace(Description) ? line.Split('=')[1] : Description);
+ break;
+ }
+ }
+ // If we have a URL
+ else if (line.ToLowerInvariant().StartsWith("url="))
+ {
+ Url = (String.IsNullOrWhiteSpace(Url) ? line.Split('=')[1] : Url);
+ }
+ // If we have a comment
+ else if (line.ToLowerInvariant().StartsWith("comment="))
+ {
+ Comment = (String.IsNullOrWhiteSpace(Comment) ? line.Split('=')[1] : Comment);
+ }
+ // If we have the split flag
+ else if (line.ToLowerInvariant().StartsWith("split="))
+ {
+ if (Int32.TryParse(line.Split('=')[1], out int split))
+ {
+ if (split == 1 && ForceMerging == ForceMerging.None)
+ {
+ ForceMerging = ForceMerging.Split;
+ }
+ }
+ }
+ // If we have the merge tag
+ else if (line.ToLowerInvariant().StartsWith("merge="))
+ {
+ if (Int32.TryParse(line.Split('=')[1], out int merge))
+ {
+ if (merge == 1 && ForceMerging == ForceMerging.None)
+ {
+ ForceMerging = ForceMerging.Full;
+ }
+ }
+ }
+ // If we have the refname tag
+ else if (line.ToLowerInvariant().StartsWith("refname="))
+ {
+ Name = (String.IsNullOrWhiteSpace(Name) ? line.Split('=')[1] : Name);
+ }
+ // If we have a rom
+ else if (line.StartsWith("¬"))
+ {
+ // Some old RC DATs have this behavior
+ if (line.Contains("¬N¬O"))
+ {
+ line = line.Replace("¬N¬O", "") + "¬¬";
+ }
- /*
- The rominfo order is as follows:
- 1 - parent name
- 2 - parent description
- 3 - game name
- 4 - game description
- 5 - rom name
- 6 - rom crc
- 7 - rom size
- 8 - romof name
- 9 - merge name
- */
- string[] rominfo = line.Split('¬');
+ /*
+ The rominfo order is as follows:
+ 1 - parent name
+ 2 - parent description
+ 3 - game name
+ 4 - game description
+ 5 - rom name
+ 6 - rom crc
+ 7 - rom size
+ 8 - romof name
+ 9 - merge name
+ */
+ string[] rominfo = line.Split('¬');
- // Try getting the size separately
- if (!Int64.TryParse(rominfo[7], out long size))
- {
- size = 0;
- }
+ // Try getting the size separately
+ if (!Int64.TryParse(rominfo[7], out long size))
+ {
+ size = 0;
+ }
- Rom rom = new Rom
- {
- Name = rominfo[5],
- Size = size,
- CRC = Utilities.CleanHashData(rominfo[6], Constants.CRCLength),
- ItemStatus = ItemStatus.None,
+ Rom rom = new Rom
+ {
+ Name = rominfo[5],
+ Size = size,
+ CRC = Utilities.CleanHashData(rominfo[6], Constants.CRCLength),
+ ItemStatus = ItemStatus.None,
- MachineName = rominfo[3],
- MachineDescription = rominfo[4],
- CloneOf = rominfo[1],
- RomOf = rominfo[8],
+ MachineName = rominfo[3],
+ MachineDescription = rominfo[4],
+ CloneOf = rominfo[1],
+ RomOf = rominfo[8],
- SystemID = sysid,
- SourceID = srcid,
- };
+ SystemID = sysid,
+ SourceID = srcid,
+ };
- // Now process and add the rom
- ParseAddHelper(rom, clean, remUnicode);
- }
- }
- }
+ // Now process and add the rom
+ ParseAddHelper(rom, clean, remUnicode);
+ }
+ }
+ }
- sr.Dispose();
- }
+ sr.Dispose();
+ }
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
- // Write out the header
- WriteHeader(sw);
+ // Write out the header
+ WriteHeader(sw);
- // Write out each of the machines and roms
- string lastgame = null;
- List splitpath = new List();
+ // Write out each of the machines and roms
+ string lastgame = null;
+ List splitpath = new List();
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
- foreach (string key in keys)
- {
- List roms = this[key];
+ foreach (string key in keys)
+ {
+ List roms = this[key];
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
- rom.Name = (rom.Name == "null" ? "-" : rom.Name);
- ((Rom)rom).Size = Constants.SizeZero;
- ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
- ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
- ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
- ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
- ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
- ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
- }
+ rom.Name = (rom.Name == "null" ? "-" : rom.Name);
+ ((Rom)rom).Size = Constants.SizeZero;
+ ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null;
+ ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null;
+ ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null;
+ ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null;
+ ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null;
+ ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null;
+ }
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = header = "[CREDITS]\n" +
- "author=" + Author + "\n" +
- "version=" + Version + "\n" +
- "comment=" + Comment + "\n" +
- "[DAT]\n" +
- "version=2.50\n" +
- "split=" + (ForceMerging == ForceMerging.Split ? "1" : "0") + "\n" +
- "merge=" + (ForceMerging == ForceMerging.Full || ForceMerging == ForceMerging.Merged ? "1" : "0") + "\n" +
- "[EMULATOR]\n" +
- "refname=" + Name + "\n" +
- "version=" + Description + "\n" +
- "[GAMES]\n";
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = header = "[CREDITS]\n" +
+ "author=" + Author + "\n" +
+ "version=" + Version + "\n" +
+ "comment=" + Comment + "\n" +
+ "[DAT]\n" +
+ "version=2.50\n" +
+ "split=" + (ForceMerging == ForceMerging.Split ? "1" : "0") + "\n" +
+ "merge=" + (ForceMerging == ForceMerging.Full || ForceMerging == ForceMerging.Merged ? "1" : "0") + "\n" +
+ "[EMULATOR]\n" +
+ "refname=" + Name + "\n" +
+ "version=" + Description + "\n" +
+ "[GAMES]\n";
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
- try
- {
- string state = "";
+ try
+ {
+ string state = "";
- // Pre-process the item name
- ProcessItemName(rom, true);
+ // Pre-process the item name
+ ProcessItemName(rom, true);
- if (rom.ItemType == ItemType.Rom)
- {
- state += "¬" + (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? HttpUtility.HtmlEncode(rom.CloneOf) : "") +
- "¬" + (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? HttpUtility.HtmlEncode(rom.CloneOf) : "") +
- "¬" + (!ExcludeFields[(int)Field.MachineName] ? HttpUtility.HtmlEncode(rom.MachineName) : "") +
- "¬" + (!ExcludeFields[(int)Field.Description] ? HttpUtility.HtmlEncode((String.IsNullOrWhiteSpace(rom.MachineDescription) ? rom.MachineName : rom.MachineDescription)) : "") +
- "¬" + (!ExcludeFields[(int)Field.Name] ? HttpUtility.HtmlEncode(rom.Name) : "") +
- "¬" + (!ExcludeFields[(int)Field.CRC] ? ((Rom)rom).CRC.ToLowerInvariant() : "") +
- "¬" + (!ExcludeFields[(int)Field.Size] && ((Rom)rom).Size != -1 ? ((Rom)rom).Size.ToString() : "") + "¬¬¬\n";
- }
- else if (rom.ItemType == ItemType.Disk)
- {
- state += "¬" + (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? HttpUtility.HtmlEncode(rom.CloneOf) : "") +
- "¬" + (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? HttpUtility.HtmlEncode(rom.CloneOf) : "") +
- "¬" + (!ExcludeFields[(int)Field.MachineName] ? HttpUtility.HtmlEncode(rom.MachineName) : "") +
- "¬" + (!ExcludeFields[(int)Field.Description] ? HttpUtility.HtmlEncode((String.IsNullOrWhiteSpace(rom.MachineDescription) ? rom.MachineName : rom.MachineDescription)) : "") +
- "¬" + (!ExcludeFields[(int)Field.Name] ? HttpUtility.HtmlEncode(rom.Name) : "") +
- "¬¬¬¬¬\n";
- }
+ if (rom.ItemType == ItemType.Rom)
+ {
+ state += "¬" + (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? HttpUtility.HtmlEncode(rom.CloneOf) : "") +
+ "¬" + (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? HttpUtility.HtmlEncode(rom.CloneOf) : "") +
+ "¬" + (!ExcludeFields[(int)Field.MachineName] ? HttpUtility.HtmlEncode(rom.MachineName) : "") +
+ "¬" + (!ExcludeFields[(int)Field.Description] ? HttpUtility.HtmlEncode((String.IsNullOrWhiteSpace(rom.MachineDescription) ? rom.MachineName : rom.MachineDescription)) : "") +
+ "¬" + (!ExcludeFields[(int)Field.Name] ? HttpUtility.HtmlEncode(rom.Name) : "") +
+ "¬" + (!ExcludeFields[(int)Field.CRC] ? ((Rom)rom).CRC.ToLowerInvariant() : "") +
+ "¬" + (!ExcludeFields[(int)Field.Size] && ((Rom)rom).Size != -1 ? ((Rom)rom).Size.ToString() : "") + "¬¬¬\n";
+ }
+ else if (rom.ItemType == ItemType.Disk)
+ {
+ state += "¬" + (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? HttpUtility.HtmlEncode(rom.CloneOf) : "") +
+ "¬" + (!ExcludeFields[(int)Field.CloneOf] && String.IsNullOrWhiteSpace(rom.CloneOf) ? HttpUtility.HtmlEncode(rom.CloneOf) : "") +
+ "¬" + (!ExcludeFields[(int)Field.MachineName] ? HttpUtility.HtmlEncode(rom.MachineName) : "") +
+ "¬" + (!ExcludeFields[(int)Field.Description] ? HttpUtility.HtmlEncode((String.IsNullOrWhiteSpace(rom.MachineDescription) ? rom.MachineName : rom.MachineDescription)) : "") +
+ "¬" + (!ExcludeFields[(int)Field.Name] ? HttpUtility.HtmlEncode(rom.Name) : "") +
+ "¬¬¬¬¬\n";
+ }
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
- }
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/SabreDat.cs b/SabreTools.Library/DatFiles/SabreDat.cs
index 75f4189b..41f0f669 100644
--- a/SabreTools.Library/DatFiles/SabreDat.cs
+++ b/SabreTools.Library/DatFiles/SabreDat.cs
@@ -2,10 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
-using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -22,918 +20,918 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of an SabreDat XML DAT
- ///
- /// TODO: Verify that all write for this DatFile type is correct
- internal class SabreDat : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public SabreDat(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
-
- ///
- /// 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
- /// 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)
- public override void ParseFile(
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Prepare all internal variables
- bool empty = true;
- string key = "";
- List parent = new List();
-
- Encoding enc = Utilities.GetEncoding(filename);
- XmlReader xtr = Utilities.GetXmlTextReader(filename);
-
- // If we got a null reader, just return
- if (xtr == null)
- {
- return;
- }
-
- // Otherwise, read the file to the end
- try
- {
- xtr.MoveToContent();
- while (!xtr.EOF)
- {
- // 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);
- }
- }
- }
-
- // We only want elements
- if (xtr.NodeType != XmlNodeType.Element)
- {
- xtr.Read();
- continue;
- }
-
- switch (xtr.Name)
- {
- // We want to process the entire subtree of the header
- case "header":
- ReadHeader(xtr.ReadSubtree(), keep);
-
- // Skip the header node now that we've processed it
- xtr.Skip();
- break;
- case "dir":
- case "directory":
- 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:
- xtr.Read();
- break;
- }
- }
- }
- catch (Exception ex)
- {
- Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
-
- // For XML errors, just skip the affected node
- xtr?.Read();
- }
-
- 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 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
- SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
- SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
- SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
- SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
- 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 = Utilities.CleanHashData(reader.GetAttribute("crc"), Constants.CRCLength),
- MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
- SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
- SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
- SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
- SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
- 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
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- /// TODO: Fix writing out files that have a path in the name
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
-
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
-
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
-
- // Write out the header
- WriteHeader(sw);
-
- // Write out each of the machines and roms
- int depth = 2, last = -1;
- string lastgame = null;
- List splitpath = new List();
-
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
-
- foreach (string key in keys)
- {
- List roms = this[key];
-
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
-
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
-
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
-
- List newsplit = rom.MachineName.Split('\\').ToList();
-
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- depth = WriteEndGame(sw, splitpath, newsplit, depth, out last);
- }
-
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- depth = WriteStartGame(sw, rom, newsplit, lastgame, depth, last);
- }
-
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
-
- splitpath = newsplit;
- lastgame = rom.MachineName;
- continue;
- }
-
- // Now, output the rom data
- WriteDatItem(sw, rom, depth, ignoreblanks);
-
- // Set the new data to compare against
- splitpath = newsplit;
- lastgame = rom.MachineName;
- }
- }
-
- // Write the file footer out
- WriteFooter(sw, depth);
-
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "\n" +
- "\n\n" +
- "\n" +
- "\t\n" +
- "\t\t" + HttpUtility.HtmlEncode(Name) + "\n" +
- "\t\t" + HttpUtility.HtmlEncode(Description) + "\n" +
- (!String.IsNullOrWhiteSpace(RootDir) ? "\t\t" + HttpUtility.HtmlEncode(RootDir) + "\n" : "") +
- (!String.IsNullOrWhiteSpace(Category) ? "\t\t" + HttpUtility.HtmlEncode(Category) + "\n" : "") +
- "\t\t" + HttpUtility.HtmlEncode(Version) + "\n" +
- (!String.IsNullOrWhiteSpace(Date) ? "\t\t" + HttpUtility.HtmlEncode(Date) + "\n" : "") +
- "\t\t" + HttpUtility.HtmlEncode(Author) + "\n" +
- (!String.IsNullOrWhiteSpace(Comment) ? "\t\t" + HttpUtility.HtmlEncode(Comment) + "\n" : "") +
- (!String.IsNullOrWhiteSpace(Type) || ForcePacking != ForcePacking.None || ForceMerging != ForceMerging.None || ForceNodump != ForceNodump.None ?
- "\t\t\n" +
- (!String.IsNullOrWhiteSpace(Type) ? "\t\t\t\n" : "") +
- (ForcePacking == ForcePacking.Unzip ? "\t\t\t\n" : "") +
- (ForcePacking == ForcePacking.Zip ? "\t\t\t\n" : "") +
- (ForceMerging == ForceMerging.Full ? "\t\t\t\n" : "") +
- (ForceMerging == ForceMerging.Split ? "\t\t\t\n" : "") +
- (ForceMerging == ForceMerging.Merged ? "\t\t\t\n" : "") +
- (ForceMerging == ForceMerging.NonMerged ? "\t\t\t\n" : "") +
- (ForceNodump == ForceNodump.Ignore ? "\t\t\t\n" : "") +
- (ForceNodump == ForceNodump.Obsolete ? "\t\t\t\n" : "") +
- (ForceNodump == ForceNodump.Required ? "\t\t\t\n" : "") +
- "\t\t\n"
- : "") +
- "\t\n" +
- "\t\n";
-
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// Split path representing the parent game (SabreDAT only)
- /// The name of the last game to be output
- /// Current depth to output file at (SabreDAT only)
- /// Last known depth to cycle back from (SabreDAT only)
- /// The new depth of the tag
- private int WriteStartGame(StreamWriter sw, DatItem rom, List newsplit, string lastgame, int depth, int last)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
-
- string state = "";
- for (int i = (last == -1 ? 0 : last); i < newsplit.Count; i++)
- {
- for (int j = 0; j < depth - last + i - (lastgame == null ? 1 : 0); j++)
- {
- state += "\t";
- }
- state += "\n";
- }
- depth = depth - (last == -1 ? 0 : last) + newsplit.Count;
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return depth;
- }
-
- return depth;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// Split path representing last kwown parent game (SabreDAT only)
- /// Split path representing the parent game (SabreDAT only)
- /// Current depth to output file at (SabreDAT only)
- /// Last known depth to cycle back from (SabreDAT only)
- /// The new depth of the tag
- private int WriteEndGame(StreamWriter sw, List splitpath, List newsplit, int depth, out int last)
- {
- last = 0;
-
- try
- {
- string state = "";
- if (splitpath != null)
- {
- for (int i = 0; i < newsplit.Count && i < splitpath.Count; i++)
- {
- // Always keep track of the last seen item
- last = i;
-
- // If we find a difference, break
- if (newsplit[i] != splitpath[i])
- {
- break;
- }
- }
-
- // Now that we have the last known position, take down all open folders
- for (int i = depth - 1; i > last + 1; i--)
- {
- // Print out the number of tabs and the end folder
- for (int j = 0; j < i; j++)
- {
- state += "\t";
- }
- state += "\n";
- }
-
- // Reset the current depth
- depth = 2 + last;
- }
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return depth;
- }
-
- return depth;
- }
-
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// Current depth to output file at (SabreDAT only)
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, int depth, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
-
- try
- {
- string state = "", prefix = "";
-
- // Pre-process the item name
- ProcessItemName(rom, true);
-
- for (int i = 0; i < depth; i++)
- {
- prefix += "\t";
- }
- state += prefix;
-
- switch (rom.ItemType)
- {
- case ItemType.Archive:
- state += "\n";
- break;
- case ItemType.BiosSet:
- state += "\n";
- break;
- case ItemType.Disk:
- state += "\n" + prefix + "\t\n" +
- prefix + "\t\t\n" +
- prefix + "\t\n" +
- prefix + "\n" : "/>\n");
- break;
- case ItemType.Release:
- state += "\n";
- break;
- case ItemType.Rom:
- state += "\n" + prefix + "\t\n" +
- prefix + "\t\t\n" +
- prefix + "\t\n" +
- prefix + "\n" : "/>\n");
- break;
- case ItemType.Sample:
- state += "\n";
- break;
- }
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT footer using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// Current depth to output file at (SabreDAT only)
- /// True if the data was written, false on error
- private bool WriteFooter(StreamWriter sw, int depth)
- {
- try
- {
- string footer = "";
- for (int i = depth - 1; i >= 2; i--)
- {
- // Print out the number of tabs and the end folder
- for (int j = 0; j < i; j++)
- {
- footer += "\t";
- }
- footer += "\n";
- }
- footer += "\t\n\n";
-
- // Write the footer out
- sw.Write(footer);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
- }
+ ///
+ /// Represents parsing and writing of an SabreDat XML DAT
+ ///
+ /// TODO: Verify that all write for this DatFile type is correct
+ internal class SabreDat : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public SabreDat(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
+
+ ///
+ /// 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
+ /// 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)
+ public override void ParseFile(
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Prepare all internal variables
+ bool empty = true;
+ string key = "";
+ List parent = new List();
+
+ Encoding enc = Utilities.GetEncoding(filename);
+ XmlReader xtr = Utilities.GetXmlTextReader(filename);
+
+ // If we got a null reader, just return
+ if (xtr == null)
+ {
+ return;
+ }
+
+ // Otherwise, read the file to the end
+ try
+ {
+ xtr.MoveToContent();
+ while (!xtr.EOF)
+ {
+ // 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);
+ }
+ }
+ }
+
+ // We only want elements
+ if (xtr.NodeType != XmlNodeType.Element)
+ {
+ xtr.Read();
+ continue;
+ }
+
+ switch (xtr.Name)
+ {
+ // We want to process the entire subtree of the header
+ case "header":
+ ReadHeader(xtr.ReadSubtree(), keep);
+
+ // Skip the header node now that we've processed it
+ xtr.Skip();
+ break;
+ case "dir":
+ case "directory":
+ 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:
+ xtr.Read();
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
+
+ // For XML errors, just skip the affected node
+ xtr?.Read();
+ }
+
+ 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 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
+ SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
+ SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
+ SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
+ SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
+ 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 = Utilities.CleanHashData(reader.GetAttribute("crc"), Constants.CRCLength),
+ MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
+ SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
+ SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
+ SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
+ SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
+ 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
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ /// TODO: Fix writing out files that have a path in the name
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
+
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
+
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+
+ // Write out the header
+ WriteHeader(sw);
+
+ // Write out each of the machines and roms
+ int depth = 2, last = -1;
+ string lastgame = null;
+ List splitpath = new List();
+
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
+
+ foreach (string key in keys)
+ {
+ List roms = this[key];
+
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
+
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
+
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
+
+ List newsplit = rom.MachineName.Split('\\').ToList();
+
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ depth = WriteEndGame(sw, splitpath, newsplit, depth, out last);
+ }
+
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ depth = WriteStartGame(sw, rom, newsplit, lastgame, depth, last);
+ }
+
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+
+ splitpath = newsplit;
+ lastgame = rom.MachineName;
+ continue;
+ }
+
+ // Now, output the rom data
+ WriteDatItem(sw, rom, depth, ignoreblanks);
+
+ // Set the new data to compare against
+ splitpath = newsplit;
+ lastgame = rom.MachineName;
+ }
+ }
+
+ // Write the file footer out
+ WriteFooter(sw, depth);
+
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "\n" +
+ "\n\n" +
+ "\n" +
+ "\t\n" +
+ "\t\t" + HttpUtility.HtmlEncode(Name) + "\n" +
+ "\t\t" + HttpUtility.HtmlEncode(Description) + "\n" +
+ (!String.IsNullOrWhiteSpace(RootDir) ? "\t\t" + HttpUtility.HtmlEncode(RootDir) + "\n" : "") +
+ (!String.IsNullOrWhiteSpace(Category) ? "\t\t" + HttpUtility.HtmlEncode(Category) + "\n" : "") +
+ "\t\t" + HttpUtility.HtmlEncode(Version) + "\n" +
+ (!String.IsNullOrWhiteSpace(Date) ? "\t\t" + HttpUtility.HtmlEncode(Date) + "\n" : "") +
+ "\t\t" + HttpUtility.HtmlEncode(Author) + "\n" +
+ (!String.IsNullOrWhiteSpace(Comment) ? "\t\t" + HttpUtility.HtmlEncode(Comment) + "\n" : "") +
+ (!String.IsNullOrWhiteSpace(Type) || ForcePacking != ForcePacking.None || ForceMerging != ForceMerging.None || ForceNodump != ForceNodump.None ?
+ "\t\t\n" +
+ (!String.IsNullOrWhiteSpace(Type) ? "\t\t\t\n" : "") +
+ (ForcePacking == ForcePacking.Unzip ? "\t\t\t\n" : "") +
+ (ForcePacking == ForcePacking.Zip ? "\t\t\t\n" : "") +
+ (ForceMerging == ForceMerging.Full ? "\t\t\t\n" : "") +
+ (ForceMerging == ForceMerging.Split ? "\t\t\t\n" : "") +
+ (ForceMerging == ForceMerging.Merged ? "\t\t\t\n" : "") +
+ (ForceMerging == ForceMerging.NonMerged ? "\t\t\t\n" : "") +
+ (ForceNodump == ForceNodump.Ignore ? "\t\t\t\n" : "") +
+ (ForceNodump == ForceNodump.Obsolete ? "\t\t\t\n" : "") +
+ (ForceNodump == ForceNodump.Required ? "\t\t\t\n" : "") +
+ "\t\t\n"
+ : "") +
+ "\t\n" +
+ "\t\n";
+
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// Split path representing the parent game (SabreDAT only)
+ /// The name of the last game to be output
+ /// Current depth to output file at (SabreDAT only)
+ /// Last known depth to cycle back from (SabreDAT only)
+ /// The new depth of the tag
+ private int WriteStartGame(StreamWriter sw, DatItem rom, List newsplit, string lastgame, int depth, int last)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
+
+ string state = "";
+ for (int i = (last == -1 ? 0 : last); i < newsplit.Count; i++)
+ {
+ for (int j = 0; j < depth - last + i - (lastgame == null ? 1 : 0); j++)
+ {
+ state += "\t";
+ }
+ state += "\n";
+ }
+ depth = depth - (last == -1 ? 0 : last) + newsplit.Count;
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return depth;
+ }
+
+ return depth;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// Split path representing last kwown parent game (SabreDAT only)
+ /// Split path representing the parent game (SabreDAT only)
+ /// Current depth to output file at (SabreDAT only)
+ /// Last known depth to cycle back from (SabreDAT only)
+ /// The new depth of the tag
+ private int WriteEndGame(StreamWriter sw, List splitpath, List newsplit, int depth, out int last)
+ {
+ last = 0;
+
+ try
+ {
+ string state = "";
+ if (splitpath != null)
+ {
+ for (int i = 0; i < newsplit.Count && i < splitpath.Count; i++)
+ {
+ // Always keep track of the last seen item
+ last = i;
+
+ // If we find a difference, break
+ if (newsplit[i] != splitpath[i])
+ {
+ break;
+ }
+ }
+
+ // Now that we have the last known position, take down all open folders
+ for (int i = depth - 1; i > last + 1; i--)
+ {
+ // Print out the number of tabs and the end folder
+ for (int j = 0; j < i; j++)
+ {
+ state += "\t";
+ }
+ state += "\n";
+ }
+
+ // Reset the current depth
+ depth = 2 + last;
+ }
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return depth;
+ }
+
+ return depth;
+ }
+
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// Current depth to output file at (SabreDAT only)
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, int depth, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
+
+ try
+ {
+ string state = "", prefix = "";
+
+ // Pre-process the item name
+ ProcessItemName(rom, true);
+
+ for (int i = 0; i < depth; i++)
+ {
+ prefix += "\t";
+ }
+ state += prefix;
+
+ switch (rom.ItemType)
+ {
+ case ItemType.Archive:
+ state += "\n";
+ break;
+ case ItemType.BiosSet:
+ state += "\n";
+ break;
+ case ItemType.Disk:
+ state += "\n" + prefix + "\t\n" +
+ prefix + "\t\t\n" +
+ prefix + "\t\n" +
+ prefix + "\n" : "/>\n");
+ break;
+ case ItemType.Release:
+ state += "\n";
+ break;
+ case ItemType.Rom:
+ state += "\n" + prefix + "\t\n" +
+ prefix + "\t\t\n" +
+ prefix + "\t\n" +
+ prefix + "\n" : "/>\n");
+ break;
+ case ItemType.Sample:
+ state += "\n";
+ break;
+ }
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT footer using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// Current depth to output file at (SabreDAT only)
+ /// True if the data was written, false on error
+ private bool WriteFooter(StreamWriter sw, int depth)
+ {
+ try
+ {
+ string footer = "";
+ for (int i = depth - 1; i >= 2; i--)
+ {
+ // Print out the number of tabs and the end folder
+ for (int j = 0; j < i; j++)
+ {
+ footer += "\t";
+ }
+ footer += "\n";
+ }
+ footer += "\t\n\n";
+
+ // Write the footer out
+ sw.Write(footer);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/SeparatedValue.cs b/SabreTools.Library/DatFiles/SeparatedValue.cs
index 54c9f412..8c1519f7 100644
--- a/SabreTools.Library/DatFiles/SeparatedValue.cs
+++ b/SabreTools.Library/DatFiles/SeparatedValue.cs
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -18,515 +16,515 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a value-separated DAT
- ///
- internal class SeparatedValue : DatFile
- {
- // Private instance variables specific to Separated Value DATs
- char _delim;
+ ///
+ /// Represents parsing and writing of a value-separated DAT
+ ///
+ internal class SeparatedValue : DatFile
+ {
+ // Private instance variables specific to Separated Value DATs
+ char _delim;
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- /// Delimiter for parsing individual lines
- public SeparatedValue(DatFile datFile, char delim)
- : base(datFile, cloneHeader: false)
- {
- _delim = delim;
- }
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ /// Delimiter for parsing individual lines
+ public SeparatedValue(DatFile datFile, char delim)
+ : base(datFile, cloneHeader: false)
+ {
+ _delim = delim;
+ }
- ///
- /// Parse a character-separated value DAT 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
- /// 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,
- int sysid,
- int srcid,
+ ///
+ /// Parse a character-separated value DAT 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
+ /// 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,
+ int sysid,
+ int srcid,
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Open a file reader
- Encoding enc = Utilities.GetEncoding(filename);
- StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Open a file reader
+ Encoding enc = Utilities.GetEncoding(filename);
+ StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
- // Create an empty list of columns to parse though
- List columns = new List();
+ // Create an empty list of columns to parse though
+ List columns = new List();
- long linenum = -1;
- while (!sr.EndOfStream)
- {
- string line = sr.ReadLine();
- linenum++;
+ long linenum = -1;
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine();
+ linenum++;
- // Parse the first line, getting types from the column names
- if (linenum == 0)
- {
- string[] parsedColumns = line.Split(_delim);
- foreach (string parsed in parsedColumns)
- {
- switch (parsed.ToLowerInvariant().Trim('"'))
- {
- case "file":
- case "filename":
- case "file name":
- columns.Add("DatFile.FileName");
- break;
- case "internal name":
- columns.Add("DatFile.Name");
- break;
- case "description":
- case "dat description":
- columns.Add("DatFile.Description");
- break;
- case "game name":
- case "game":
- case "machine":
- columns.Add("Machine.Name");
- break;
- case "game description":
- columns.Add("Description");
- break;
- case "type":
- columns.Add("DatItem.Type");
- break;
- case "rom":
- case "romname":
- case "rom name":
- case "name":
- columns.Add("Rom.Name");
- break;
- case "disk":
- case "diskname":
- case "disk name":
- columns.Add("Disk.Name");
- break;
- case "size":
- columns.Add("DatItem.Size");
- break;
- case "crc":
- case "crc hash":
- columns.Add("DatItem.CRC");
- break;
- case "md5":
- case "md5 hash":
- columns.Add("DatItem.MD5");
- break;
- case "sha1":
- case "sha-1":
- case "sha1 hash":
- case "sha-1 hash":
- columns.Add("DatItem.SHA1");
- break;
- case "sha256":
- case "sha-256":
- case "sha256 hash":
- case "sha-256 hash":
- columns.Add("DatItem.SHA256");
- break;
- case "sha384":
- case "sha-384":
- case "sha384 hash":
- case "sha-384 hash":
- columns.Add("DatItem.SHA384");
- break;
- case "sha512":
- case "sha-512":
- case "sha512 hash":
- case "sha-512 hash":
- columns.Add("DatItem.SHA512");
- break;
- case "nodump":
- case "no dump":
- case "status":
- case "item status":
- columns.Add("DatItem.Nodump");
- break;
- case "date":
- columns.Add("DatItem.Date");
- break;
- default:
- columns.Add("INVALID");
- break;
- }
- }
+ // Parse the first line, getting types from the column names
+ if (linenum == 0)
+ {
+ string[] parsedColumns = line.Split(_delim);
+ foreach (string parsed in parsedColumns)
+ {
+ switch (parsed.ToLowerInvariant().Trim('"'))
+ {
+ case "file":
+ case "filename":
+ case "file name":
+ columns.Add("DatFile.FileName");
+ break;
+ case "internal name":
+ columns.Add("DatFile.Name");
+ break;
+ case "description":
+ case "dat description":
+ columns.Add("DatFile.Description");
+ break;
+ case "game name":
+ case "game":
+ case "machine":
+ columns.Add("Machine.Name");
+ break;
+ case "game description":
+ columns.Add("Description");
+ break;
+ case "type":
+ columns.Add("DatItem.Type");
+ break;
+ case "rom":
+ case "romname":
+ case "rom name":
+ case "name":
+ columns.Add("Rom.Name");
+ break;
+ case "disk":
+ case "diskname":
+ case "disk name":
+ columns.Add("Disk.Name");
+ break;
+ case "size":
+ columns.Add("DatItem.Size");
+ break;
+ case "crc":
+ case "crc hash":
+ columns.Add("DatItem.CRC");
+ break;
+ case "md5":
+ case "md5 hash":
+ columns.Add("DatItem.MD5");
+ break;
+ case "sha1":
+ case "sha-1":
+ case "sha1 hash":
+ case "sha-1 hash":
+ columns.Add("DatItem.SHA1");
+ break;
+ case "sha256":
+ case "sha-256":
+ case "sha256 hash":
+ case "sha-256 hash":
+ columns.Add("DatItem.SHA256");
+ break;
+ case "sha384":
+ case "sha-384":
+ case "sha384 hash":
+ case "sha-384 hash":
+ columns.Add("DatItem.SHA384");
+ break;
+ case "sha512":
+ case "sha-512":
+ case "sha512 hash":
+ case "sha-512 hash":
+ columns.Add("DatItem.SHA512");
+ break;
+ case "nodump":
+ case "no dump":
+ case "status":
+ case "item status":
+ columns.Add("DatItem.Nodump");
+ break;
+ case "date":
+ columns.Add("DatItem.Date");
+ break;
+ default:
+ columns.Add("INVALID");
+ break;
+ }
+ }
- continue;
- }
+ continue;
+ }
- // Otherwise, we want to split the line and parse
- string[] parsedLine = line.Split(_delim);
+ // Otherwise, we want to split the line and parse
+ string[] parsedLine = line.Split(_delim);
- // If the line doesn't have the correct number of columns, we log and skip
- if (parsedLine.Length != columns.Count)
- {
- Globals.Logger.Warning("Malformed line found in '{0}' at line {1}", filename, linenum);
- continue;
- }
+ // If the line doesn't have the correct number of columns, we log and skip
+ if (parsedLine.Length != columns.Count)
+ {
+ Globals.Logger.Warning("Malformed line found in '{0}' at line {1}", filename, linenum);
+ continue;
+ }
- // Set the output item information
- string machineName = null, machineDesc = null, name = null, crc = null, md5 = null, sha1 = null,
- sha256 = null, sha384 = null, sha512 = null, date = null;
- long size = -1;
- ItemType itemType = ItemType.Rom;
- ItemStatus status = ItemStatus.None;
+ // Set the output item information
+ string machineName = null, machineDesc = null, name = null, crc = null, md5 = null, sha1 = null,
+ sha256 = null, sha384 = null, sha512 = null, date = null;
+ long size = -1;
+ ItemType itemType = ItemType.Rom;
+ ItemStatus status = ItemStatus.None;
- // Now we loop through and get values for everything
- for (int i = 0; i < columns.Count; i++)
- {
- string value = parsedLine[i].Trim('"');
- switch (columns[i])
- {
- case "DatFile.FileName":
- FileName = (String.IsNullOrWhiteSpace(FileName) ? value : FileName);
- break;
- case "DatFile.Name":
- Name = (String.IsNullOrWhiteSpace(Name) ? value : Name);
- break;
- case "DatFile.Description":
- Description = (String.IsNullOrWhiteSpace(Description) ? value : Description);
- break;
- case "Machine.Name":
- machineName = value;
- break;
- case "Description":
- machineDesc = value;
- break;
- case "DatItem.Type":
- itemType = Utilities.GetItemType(value) ?? ItemType.Rom;
- break;
- case "Rom.Name":
- case "Disk.Name":
- name = String.IsNullOrWhiteSpace(value) ? name : value;
- break;
- case "DatItem.Size":
- if (!Int64.TryParse(value, out size))
- {
- size = -1;
- }
- break;
- case "DatItem.CRC":
- crc = Utilities.CleanHashData(value, Constants.CRCLength);
- break;
- case "DatItem.MD5":
- md5 = Utilities.CleanHashData(value, Constants.MD5Length);
- break;
- case "DatItem.SHA1":
- sha1 = Utilities.CleanHashData(value, Constants.SHA1Length);
- break;
- case "DatItem.SHA256":
- sha256 = Utilities.CleanHashData(value, Constants.SHA256Length);
- break;
- case "DatItem.SHA384":
- sha384 = Utilities.CleanHashData(value, Constants.SHA384Length);
- break;
- case "DatItem.SHA512":
- sha512 = Utilities.CleanHashData(value, Constants.SHA512Length);
- break;
- case "DatItem.Nodump":
- status = Utilities.GetItemStatus(value);
- break;
- case "DatItem.Date":
- date = value;
- break;
- }
- }
+ // Now we loop through and get values for everything
+ for (int i = 0; i < columns.Count; i++)
+ {
+ string value = parsedLine[i].Trim('"');
+ switch (columns[i])
+ {
+ case "DatFile.FileName":
+ FileName = (String.IsNullOrWhiteSpace(FileName) ? value : FileName);
+ break;
+ case "DatFile.Name":
+ Name = (String.IsNullOrWhiteSpace(Name) ? value : Name);
+ break;
+ case "DatFile.Description":
+ Description = (String.IsNullOrWhiteSpace(Description) ? value : Description);
+ break;
+ case "Machine.Name":
+ machineName = value;
+ break;
+ case "Description":
+ machineDesc = value;
+ break;
+ case "DatItem.Type":
+ itemType = Utilities.GetItemType(value) ?? ItemType.Rom;
+ break;
+ case "Rom.Name":
+ case "Disk.Name":
+ name = String.IsNullOrWhiteSpace(value) ? name : value;
+ break;
+ case "DatItem.Size":
+ if (!Int64.TryParse(value, out size))
+ {
+ size = -1;
+ }
+ break;
+ case "DatItem.CRC":
+ crc = Utilities.CleanHashData(value, Constants.CRCLength);
+ break;
+ case "DatItem.MD5":
+ md5 = Utilities.CleanHashData(value, Constants.MD5Length);
+ break;
+ case "DatItem.SHA1":
+ sha1 = Utilities.CleanHashData(value, Constants.SHA1Length);
+ break;
+ case "DatItem.SHA256":
+ sha256 = Utilities.CleanHashData(value, Constants.SHA256Length);
+ break;
+ case "DatItem.SHA384":
+ sha384 = Utilities.CleanHashData(value, Constants.SHA384Length);
+ break;
+ case "DatItem.SHA512":
+ sha512 = Utilities.CleanHashData(value, Constants.SHA512Length);
+ break;
+ case "DatItem.Nodump":
+ status = Utilities.GetItemStatus(value);
+ break;
+ case "DatItem.Date":
+ date = value;
+ break;
+ }
+ }
- // And now we populate and add the new item
- switch (itemType)
- {
- case ItemType.Archive:
- Archive archive = new Archive()
- {
- Name = name,
+ // And now we populate and add the new item
+ switch (itemType)
+ {
+ case ItemType.Archive:
+ Archive archive = new Archive()
+ {
+ Name = name,
- MachineName = machineName,
- MachineDescription = machineDesc,
- };
+ MachineName = machineName,
+ MachineDescription = machineDesc,
+ };
- ParseAddHelper(archive, clean, remUnicode);
- break;
- case ItemType.BiosSet:
- BiosSet biosset = new BiosSet()
- {
- Name = name,
+ ParseAddHelper(archive, clean, remUnicode);
+ break;
+ case ItemType.BiosSet:
+ BiosSet biosset = new BiosSet()
+ {
+ Name = name,
- MachineName = machineName,
- Description = machineDesc,
- };
+ MachineName = machineName,
+ Description = machineDesc,
+ };
- ParseAddHelper(biosset, clean, remUnicode);
- break;
- case ItemType.Disk:
- Disk disk = new Disk()
- {
- Name = name,
- MD5 = md5,
- SHA1 = sha1,
- SHA256 = sha256,
- SHA384 = sha384,
- SHA512 = sha512,
+ ParseAddHelper(biosset, clean, remUnicode);
+ break;
+ case ItemType.Disk:
+ Disk disk = new Disk()
+ {
+ Name = name,
+ MD5 = md5,
+ SHA1 = sha1,
+ SHA256 = sha256,
+ SHA384 = sha384,
+ SHA512 = sha512,
- MachineName = machineName,
- MachineDescription = machineDesc,
+ MachineName = machineName,
+ MachineDescription = machineDesc,
- ItemStatus = status,
- };
+ ItemStatus = status,
+ };
- ParseAddHelper(disk, clean, remUnicode);
- break;
- case ItemType.Release:
- Release release = new Release()
- {
- Name = name,
+ ParseAddHelper(disk, clean, remUnicode);
+ break;
+ case ItemType.Release:
+ Release release = new Release()
+ {
+ Name = name,
- MachineName = machineName,
- MachineDescription = machineDesc,
- };
+ MachineName = machineName,
+ MachineDescription = machineDesc,
+ };
- ParseAddHelper(release, clean, remUnicode);
- break;
- case ItemType.Rom:
- Rom rom = new Rom()
- {
- Name = name,
- Size = size,
- CRC = crc,
- MD5 = md5,
- SHA1 = sha1,
- SHA256 = sha256,
- SHA384 = sha384,
- SHA512 = sha512,
- Date = date,
+ ParseAddHelper(release, clean, remUnicode);
+ break;
+ case ItemType.Rom:
+ Rom rom = new Rom()
+ {
+ Name = name,
+ Size = size,
+ CRC = crc,
+ MD5 = md5,
+ SHA1 = sha1,
+ SHA256 = sha256,
+ SHA384 = sha384,
+ SHA512 = sha512,
+ Date = date,
- MachineName = machineName,
- MachineDescription = machineDesc,
+ MachineName = machineName,
+ MachineDescription = machineDesc,
- ItemStatus = status,
- };
+ ItemStatus = status,
+ };
- ParseAddHelper(rom, clean, remUnicode);
- break;
- case ItemType.Sample:
- Sample sample = new Sample()
- {
- Name = name,
+ ParseAddHelper(rom, clean, remUnicode);
+ break;
+ case ItemType.Sample:
+ Sample sample = new Sample()
+ {
+ Name = name,
- MachineName = machineName,
- MachineDescription = machineDesc,
- };
+ MachineName = machineName,
+ MachineDescription = machineDesc,
+ };
- ParseAddHelper(sample, clean, remUnicode);
- break;
- }
- }
- }
+ ParseAddHelper(sample, clean, remUnicode);
+ break;
+ }
+ }
+ }
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
- // Write out the header
- WriteHeader(sw);
+ // Write out the header
+ WriteHeader(sw);
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
- foreach (string key in keys)
- {
- List roms = this[key];
+ foreach (string key in keys)
+ {
+ List roms = this[key];
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
- }
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+ }
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
- }
- }
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+ }
+ }
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = string.Format("\"File Name\"{0}\"Internal Name\"{0}\"Description\"{0}\"Game Name\"{0}\"Game Description\"{0}\"Type\"{0}\"" +
- "Rom Name\"{0}\"Disk Name\"{0}\"Size\"{0}\"CRC\"{0}\"MD5\"{0}\"SHA1\"{0}\"SHA256\"{0}\"Nodump\"\n", _delim);
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = string.Format("\"File Name\"{0}\"Internal Name\"{0}\"Description\"{0}\"Game Name\"{0}\"Game Description\"{0}\"Type\"{0}\"" +
+ "Rom Name\"{0}\"Disk Name\"{0}\"Size\"{0}\"CRC\"{0}\"MD5\"{0}\"SHA1\"{0}\"SHA256\"{0}\"Nodump\"\n", _delim);
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
- try
- {
- // Initialize all strings
- string state = "",
- pre = "",
- post = "",
- type = "",
- romname = "",
- diskname = "",
- size = "",
- crc = "",
- md5 = "",
- sha1 = "",
- sha256 = "",
- sha384 = "",
- sha512 = "",
- status = "";
+ try
+ {
+ // Initialize all strings
+ string state = "",
+ pre = "",
+ post = "",
+ type = "",
+ romname = "",
+ diskname = "",
+ size = "",
+ crc = "",
+ md5 = "",
+ sha1 = "",
+ sha256 = "",
+ sha384 = "",
+ sha512 = "",
+ status = "";
- // Separated values should only output Rom and Disk
- if (rom.ItemType != ItemType.Disk && rom.ItemType != ItemType.Rom)
- {
- return true;
- }
+ // Separated values should only output Rom and Disk
+ if (rom.ItemType != ItemType.Disk && rom.ItemType != ItemType.Rom)
+ {
+ return true;
+ }
- if (rom.ItemType == ItemType.Rom)
- {
- type = "rom";
- romname = rom.Name;
- size = ((Rom)rom).Size.ToString();
- crc = ((Rom)rom).CRC;
- md5 = ((Rom)rom).MD5;
- sha1 = ((Rom)rom).SHA1;
- sha256 = ((Rom)rom).SHA256;
- sha384 = ((Rom)rom).SHA384;
- sha512 = ((Rom)rom).SHA512;
- status = (((Rom)rom).ItemStatus != ItemStatus.None ? "\"" + ((Rom)rom).ItemStatus.ToString() + "\"" : "\"\"");
- }
- else if (rom.ItemType == ItemType.Disk)
- {
- type = "disk";
- diskname = rom.Name;
- md5 = ((Disk)rom).MD5;
- sha1 = ((Disk)rom).SHA1;
- sha256 = ((Disk)rom).SHA256;
- sha384 = ((Disk)rom).SHA384;
- sha512 = ((Disk)rom).SHA512;
- status = (((Disk)rom).ItemStatus != ItemStatus.None ? "\"" + ((Disk)rom).ItemStatus.ToString() + "\"" : "\"\"");
- }
+ if (rom.ItemType == ItemType.Rom)
+ {
+ type = "rom";
+ romname = rom.Name;
+ size = ((Rom)rom).Size.ToString();
+ crc = ((Rom)rom).CRC;
+ md5 = ((Rom)rom).MD5;
+ sha1 = ((Rom)rom).SHA1;
+ sha256 = ((Rom)rom).SHA256;
+ sha384 = ((Rom)rom).SHA384;
+ sha512 = ((Rom)rom).SHA512;
+ status = (((Rom)rom).ItemStatus != ItemStatus.None ? "\"" + ((Rom)rom).ItemStatus.ToString() + "\"" : "\"\"");
+ }
+ else if (rom.ItemType == ItemType.Disk)
+ {
+ type = "disk";
+ diskname = rom.Name;
+ md5 = ((Disk)rom).MD5;
+ sha1 = ((Disk)rom).SHA1;
+ sha256 = ((Disk)rom).SHA256;
+ sha384 = ((Disk)rom).SHA384;
+ sha512 = ((Disk)rom).SHA512;
+ status = (((Disk)rom).ItemStatus != ItemStatus.None ? "\"" + ((Disk)rom).ItemStatus.ToString() + "\"" : "\"\"");
+ }
- pre = CreatePrefixPostfix(rom, true);
- post = CreatePrefixPostfix(rom, false);
- string inline = string.Format("\"" + FileName + "\""
- + "{0}\"" + Name + "\""
- + "{0}\"" + Description + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName : "") + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.Description] ? rom.MachineDescription : "") + "\""
- + "{0}\"" + type + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.Name] ? romname : "") + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.Name] ? diskname : "") + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.Size] ? size : "") + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.CRC] ? crc : "") + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.MD5] ? md5 : "") + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.SHA1] ? sha1 : "") + "\""
- + "{0}\"" + (!ExcludeFields[(int)Field.SHA256] ? sha256 : "") + "\""
- // + "{0}\"" + (!ExcludeFields[(int)Field.SHA384] ? sha384 : "") + "\""
- // + "{0}\"" + (!ExcludeFields[(int)Field.SHA512] ? sha512 : "") + "\""
- + "{0}" + status, _delim);
- state += pre + inline + post + "\n";
+ pre = CreatePrefixPostfix(rom, true);
+ post = CreatePrefixPostfix(rom, false);
+ string inline = string.Format("\"" + FileName + "\""
+ + "{0}\"" + Name + "\""
+ + "{0}\"" + Description + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.MachineName] ? rom.MachineName : "") + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.Description] ? rom.MachineDescription : "") + "\""
+ + "{0}\"" + type + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.Name] ? romname : "") + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.Name] ? diskname : "") + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.Size] ? size : "") + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.CRC] ? crc : "") + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.MD5] ? md5 : "") + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.SHA1] ? sha1 : "") + "\""
+ + "{0}\"" + (!ExcludeFields[(int)Field.SHA256] ? sha256 : "") + "\""
+ // + "{0}\"" + (!ExcludeFields[(int)Field.SHA384] ? sha384 : "") + "\""
+ // + "{0}\"" + (!ExcludeFields[(int)Field.SHA512] ? sha512 : "") + "\""
+ + "{0}" + status, _delim);
+ state += pre + inline + post + "\n";
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
- return true;
- }
- }
+ return true;
+ }
+ }
}
diff --git a/SabreTools.Library/DatFiles/SoftwareList.cs b/SabreTools.Library/DatFiles/SoftwareList.cs
index 3d42d8b2..0fca4983 100644
--- a/SabreTools.Library/DatFiles/SoftwareList.cs
+++ b/SabreTools.Library/DatFiles/SoftwareList.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Xml;
-
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
@@ -20,855 +19,855 @@ using NaturalSort;
namespace SabreTools.Library.DatFiles
{
- ///
- /// Represents parsing and writing of a SofwareList, M1, or MAME XML DAT
- ///
- /// TODO: Verify that all write for this DatFile type is correct
- internal class SoftwareList : DatFile
- {
- ///
- /// Constructor designed for casting a base DatFile
- ///
- /// Parent DatFile to copy from
- public SoftwareList(DatFile datFile)
- : base(datFile, cloneHeader: false)
- {
- }
-
- ///
- /// Parse an SofwareList XML DAT 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
- /// 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,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // Prepare all internal variables
- Encoding enc = Utilities.GetEncoding(filename);
- XmlReader xtr = Utilities.GetXmlTextReader(filename);
-
- // If we got a null reader, just return
- if (xtr == null)
- {
- return;
- }
-
- // Otherwise, read the file to the end
- try
- {
- xtr.MoveToContent();
- while (!xtr.EOF)
- {
- // We only want elements
- if (xtr.NodeType != XmlNodeType.Element)
- {
- xtr.Read();
- continue;
- }
-
- switch (xtr.Name)
- {
- case "softwarelist":
- Name = (String.IsNullOrWhiteSpace(Name) ? xtr.GetAttribute("name") ?? "" : Name);
- 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;
- // We want to process the entire subtree of the machine
- case "software":
- ReadSoftware(xtr.ReadSubtree(), filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the software now that we've processed it
- xtr.Skip();
- break;
- default:
- xtr.Read();
- break;
- }
- }
- }
- catch (Exception ex)
- {
- Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
-
- // For XML errors, just skip the affected node
- xtr?.Read();
- }
-
- xtr.Dispose();
- }
-
- ///
- /// Read software information
- ///
- /// XmlReader representing a software block
- /// 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 void ReadSoftware(
- XmlReader reader,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- // If we have an empty software, skip it
- if (reader == null)
- {
- return;
- }
-
- // Otherwise, add what is possible
- reader.MoveToContent();
-
- string key = "";
- string temptype = reader.Name;
- bool containsItems = false;
-
- // Create a new machine
- MachineType machineType = MachineType.NULL;
- if (Utilities.GetYesNo(reader.GetAttribute("isbios")) == true)
- {
- machineType |= MachineType.Bios;
- }
- if (Utilities.GetYesNo(reader.GetAttribute("isdevice")) == true)
- {
- machineType |= MachineType.Device;
- }
- if (Utilities.GetYesNo(reader.GetAttribute("ismechanical")) == true)
- {
- machineType |= MachineType.Mechanical;
- }
-
- Machine machine = new Machine
- {
- Name = reader.GetAttribute("name"),
- Description = reader.GetAttribute("name"),
- Supported = Utilities.GetYesNo(reader.GetAttribute("supported")), // (yes|partial|no) "yes"
-
- CloneOf = reader.GetAttribute("cloneof") ?? "",
- Infos = new List>(),
-
- MachineType = (machineType == MachineType.NULL ? MachineType.None : machineType),
- };
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the software
- switch (reader.Name)
- {
- case "description":
- machine.Description = reader.ReadElementContentAsString();
- break;
- case "year":
- machine.Year = reader.ReadElementContentAsString();
- break;
- case "publisher":
- machine.Publisher = reader.ReadElementContentAsString();
- break;
- case "info":
- machine.Infos.Add(new Tuple(reader.GetAttribute("name"), reader.GetAttribute("value")));
-
- reader.Read();
- break;
- case "sharedfeat":
- // string sharedfeat_name = reader.GetAttribute("name");
- // string sharedfeat_value = reader.GetAttribute("value");
-
- reader.Read();
- break;
- case "part": // Contains all rom and disk information
- containsItems = ReadPart(reader.ReadSubtree(), machine, filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the part now that we've processed it
- reader.Skip();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- // If no items were found for this machine, add a Blank placeholder
- if (!containsItems)
- {
- Blank blank = new Blank()
- {
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
- blank.CopyMachineInformation(machine);
-
- // Now process and add the rom
- ParseAddHelper(blank, clean, remUnicode);
- }
- }
-
- ///
- /// Read part information
- ///
- /// XmlReader representing a part block
- /// Machine information to pass to contained items
- /// 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 ReadPart(
- XmlReader reader,
- Machine machine,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- string key = "", areaname = "", partname = "", partinterface = "";
- string temptype = reader.Name;
- long? areasize = null;
- List> features = new List>();
- bool containsItems = false;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "part")
- {
- partname = "";
- partinterface = "";
- features = new List>();
- }
- if (reader.NodeType == XmlNodeType.EndElement && (reader.Name == "dataarea" || reader.Name == "diskarea"))
- {
- areaname = "";
- areasize = null;
- }
-
- reader.Read();
- continue;
- }
-
- // Get the elements from the software
- switch (reader.Name)
- {
- case "part":
- partname = reader.GetAttribute("name");
- partinterface = reader.GetAttribute("interface");
-
- reader.Read();
- break;
- case "feature":
- features.Add(new Tuple(reader.GetAttribute("name"), reader.GetAttribute("feature")));
-
- reader.Read();
- break;
- case "dataarea":
- areaname = reader.GetAttribute("name");
- if (reader.GetAttribute("size") != null)
- {
- if (Int64.TryParse(reader.GetAttribute("size"), out long tempas))
- {
- areasize = tempas;
- }
- }
- // string dataarea_width = reader.GetAttribute("width"); // (8|16|32|64) "8"
- // string dataarea_endianness = reader.GetAttribute("endianness"); // endianness (big|little) "little"
-
- containsItems = ReadDataArea(reader.ReadSubtree(), machine, features, areaname, areasize,
- partname, partinterface, filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the dataarea now that we've processed it
- reader.Skip();
- break;
- case "diskarea":
- areaname = reader.GetAttribute("name");
-
- containsItems = ReadDiskArea(reader.ReadSubtree(), machine, features, areaname, areasize,
- partname, partinterface, filename, sysid, srcid, keep, clean, remUnicode);
-
- // Skip the diskarea now that we've processed it
- reader.Skip();
- break;
- case "dipswitch":
- // string dipswitch_name = reader.GetAttribute("name");
- // string dipswitch_tag = reader.GetAttribute("tag");
- // string dipswitch_mask = reader.GetAttribute("mask");
-
- // For every element...
- // string dipvalue_name = reader.GetAttribute("name");
- // string dipvalue_value = reader.GetAttribute("value");
- // bool? dipvalue_default = Utilities.GetYesNo(reader.GetAttribute("default")); // (yes|no) "no"
-
- reader.Skip();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- return containsItems;
- }
-
- ///
- /// Read dataarea information
- ///
- /// XmlReader representing a dataarea block
- /// Machine information to pass to contained items
- /// List of features from the parent part
- /// Name of the containing area
- /// Size of the containing area
- /// Name of the containing part
- /// Interface of the containing part
- /// 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 ReadDataArea(
- XmlReader reader,
- Machine machine,
- List> features,
- string areaname,
- long? areasize,
- string partname,
- string partinterface,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- string key = "";
- string temptype = reader.Name;
- bool containsItems = false;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the software
- switch (reader.Name)
- {
- case "rom":
- containsItems = true;
-
- // If the rom is continue or ignore, add the size to the previous rom
- if (reader.GetAttribute("loadflag") == "continue" || reader.GetAttribute("loadflag") == "ignore")
- {
- int index = this[key].Count - 1;
- DatItem lastrom = this[key][index];
- if (lastrom.ItemType == ItemType.Rom)
- {
- ((Rom)lastrom).Size += Utilities.GetSize(reader.GetAttribute("size"));
- }
- this[key].RemoveAt(index);
- this[key].Add(lastrom);
- reader.Read();
- continue;
- }
-
- DatItem rom = new Rom
- {
- Name = reader.GetAttribute("name"),
- Size = Utilities.GetSize(reader.GetAttribute("size")),
- CRC = Utilities.CleanHashData(reader.GetAttribute("crc"), Constants.CRCLength),
- MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
- SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
- SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
- SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
- SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
- Offset = reader.GetAttribute("offset"),
- // Value = reader.GetAttribute("value");
- ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
- // LoadFlag = reader.GetAttribute("loadflag"), // (load16_byte|load16_word|load16_word_swap|load32_byte|load32_word|load32_word_swap|load32_dword|load64_word|load64_word_swap|reload|fill|continue|reload_plain|ignore)
-
- AreaName = areaname,
- AreaSize = areasize,
- Features = features,
- PartName = partname,
- PartInterface = partinterface,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- rom.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(rom, clean, remUnicode);
-
- reader.Read();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- return containsItems;
- }
-
- ///
- /// Read diskarea information
- ///
- /// XmlReader representing a diskarea block
- /// Machine information to pass to contained items
- /// List of features from the parent part
- /// Name of the containing area
- /// Size of the containing area
- /// Name of the containing part
- /// Interface of the containing part
- /// 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 ReadDiskArea(
- XmlReader reader,
- Machine machine,
- List> features,
- string areaname,
- long? areasize,
- string partname,
- string partinterface,
-
- // Standard Dat parsing
- string filename,
- int sysid,
- int srcid,
-
- // Miscellaneous
- bool keep,
- bool clean,
- bool remUnicode)
- {
- string key = "";
- string temptype = reader.Name;
- bool containsItems = false;
-
- while (!reader.EOF)
- {
- // We only want elements
- if (reader.NodeType != XmlNodeType.Element)
- {
- reader.Read();
- continue;
- }
-
- // Get the elements from the software
- switch (reader.Name)
- {
- case "disk":
- containsItems = true;
-
- DatItem disk = new Disk
- {
- Name = reader.GetAttribute("name"),
- MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
- SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
- SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
- SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
- SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
- ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
- Writable = Utilities.GetYesNo(reader.GetAttribute("writable")),
-
- AreaName = areaname,
- AreaSize = areasize,
- Features = features,
- PartName = partname,
- PartInterface = partinterface,
-
- SystemID = sysid,
- System = filename,
- SourceID = srcid,
- };
-
- disk.CopyMachineInformation(machine);
-
- // Now process and add the rom
- key = ParseAddHelper(disk, clean, remUnicode);
-
- reader.Read();
- break;
- default:
- reader.Read();
- break;
- }
- }
-
- return containsItems;
- }
-
- ///
- /// Create and open an output file for writing direct from a dictionary
- ///
- /// Name of the file to write to
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the DAT was written correctly, false otherwise
- public override bool WriteToFile(string outfile, bool ignoreblanks = false)
- {
- try
- {
- Globals.Logger.User("Opening file for writing: {0}", outfile);
- FileStream fs = Utilities.TryCreate(outfile);
-
- // If we get back null for some reason, just log and return
- if (fs == null)
- {
- Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
- return false;
- }
-
- StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
-
- // Write out the header
- WriteHeader(sw);
-
- // Write out each of the machines and roms
- string lastgame = null;
-
- // Get a properly sorted set of keys
- List keys = Keys;
- keys.Sort(new NaturalComparer());
-
- foreach (string key in keys)
- {
- List roms = this[key];
-
- // Resolve the names in the block
- roms = DatItem.ResolveNames(roms);
-
- for (int index = 0; index < roms.Count; index++)
- {
- DatItem rom = roms[index];
-
- // There are apparently times when a null rom can skip by, skip them
- if (rom.Name == null || rom.MachineName == null)
- {
- Globals.Logger.Warning("Null rom found!");
- continue;
- }
-
- // If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteEndGame(sw);
- }
-
- // If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
- {
- WriteStartGame(sw, rom);
- }
-
- // If we have a "null" game (created by DATFromDir or something similar), log it to file
- if (rom.ItemType == ItemType.Rom
- && ((Rom)rom).Size == -1
- && ((Rom)rom).CRC == "null")
- {
- Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
-
- lastgame = rom.MachineName;
- continue;
- }
-
- // Now, output the rom data
- WriteDatItem(sw, rom, ignoreblanks);
-
- // Set the new data to compare against
- lastgame = rom.MachineName;
- }
- }
-
- // Write the file footer out
- WriteFooter(sw);
-
- Globals.Logger.Verbose("File written!" + Environment.NewLine);
- sw.Dispose();
- fs.Dispose();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT header using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteHeader(StreamWriter sw)
- {
- try
- {
- string header = "\n" +
- "\n\n" +
- "\n\n";
-
- // Write the header out
- sw.Write(header);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if the data was written, false on error
- private bool WriteStartGame(StreamWriter sw, DatItem rom)
- {
- try
- {
- // No game should start with a path separator
- if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
- {
- rom.MachineName = rom.MachineName.Substring(1);
- }
-
- string state = "\t\n" : "")
- + (!ExcludeFields[(int)Field.Description] ? "\t\t" + HttpUtility.HtmlEncode(rom.MachineDescription) + "\n" : "")
- + (!ExcludeFields[(int)Field.Year] && rom.Year != null ? "\t\t" + HttpUtility.HtmlEncode(rom.Year) + "\n" : "")
- + (!ExcludeFields[(int)Field.Publisher] && rom.Publisher != null ? "\t\t" + HttpUtility.HtmlEncode(rom.Publisher) + "\n" : "");
-
- if (!ExcludeFields[(int)Field.Infos])
- {
- foreach (Tuple kvp in rom.Infos)
- {
- state += "\t\t\n";
- }
- }
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out Game start using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteEndGame(StreamWriter sw)
- {
- try
- {
- string state = "\t\n\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DatItem using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// DatItem object to be output
- /// True if blank roms should be skipped on output, false otherwise (default)
- /// True if the data was written, false on error
- private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
- {
- // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
- if (ignoreblanks
- && (rom.ItemType == ItemType.Rom
- && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
- {
- return true;
- }
-
- try
- {
- string state = "";
-
- // Pre-process the item name
- ProcessItemName(rom, true);
-
- state += "\t\t\n";
-
- if (!ExcludeFields[(int)Field.Features])
- {
- foreach (Tuple kvp in rom.Features)
- {
- state += "\t\t\t\n";
- }
- }
-
- switch (rom.ItemType)
- {
- case ItemType.Disk:
- state += "\t\t\t\n"
- + "\t\t\t\t\n"
- + "\t\t\t\n";
- break;
- case ItemType.Rom:
- state += "\t\t\t\n"
- + "\t\t\t\t\n"
- + "\t\t\t\n";
- break;
- }
-
- state += "\t\t\n";
-
- sw.Write(state);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write out DAT footer using the supplied StreamWriter
- ///
- /// StreamWriter to output to
- /// True if the data was written, false on error
- private bool WriteFooter(StreamWriter sw)
- {
- try
- {
- string footer = "\t\n\n\n";
-
- // Write the footer out
- sw.Write(footer);
- sw.Flush();
- }
- catch (Exception ex)
- {
- Globals.Logger.Error(ex.ToString());
- return false;
- }
-
- return true;
- }
- }
+ ///
+ /// Represents parsing and writing of a SofwareList, M1, or MAME XML DAT
+ ///
+ /// TODO: Verify that all write for this DatFile type is correct
+ internal class SoftwareList : DatFile
+ {
+ ///
+ /// Constructor designed for casting a base DatFile
+ ///
+ /// Parent DatFile to copy from
+ public SoftwareList(DatFile datFile)
+ : base(datFile, cloneHeader: false)
+ {
+ }
+
+ ///
+ /// Parse an SofwareList XML DAT 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
+ /// 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,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // Prepare all internal variables
+ Encoding enc = Utilities.GetEncoding(filename);
+ XmlReader xtr = Utilities.GetXmlTextReader(filename);
+
+ // If we got a null reader, just return
+ if (xtr == null)
+ {
+ return;
+ }
+
+ // Otherwise, read the file to the end
+ try
+ {
+ xtr.MoveToContent();
+ while (!xtr.EOF)
+ {
+ // We only want elements
+ if (xtr.NodeType != XmlNodeType.Element)
+ {
+ xtr.Read();
+ continue;
+ }
+
+ switch (xtr.Name)
+ {
+ case "softwarelist":
+ Name = (String.IsNullOrWhiteSpace(Name) ? xtr.GetAttribute("name") ?? "" : Name);
+ 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;
+ // We want to process the entire subtree of the machine
+ case "software":
+ ReadSoftware(xtr.ReadSubtree(), filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the software now that we've processed it
+ xtr.Skip();
+ break;
+ default:
+ xtr.Read();
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Warning("Exception found while parsing '{0}': {1}", filename, ex);
+
+ // For XML errors, just skip the affected node
+ xtr?.Read();
+ }
+
+ xtr.Dispose();
+ }
+
+ ///
+ /// Read software information
+ ///
+ /// XmlReader representing a software block
+ /// 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 void ReadSoftware(
+ XmlReader reader,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ // If we have an empty software, skip it
+ if (reader == null)
+ {
+ return;
+ }
+
+ // Otherwise, add what is possible
+ reader.MoveToContent();
+
+ string key = "";
+ string temptype = reader.Name;
+ bool containsItems = false;
+
+ // Create a new machine
+ MachineType machineType = MachineType.NULL;
+ if (Utilities.GetYesNo(reader.GetAttribute("isbios")) == true)
+ {
+ machineType |= MachineType.Bios;
+ }
+ if (Utilities.GetYesNo(reader.GetAttribute("isdevice")) == true)
+ {
+ machineType |= MachineType.Device;
+ }
+ if (Utilities.GetYesNo(reader.GetAttribute("ismechanical")) == true)
+ {
+ machineType |= MachineType.Mechanical;
+ }
+
+ Machine machine = new Machine
+ {
+ Name = reader.GetAttribute("name"),
+ Description = reader.GetAttribute("name"),
+ Supported = Utilities.GetYesNo(reader.GetAttribute("supported")), // (yes|partial|no) "yes"
+
+ CloneOf = reader.GetAttribute("cloneof") ?? "",
+ Infos = new List>(),
+
+ MachineType = (machineType == MachineType.NULL ? MachineType.None : machineType),
+ };
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the elements from the software
+ switch (reader.Name)
+ {
+ case "description":
+ machine.Description = reader.ReadElementContentAsString();
+ break;
+ case "year":
+ machine.Year = reader.ReadElementContentAsString();
+ break;
+ case "publisher":
+ machine.Publisher = reader.ReadElementContentAsString();
+ break;
+ case "info":
+ machine.Infos.Add(new Tuple(reader.GetAttribute("name"), reader.GetAttribute("value")));
+
+ reader.Read();
+ break;
+ case "sharedfeat":
+ // string sharedfeat_name = reader.GetAttribute("name");
+ // string sharedfeat_value = reader.GetAttribute("value");
+
+ reader.Read();
+ break;
+ case "part": // Contains all rom and disk information
+ containsItems = ReadPart(reader.ReadSubtree(), machine, filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the part now that we've processed it
+ reader.Skip();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ // If no items were found for this machine, add a Blank placeholder
+ if (!containsItems)
+ {
+ Blank blank = new Blank()
+ {
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+ blank.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ ParseAddHelper(blank, clean, remUnicode);
+ }
+ }
+
+ ///
+ /// Read part information
+ ///
+ /// XmlReader representing a part block
+ /// Machine information to pass to contained items
+ /// 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 ReadPart(
+ XmlReader reader,
+ Machine machine,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ string key = "", areaname = "", partname = "", partinterface = "";
+ string temptype = reader.Name;
+ long? areasize = null;
+ List> features = new List>();
+ bool containsItems = false;
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "part")
+ {
+ partname = "";
+ partinterface = "";
+ features = new List>();
+ }
+ if (reader.NodeType == XmlNodeType.EndElement && (reader.Name == "dataarea" || reader.Name == "diskarea"))
+ {
+ areaname = "";
+ areasize = null;
+ }
+
+ reader.Read();
+ continue;
+ }
+
+ // Get the elements from the software
+ switch (reader.Name)
+ {
+ case "part":
+ partname = reader.GetAttribute("name");
+ partinterface = reader.GetAttribute("interface");
+
+ reader.Read();
+ break;
+ case "feature":
+ features.Add(new Tuple(reader.GetAttribute("name"), reader.GetAttribute("feature")));
+
+ reader.Read();
+ break;
+ case "dataarea":
+ areaname = reader.GetAttribute("name");
+ if (reader.GetAttribute("size") != null)
+ {
+ if (Int64.TryParse(reader.GetAttribute("size"), out long tempas))
+ {
+ areasize = tempas;
+ }
+ }
+ // string dataarea_width = reader.GetAttribute("width"); // (8|16|32|64) "8"
+ // string dataarea_endianness = reader.GetAttribute("endianness"); // endianness (big|little) "little"
+
+ containsItems = ReadDataArea(reader.ReadSubtree(), machine, features, areaname, areasize,
+ partname, partinterface, filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the dataarea now that we've processed it
+ reader.Skip();
+ break;
+ case "diskarea":
+ areaname = reader.GetAttribute("name");
+
+ containsItems = ReadDiskArea(reader.ReadSubtree(), machine, features, areaname, areasize,
+ partname, partinterface, filename, sysid, srcid, keep, clean, remUnicode);
+
+ // Skip the diskarea now that we've processed it
+ reader.Skip();
+ break;
+ case "dipswitch":
+ // string dipswitch_name = reader.GetAttribute("name");
+ // string dipswitch_tag = reader.GetAttribute("tag");
+ // string dipswitch_mask = reader.GetAttribute("mask");
+
+ // For every element...
+ // string dipvalue_name = reader.GetAttribute("name");
+ // string dipvalue_value = reader.GetAttribute("value");
+ // bool? dipvalue_default = Utilities.GetYesNo(reader.GetAttribute("default")); // (yes|no) "no"
+
+ reader.Skip();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ return containsItems;
+ }
+
+ ///
+ /// Read dataarea information
+ ///
+ /// XmlReader representing a dataarea block
+ /// Machine information to pass to contained items
+ /// List of features from the parent part
+ /// Name of the containing area
+ /// Size of the containing area
+ /// Name of the containing part
+ /// Interface of the containing part
+ /// 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 ReadDataArea(
+ XmlReader reader,
+ Machine machine,
+ List> features,
+ string areaname,
+ long? areasize,
+ string partname,
+ string partinterface,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ string key = "";
+ string temptype = reader.Name;
+ bool containsItems = false;
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the elements from the software
+ switch (reader.Name)
+ {
+ case "rom":
+ containsItems = true;
+
+ // If the rom is continue or ignore, add the size to the previous rom
+ if (reader.GetAttribute("loadflag") == "continue" || reader.GetAttribute("loadflag") == "ignore")
+ {
+ int index = this[key].Count - 1;
+ DatItem lastrom = this[key][index];
+ if (lastrom.ItemType == ItemType.Rom)
+ {
+ ((Rom)lastrom).Size += Utilities.GetSize(reader.GetAttribute("size"));
+ }
+ this[key].RemoveAt(index);
+ this[key].Add(lastrom);
+ reader.Read();
+ continue;
+ }
+
+ DatItem rom = new Rom
+ {
+ Name = reader.GetAttribute("name"),
+ Size = Utilities.GetSize(reader.GetAttribute("size")),
+ CRC = Utilities.CleanHashData(reader.GetAttribute("crc"), Constants.CRCLength),
+ MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
+ SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
+ SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
+ SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
+ SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
+ Offset = reader.GetAttribute("offset"),
+ // Value = reader.GetAttribute("value");
+ ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
+ // LoadFlag = reader.GetAttribute("loadflag"), // (load16_byte|load16_word|load16_word_swap|load32_byte|load32_word|load32_word_swap|load32_dword|load64_word|load64_word_swap|reload|fill|continue|reload_plain|ignore)
+
+ AreaName = areaname,
+ AreaSize = areasize,
+ Features = features,
+ PartName = partname,
+ PartInterface = partinterface,
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ rom.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(rom, clean, remUnicode);
+
+ reader.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ return containsItems;
+ }
+
+ ///
+ /// Read diskarea information
+ ///
+ /// XmlReader representing a diskarea block
+ /// Machine information to pass to contained items
+ /// List of features from the parent part
+ /// Name of the containing area
+ /// Size of the containing area
+ /// Name of the containing part
+ /// Interface of the containing part
+ /// 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 ReadDiskArea(
+ XmlReader reader,
+ Machine machine,
+ List> features,
+ string areaname,
+ long? areasize,
+ string partname,
+ string partinterface,
+
+ // Standard Dat parsing
+ string filename,
+ int sysid,
+ int srcid,
+
+ // Miscellaneous
+ bool keep,
+ bool clean,
+ bool remUnicode)
+ {
+ string key = "";
+ string temptype = reader.Name;
+ bool containsItems = false;
+
+ while (!reader.EOF)
+ {
+ // We only want elements
+ if (reader.NodeType != XmlNodeType.Element)
+ {
+ reader.Read();
+ continue;
+ }
+
+ // Get the elements from the software
+ switch (reader.Name)
+ {
+ case "disk":
+ containsItems = true;
+
+ DatItem disk = new Disk
+ {
+ Name = reader.GetAttribute("name"),
+ MD5 = Utilities.CleanHashData(reader.GetAttribute("md5"), Constants.MD5Length),
+ SHA1 = Utilities.CleanHashData(reader.GetAttribute("sha1"), Constants.SHA1Length),
+ SHA256 = Utilities.CleanHashData(reader.GetAttribute("sha256"), Constants.SHA256Length),
+ SHA384 = Utilities.CleanHashData(reader.GetAttribute("sha384"), Constants.SHA384Length),
+ SHA512 = Utilities.CleanHashData(reader.GetAttribute("sha512"), Constants.SHA512Length),
+ ItemStatus = Utilities.GetItemStatus(reader.GetAttribute("status")),
+ Writable = Utilities.GetYesNo(reader.GetAttribute("writable")),
+
+ AreaName = areaname,
+ AreaSize = areasize,
+ Features = features,
+ PartName = partname,
+ PartInterface = partinterface,
+
+ SystemID = sysid,
+ System = filename,
+ SourceID = srcid,
+ };
+
+ disk.CopyMachineInformation(machine);
+
+ // Now process and add the rom
+ key = ParseAddHelper(disk, clean, remUnicode);
+
+ reader.Read();
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+
+ return containsItems;
+ }
+
+ ///
+ /// Create and open an output file for writing direct from a dictionary
+ ///
+ /// Name of the file to write to
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the DAT was written correctly, false otherwise
+ public override bool WriteToFile(string outfile, bool ignoreblanks = false)
+ {
+ try
+ {
+ Globals.Logger.User("Opening file for writing: {0}", outfile);
+ FileStream fs = Utilities.TryCreate(outfile);
+
+ // If we get back null for some reason, just log and return
+ if (fs == null)
+ {
+ Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
+ return false;
+ }
+
+ StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
+
+ // Write out the header
+ WriteHeader(sw);
+
+ // Write out each of the machines and roms
+ string lastgame = null;
+
+ // Get a properly sorted set of keys
+ List keys = Keys;
+ keys.Sort(new NaturalComparer());
+
+ foreach (string key in keys)
+ {
+ List roms = this[key];
+
+ // Resolve the names in the block
+ roms = DatItem.ResolveNames(roms);
+
+ for (int index = 0; index < roms.Count; index++)
+ {
+ DatItem rom = roms[index];
+
+ // There are apparently times when a null rom can skip by, skip them
+ if (rom.Name == null || rom.MachineName == null)
+ {
+ Globals.Logger.Warning("Null rom found!");
+ continue;
+ }
+
+ // If we have a different game and we're not at the start of the list, output the end of last item
+ if (lastgame != null && lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteEndGame(sw);
+ }
+
+ // If we have a new game, output the beginning of the new item
+ if (lastgame == null || lastgame.ToLowerInvariant() != rom.MachineName.ToLowerInvariant())
+ {
+ WriteStartGame(sw, rom);
+ }
+
+ // If we have a "null" game (created by DATFromDir or something similar), log it to file
+ if (rom.ItemType == ItemType.Rom
+ && ((Rom)rom).Size == -1
+ && ((Rom)rom).CRC == "null")
+ {
+ Globals.Logger.Verbose("Empty folder found: {0}", rom.MachineName);
+
+ lastgame = rom.MachineName;
+ continue;
+ }
+
+ // Now, output the rom data
+ WriteDatItem(sw, rom, ignoreblanks);
+
+ // Set the new data to compare against
+ lastgame = rom.MachineName;
+ }
+ }
+
+ // Write the file footer out
+ WriteFooter(sw);
+
+ Globals.Logger.Verbose("File written!" + Environment.NewLine);
+ sw.Dispose();
+ fs.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT header using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteHeader(StreamWriter sw)
+ {
+ try
+ {
+ string header = "\n" +
+ "\n\n" +
+ "\n\n";
+
+ // Write the header out
+ sw.Write(header);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if the data was written, false on error
+ private bool WriteStartGame(StreamWriter sw, DatItem rom)
+ {
+ try
+ {
+ // No game should start with a path separator
+ if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ rom.MachineName = rom.MachineName.Substring(1);
+ }
+
+ string state = "\t\n" : "")
+ + (!ExcludeFields[(int)Field.Description] ? "\t\t" + HttpUtility.HtmlEncode(rom.MachineDescription) + "\n" : "")
+ + (!ExcludeFields[(int)Field.Year] && rom.Year != null ? "\t\t" + HttpUtility.HtmlEncode(rom.Year) + "\n" : "")
+ + (!ExcludeFields[(int)Field.Publisher] && rom.Publisher != null ? "\t\t" + HttpUtility.HtmlEncode(rom.Publisher) + "\n" : "");
+
+ if (!ExcludeFields[(int)Field.Infos])
+ {
+ foreach (Tuple kvp in rom.Infos)
+ {
+ state += "\t\t\n";
+ }
+ }
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out Game start using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteEndGame(StreamWriter sw)
+ {
+ try
+ {
+ string state = "\t\n\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DatItem using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// DatItem object to be output
+ /// True if blank roms should be skipped on output, false otherwise (default)
+ /// True if the data was written, false on error
+ private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
+ {
+ // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
+ if (ignoreblanks
+ && (rom.ItemType == ItemType.Rom
+ && (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
+ {
+ return true;
+ }
+
+ try
+ {
+ string state = "";
+
+ // Pre-process the item name
+ ProcessItemName(rom, true);
+
+ state += "\t\t\n";
+
+ if (!ExcludeFields[(int)Field.Features])
+ {
+ foreach (Tuple kvp in rom.Features)
+ {
+ state += "\t\t\t\n";
+ }
+ }
+
+ switch (rom.ItemType)
+ {
+ case ItemType.Disk:
+ state += "\t\t\t\n"
+ + "\t\t\t\t\n"
+ + "\t\t\t\n";
+ break;
+ case ItemType.Rom:
+ state += "\t\t\t\n"
+ + "\t\t\t\t\n"
+ + "\t\t\t\n";
+ break;
+ }
+
+ state += "\t\t\n";
+
+ sw.Write(state);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Write out DAT footer using the supplied StreamWriter
+ ///
+ /// StreamWriter to output to
+ /// True if the data was written, false on error
+ private bool WriteFooter(StreamWriter sw)
+ {
+ try
+ {
+ string footer = "\t\n\n\n";
+
+ // Write the footer out
+ sw.Write(footer);
+ sw.Flush();
+ }
+ catch (Exception ex)
+ {
+ Globals.Logger.Error(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+ }
}