using System; using System.Collections.Generic; using System.Threading.Tasks; using SabreTools.Core; using SabreTools.IO; using SabreTools.Logging; // This file represents all methods related to writing to a file namespace SabreTools.DatFiles { public class Writer { #region Logging /// /// Logging object /// private static readonly Logger logger = new Logger(); #endregion /// /// Create and open an output file for writing direct from a dictionary /// /// Current DatFile object to write from /// Set the output directory (current directory on null) /// True if files should be overwritten (default), false if they should be renamed instead /// True if blank roms should be skipped on output, false otherwise (default) /// True if quotes are assumed in supported types (default), false otherwise /// True if the error that is thrown should be thrown back to the caller, false otherwise /// True if the DAT was written correctly, false otherwise public static bool Write( DatFile datFile, string outDir, bool overwrite = true, bool ignoreblanks = false, bool quotes = true, bool throwOnError = false) { // If we have nothing writable, abort if (!HasWritable(datFile)) { logger.User("There were no items to write out!"); return false; } // Ensure the output directory is set and created outDir = DirectoryExtensions.Ensure(outDir, create: true); // If the DAT has no output format, default to XML if (datFile.Header.DatFormat == 0) { logger.Verbose("No DAT format defined, defaulting to XML"); datFile.Header.DatFormat = DatFormat.Logiqx; } // Make sure that the three essential fields are filled in EnsureHeaderFields(datFile); // Bucket roms by game name, if not already datFile.Items.BucketBy(Field.Machine_Name, DedupeType.None); // Output the number of items we're going to be writing logger.User($"A total of {datFile.Items.TotalCount - datFile.Items.RemovedCount} items will be written out to '{datFile.Header.FileName}'"); // Get the outfile names Dictionary outfiles = datFile.Header.CreateOutFileNames(outDir, overwrite); try { // Write out all required formats Parallel.ForEach(outfiles.Keys, Globals.ParallelOptions, datFormat => { string outfile = outfiles[datFormat]; try { DatFile.Create(datFormat, datFile, quotes)?.WriteToFile(outfile, ignoreblanks, throwOnError); } catch (Exception ex) { logger.Error(ex, $"Datfile {outfile} could not be written out"); if (throwOnError) throw ex; } }); } catch (Exception ex) { logger.Error(ex); if (throwOnError) throw ex; return false; } return true; } /// /// Ensure that FileName, Name, and Description are filled with some value /// /// Current DatFile object to write from private static void EnsureHeaderFields(DatFile datFile) { // Empty FileName if (string.IsNullOrWhiteSpace(datFile.Header.FileName)) { if (string.IsNullOrWhiteSpace(datFile.Header.Name) && string.IsNullOrWhiteSpace(datFile.Header.Description)) datFile.Header.FileName = datFile.Header.Name = datFile.Header.Description = "Default"; else if (string.IsNullOrWhiteSpace(datFile.Header.Name) && !string.IsNullOrWhiteSpace(datFile.Header.Description)) datFile.Header.FileName = datFile.Header.Name = datFile.Header.Description; else if (!string.IsNullOrWhiteSpace(datFile.Header.Name) && string.IsNullOrWhiteSpace(datFile.Header.Description)) datFile.Header.FileName = datFile.Header.Description = datFile.Header.Name; else if (!string.IsNullOrWhiteSpace(datFile.Header.Name) && !string.IsNullOrWhiteSpace(datFile.Header.Description)) datFile.Header.FileName = datFile.Header.Description; } // Filled FileName else { if (string.IsNullOrWhiteSpace(datFile.Header.Name) && string.IsNullOrWhiteSpace(datFile.Header.Description)) datFile.Header.Name = datFile.Header.Description = datFile.Header.FileName; else if (string.IsNullOrWhiteSpace(datFile.Header.Name) && !string.IsNullOrWhiteSpace(datFile.Header.Description)) datFile.Header.Name = datFile.Header.Description; else if (!string.IsNullOrWhiteSpace(datFile.Header.Name) && string.IsNullOrWhiteSpace(datFile.Header.Description)) datFile.Header.Description = datFile.Header.Name; } } /// /// Get if the DatFile has any writable items /// /// Current DatFile object to write from /// True if there are any writable items, false otherwise private static bool HasWritable(DatFile datFile) { // Force a statistics recheck, just in case datFile.Items.RecalculateStats(); // If there's nothing there, abort if (datFile.Items.TotalCount == 0) return false; // If every item is removed, abort if (datFile.Items.TotalCount == datFile.Items.RemovedCount) return false; return true; } } }