using System; using System.Collections.Generic; using Mono.Data.Sqlite; using System.IO; using System.Linq; using System.Text; using System.Web; namespace SabreTools.Helper { public class Output { /// /// Create and open an output file for writing /// /// Internal name of the DAT /// Description and external name of the DAT /// Version or iteration of the DAT /// Usually the DAT creation date /// Category of the DAT /// DAT author /// Force all sets to be unzipped /// Set output mode to old-style DAT /// Set the output directory /// List of RomData objects representing the games to be written out /// Logger object for console and/or file output /// Tru if the DAT was written correctly, false otherwise public static bool WriteToDat(string name, string description, string version, string date, string category, string author, bool forceunpack, bool old, string outDir, List roms, Logger logger) { // If it's empty, use the current folder if (outDir.Trim() == "") { outDir = Environment.CurrentDirectory; } // Double check the outdir for the end delim if (!outDir.EndsWith(Path.DirectorySeparatorChar.ToString())) { outDir += Path.DirectorySeparatorChar; } // (currently uses current time, change to "last updated time") logger.User("Opening file for writing: " + outDir + description + (old ? ".dat" : ".xml")); try { FileStream fs = File.Create(outDir + description + (old ? ".dat" : ".xml")); StreamWriter sw = new StreamWriter(fs, Encoding.UTF8); string header_old = "clrmamepro (\n" + "\tname \"" + HttpUtility.HtmlEncode(name) + "\"\n" + "\tdescription \"" + HttpUtility.HtmlEncode(description) + "\"\n" + "\tcategory \"" + HttpUtility.HtmlEncode(category) + "\"\n" + "\tversion \"" + HttpUtility.HtmlEncode(version) + "\"\n" + "\tdate \"" + HttpUtility.HtmlEncode(date) + "\"\n" + "\tauthor \"" + HttpUtility.HtmlEncode(author) + "\"\n" + (forceunpack ? "\tforcezipping no\n" : "") + ")\n"; string header = "\n" + "\n\n" + "\n" + "\t
\n" + "\t\t" + HttpUtility.HtmlEncode(name) + "\n" + "\t\t" + HttpUtility.HtmlEncode(description) + "\n" + "\t\t" + HttpUtility.HtmlEncode(category) + "\n" + "\t\t" + HttpUtility.HtmlEncode(version) + "\n" + "\t\t" + HttpUtility.HtmlEncode(date) + "\n" + "\t\t" + HttpUtility.HtmlEncode(author) + "\n" + (forceunpack ? "\t\t\n" : "") + "\t
\n"; // Write the header out sw.Write((old ? header_old : header)); // Write out each of the machines and roms string lastgame = null; foreach (RomData rom in roms) { string state = ""; if (lastgame != null && lastgame != rom.Game) { state += (old ? ")\n" : "\t\n"); } if (lastgame != rom.Game) { state += (old ? "game (\n\tname \"" + rom.Game + "\"\n" + "\tdescription \"" + rom.Game + "\"\n" : "\t\n" + "\t\t" + HttpUtility.HtmlEncode(rom.Game) + "\n"); } if (old) { state += "\t" + rom.Type + " ( name \"" + rom.Name + "\"" + (rom.Size != -1 && rom.Size != 0 && rom.CRC != RomManipulation.CRCZero && rom.MD5 != RomManipulation.MD5Zero && rom.SHA1 != RomManipulation.SHA1Zero ? " size " + rom.Size : "") + (rom.CRC != "" ? " crc " + rom.CRC.ToLowerInvariant() : "") + (rom.MD5 != "" ? " md5 " + rom.MD5.ToLowerInvariant() : "") + (rom.SHA1 != "" ? " sha1 " + rom.SHA1.ToLowerInvariant() : "") + " )\n"; } else { state += "\t\t<" + rom.Type + " name=\"" + HttpUtility.HtmlEncode(rom.Name) + "\"" + (rom.Size != -1 && rom.Size != 0 && rom.CRC != RomManipulation.CRCZero && rom.MD5 != RomManipulation.MD5Zero && rom.SHA1 != RomManipulation.SHA1Zero ? " size=\"" + rom.Size + "\"" : "") + (rom.CRC != "" ? " crc=\"" + rom.CRC.ToLowerInvariant() + "\"" : "") + (rom.MD5 != "" ? " md5=\"" + rom.MD5.ToLowerInvariant() + "\"" : "") + (rom.SHA1 != "" ? " sha1=\"" + rom.SHA1.ToLowerInvariant() + "\"" : "") + "/>\n"; } lastgame = rom.Game; sw.Write(state); } sw.Write((old ? ")" : "\t\n
")); logger.User("File written!" + Environment.NewLine); sw.Close(); fs.Close(); } catch (Exception ex) { logger.Error(ex.ToString()); return false; } return true; } /// /// Create and open an output file for writing direct from a dictionary /// /// All information for creating the datfile header /// Enable output in merged mode (one game per hash) /// Set the output directory /// Dictionary containing all the roms to be written /// Logger object for console and/or file output /// True if games should only be compared on game and file name (default), false if system and source are counted /// True if the DAT was written correctly, false otherwise /// /// The following features have been requested for file output: /// - Have the ability to add a comment field /// - Have the ability to strip special (non-ASCII) characters from rom information /// - Add a flag for ignoring roms with blank sizes /// public static bool WriteToDatFromDict(DatData datdata, bool merge, string outDir, Dictionary> dict, Logger logger, bool norename = true) { // Get all values in the dictionary and write out SortedDictionary> sortable = new SortedDictionary>(); long count = 0; foreach (List roms in dict.Values) { List newroms = roms; if (merge) { newroms = RomManipulation.Merge(newroms); } foreach (RomData rom in newroms) { count++; string key = (norename ? "" : rom.SystemID.ToString().PadLeft(10, '0') + "-" + rom.SourceID.ToString().PadLeft(10, '0') + "-") + rom.Game.ToLowerInvariant(); if (sortable.ContainsKey(key)) { sortable[key].Add(rom); } else { List temp = new List(); temp.Add(rom); sortable.Add(key, temp); } } } logger.Log("A total of " + count + " file hashes will be written out to file"); // Now write out to file // If it's empty, use the current folder if (outDir.Trim() == "") { outDir = Environment.CurrentDirectory; } // Double check the outdir for the end delim if (!outDir.EndsWith(Path.DirectorySeparatorChar.ToString())) { outDir += Path.DirectorySeparatorChar; } // (currently uses current time, change to "last updated time") logger.User("Opening file for writing: " + outDir + datdata.Description + (datdata.OutputFormat == OutputFormat.ClrMamePro ? ".dat" : ".xml")); try { FileStream fs = File.Create(outDir + datdata.Description + (datdata.OutputFormat == OutputFormat.ClrMamePro ? ".dat" : ".xml")); StreamWriter sw = new StreamWriter(fs, Encoding.UTF8); string header_old = "clrmamepro (\n" + "\tname \"" + HttpUtility.HtmlEncode(datdata.Name) + "\"\n" + "\tdescription \"" + HttpUtility.HtmlEncode(datdata.Description) + "\"\n" + "\tcategory \"" + HttpUtility.HtmlEncode(datdata.Category) + "\"\n" + "\tversion \"" + HttpUtility.HtmlEncode(datdata.Version) + "\"\n" + "\tdate \"" + HttpUtility.HtmlEncode(datdata.Date) + "\"\n" + "\tauthor \"" + HttpUtility.HtmlEncode(datdata.Author) + "\"\n" + (datdata.ForcePacking == ForcePacking.Unzip ? "\tforcezipping no\n" : "") + ")\n"; string header = "\n" + "\n\n" + "\n" + "\t
\n" + "\t\t" + HttpUtility.HtmlEncode(datdata.Name) + "\n" + "\t\t" + HttpUtility.HtmlEncode(datdata.Description) + "\n" + "\t\t" + HttpUtility.HtmlEncode(datdata.Category) + "\n" + "\t\t" + HttpUtility.HtmlEncode(datdata.Version) + "\n" + "\t\t" + HttpUtility.HtmlEncode(datdata.Date) + "\n" + "\t\t" + HttpUtility.HtmlEncode(datdata.Author) + "\n" + (datdata.ForcePacking == ForcePacking.Unzip ? "\t\t\n" : "") + "\t
\n"; // Write the header out sw.Write((datdata.OutputFormat == OutputFormat.ClrMamePro ? header_old : header)); // Write out each of the machines and roms string lastgame = null; foreach (List roms in sortable.Values) { foreach (RomData rom in roms) { string state = ""; if (lastgame != null && lastgame.ToLowerInvariant() != rom.Game.ToLowerInvariant()) { state += (datdata.OutputFormat == OutputFormat.ClrMamePro ? ")\n" : "\t\n"); } if (lastgame == null || lastgame.ToLowerInvariant() != rom.Game.ToLowerInvariant()) { state += (datdata.OutputFormat == OutputFormat.ClrMamePro ? "game (\n\tname \"" + rom.Game + "\"\n" + "\tdescription \"" + rom.Game + "\"\n" : "\t\n" + "\t\t" + HttpUtility.HtmlEncode(rom.Game) + "\n"); } if (datdata.OutputFormat == OutputFormat.ClrMamePro) { state += "\t" + rom.Type + " ( name \"" + rom.Name + "\"" + (rom.Size != 0 ? " size " + rom.Size : "") + (rom.CRC != "" ? " crc " + rom.CRC.ToLowerInvariant() : "") + (rom.MD5 != "" ? " md5 " + rom.MD5.ToLowerInvariant() : "") + (rom.SHA1 != "" ? " sha1 " + rom.SHA1.ToLowerInvariant() : "") + " )\n"; } else { state += "\t\t<" + rom.Type + " name=\"" + HttpUtility.HtmlEncode(rom.Name) + "\"" + (rom.Size != -1 ? " size=\"" + rom.Size + "\"" : "") + (rom.CRC != "" ? " crc=\"" + rom.CRC.ToLowerInvariant() + "\"" : "") + (rom.MD5 != "" ? " md5=\"" + rom.MD5.ToLowerInvariant() + "\"" : "") + (rom.SHA1 != "" ? " sha1=\"" + rom.SHA1.ToLowerInvariant() + "\"" : "") + "/>\n"; } lastgame = rom.Game; sw.Write(state); } } sw.Write((datdata.OutputFormat == OutputFormat.ClrMamePro ? ")" : "\t\n
")); logger.User("File written!" + Environment.NewLine); sw.Close(); fs.Close(); } catch (Exception ex) { logger.Error(ex.ToString()); return false; } return true; } /// /// Output a list of roms as a text file with an arbitrary prefix and postfix /// /// Name of the output file /// Output directory for the miss file /// List of RomData objects representing the roms to be output /// Logger object for console and/or file output /// True if only games are written to text file (default), false for files only /// Arbitrary string to prefix each line /// Arbitrary string to postfix each line /// True if quotes should be put around the item, false otherwise (default) /// Arbitrary extension added to the end of each item /// Arbitrary extension to replace all extensions in the item /// True if the game name is appended (only when !usegame), false otherwise /// True if the file was written, false otherwise /// /// The following features have been requested for this method: /// - Have switch for automatically outputting to Romba format: /// e.g. /aa/bb/cc/dd/aabbccddef770b06131a878b46d4302ac28dd126.gz /// Anything without a SHA-1 has to be skipped /// public static bool WriteToText(string textfile, string outdir, List roms, Logger logger, bool useGame = true, string prefix = "", string postfix = "", string addext = "", string repext = "", bool quotes = false, bool gamename = false) { // Normalize the output directory if (outdir == "") { outdir = Environment.CurrentDirectory; } if (!outdir.EndsWith(Path.DirectorySeparatorChar.ToString())) { outdir += Path.DirectorySeparatorChar; } // Make the output directory if it doesn't exist if (!Directory.Exists(outdir)) { Directory.CreateDirectory(outdir); } // Normalize the extensions addext = (addext == "" || addext.StartsWith(".") ? addext : "." + addext); repext = (repext == "" || repext.StartsWith(".") ? repext : "." + repext); logger.User("Opening file for writing: " + outdir + textfile); try { FileStream fs = File.Create(outdir + textfile); StreamWriter sw = new StreamWriter(fs, Encoding.UTF8); string lastgame = ""; foreach (RomData rom in roms) { string pre = prefix + (quotes ? "\"" : ""); string post = (quotes ? "\"" : "") + postfix; string name = (useGame ? rom.Game : rom.Name); if (repext != "") { string dir = Path.GetDirectoryName(name); dir = (dir.EndsWith(Path.DirectorySeparatorChar.ToString()) ? dir : dir + Path.DirectorySeparatorChar); dir = (dir.StartsWith(Path.DirectorySeparatorChar.ToString()) ? dir.Remove(0, 1) : dir); name = dir + Path.GetFileNameWithoutExtension(name) + repext; } if (addext != "") { name += addext; } if (!useGame && gamename) { name = (rom.Game.EndsWith(Path.DirectorySeparatorChar.ToString()) ? rom.Game : rom.Game + Path.DirectorySeparatorChar) + name; } if (useGame && rom.Game != lastgame) { sw.WriteLine(pre + name + post); lastgame = rom.Game; } else if (!useGame) { sw.WriteLine(pre + name + post); } } logger.User("File written!" + Environment.NewLine); sw.Close(); fs.Close(); } catch (Exception ex) { logger.Error(ex.ToString()); return false; } return true; } /// /// Convert a List of RomData objects to a List of tab-deliminated strings /// /// List of RomData objects representing the roms to be parsed /// List of Strings representing the roms public static List RomDataToString(List roms) { List outlist = new List(); foreach (RomData rom in roms) { outlist.Add(rom.Manufacturer + "\t" + rom.System + "\t" + rom.SystemID + "\t" + rom.Source + "\t" + rom.URL + "\t" + rom.SourceID + "\t" + rom.Game + "\t" + rom.Name + "\t" + rom.Type + "\t" + rom.Size + "\t" + rom.CRC + "\t" + rom.MD5 + "\t" + rom.SHA1); } return outlist; } /// /// Convert a List of RomData objects' hash information to a List of tab-deliminated strings /// /// List of RomData objects representing the roms to be parsed /// List of Strings representing the rom hashes public static List HashDataToString(List roms) { List outlist = new List(); foreach (RomData rom in roms) { outlist.Add(rom.Size + "\t" + rom.CRC + "\t" + rom.MD5 + "\t" + rom.SHA1); } return outlist; } /// /// Convert a List of tab-deliminated strings objects to a List of RomData objects /// /// List of Strings representing the roms to be parsed /// List of RomData objects representing the roms public static List StringToRomData(List roms) { List outlist = new List(); foreach (String rom in roms) { string[] temp = rom.Split('\t'); try { outlist.Add(new RomData { Manufacturer = temp[0], System = temp[1], SystemID = Int32.Parse(temp[2]), Source = temp[3], URL = temp[4], SourceID = Int32.Parse(temp[5]), Game = temp[6], Name = temp[7], Type = temp[8], Size = Int64.Parse(temp[9]), CRC = temp[10], MD5 = temp[11], SHA1 = temp[12], }); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } return outlist; } } }