using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using SabreTools.Library.Data; using SabreTools.Library.DatItems; using SabreTools.Library.IO; 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) { } /// /// Parse an AttractMode DAT and return all found games within /// /// Name of the file to be parsed /// Index ID for the DAT /// True if full pathnames are to be kept, false otherwise (default) protected override void ParseFile(string filename, int indexId, bool keep) { // Open a file reader Encoding enc = FileExtensions.GetEncoding(filename); StreamReader sr = new StreamReader(FileExtensions.TryOpenRead(filename), enc); 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 */ string[] gameinfo = line.Split(';'); Rom rom = new Rom { Name = "-", Size = Constants.SizeZero, CRC = Constants.CRCZero, MD5 = Constants.MD5Zero, #if NET_FRAMEWORK RIPEMD160 = Constants.RIPEMD160Zero, #endif SHA1 = Constants.SHA1Zero, ItemStatus = ItemStatus.None, Machine = new Machine { Name = gameinfo[0], Description = gameinfo[1], CloneOf = gameinfo[3], Year = gameinfo[4], Manufacturer = gameinfo[5], Category = gameinfo[6], Players = gameinfo[7], Rotation = gameinfo[8], Control = gameinfo[9], Status = gameinfo[10], DisplayCount = gameinfo[11], DisplayType = gameinfo[12], Comment = gameinfo[15], Buttons = gameinfo[16], }, AltName = gameinfo[13], AltTitle = gameinfo[14], Source = new Source { Index = indexId, Name = filename, }, }; // Now process and add the rom ParseAddHelper(rom); } 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: {outfile}"); FileStream fs = FileExtensions.TryCreate(outfile); // If we get back null for some reason, just log and return if (fs == null) { Globals.Logger.Warning($"File '{outfile}' could not be created for writing! Please check to see if the file is writable"); return false; } SeparatedValueWriter svw = new SeparatedValueWriter(fs, new UTF8Encoding(false)) { Quotes = false, Separator = ';', VerifyFieldCount = true }; // Write out the header WriteHeader(svw); // Use a sorted list of games to output foreach (string key in Items.SortedKeys) { List datItems = Items.FilteredItems(key); // Resolve the names in the block datItems = DatItem.ResolveNames(datItems); for (int index = 0; index < datItems.Count; index++) { DatItem datItem = datItems[index]; // Check for a "null" item datItem = ProcessNullifiedItem(datItem); // Write out the item if we're not ignoring if (!ShouldIgnore(datItem, ignoreblanks)) WriteDatItem(svw, datItem); } } Globals.Logger.Verbose($"File written!{Environment.NewLine}"); svw.Dispose(); fs.Dispose(); } catch (Exception ex) { Globals.Logger.Error(ex.ToString()); return false; } return true; } /// /// Write out DAT header using the supplied StreamWriter /// /// SeparatedValueWriter to output to /// True if the data was written, false on error private bool WriteHeader(SeparatedValueWriter svw) { try { string[] headers = new string[] { "#Title", "Name", "Emulator", "CloneOf", "Year", "Manufacturer", "Category", "Players", "Rotation", "Control", "Status", "DisplayCount", "DisplayType", "AltRomname", "AltTitle", "Extra", "Buttons", }; svw.WriteHeader(headers); svw.Flush(); } catch (Exception ex) { Globals.Logger.Error(ex.ToString()); return false; } return true; } /// /// Write out Game start using the supplied StreamWriter /// /// SeparatedValueWriter to output to /// DatItem object to be output /// True if the data was written, false on error private bool WriteDatItem(SeparatedValueWriter svw, DatItem datItem) { try { // No game should start with a path separator datItem.Machine.Name = datItem.Machine.Name.TrimStart(Path.DirectorySeparatorChar); // Pre-process the item name ProcessItemName(datItem, true); // Build the state switch (datItem.ItemType) { case ItemType.Rom: var rom = datItem as Rom; string[] fields = new string[] { rom.Machine.Name, rom.Machine.Description, Header.FileName, rom.Machine.CloneOf, rom.Machine.Year, rom.Machine.Manufacturer, rom.Machine.Category, rom.Machine.Players, rom.Machine.Rotation, rom.Machine.Control, rom.ItemStatus.ToString(), rom.Machine.DisplayCount, rom.Machine.DisplayType, rom.AltName, rom.AltTitle, rom.Machine.Comment, rom.Machine.Buttons, }; svw.WriteValues(fields); break; } svw.Flush(); } catch (Exception ex) { Globals.Logger.Error(ex.ToString()); return false; } return true; } } }