using System; using System.Collections.Generic; using System.Linq; using SabreTools.Core; using SabreTools.Core.Tools; using SabreTools.DatItems; using SabreTools.DatItems.Formats; namespace SabreTools.DatFiles.Formats { /// /// Represents parsing an OfflineList XML DAT /// internal partial class OfflineList : DatFile { /// public override void ParseFile(string filename, int indexId, bool keep, bool statsOnly = false, bool throwOnError = false) { try { // Deserialize the input file var dat = new Serialization.Files.OfflineList().Deserialize(filename); // Convert the header to the internal format OfflineList.ConvertHeader(dat); // Convert the configuration to the internal format ConvertConfiguration(dat?.Configuration, keep); // Convert the games to the internal format ConvertGames(dat?.Games, filename, indexId, statsOnly); // Convert the GUI to the internal format ConvertGUI(dat?.GUI); } catch (Exception ex) when (!throwOnError) { string message = $"'{filename}' - An error occurred during parsing"; logger.Error(ex, message); } } #region Converters /// /// Convert header information /// /// Deserialized model to convert private static void ConvertHeader(Models.OfflineList.Dat? dat) { // If the datafile is missing, we can't do anything if (dat == null) return; //Header.NoNamespaceSchemaLocation = dat.NoNamespaceSchemaLocation; // TODO: Add to internal model } /// /// Convert configuration information /// /// Deserialized model to convert private void ConvertConfiguration(Models.OfflineList.Configuration? config, bool keep) { // If the config is missing, we can't do anything if (config == null) return; Header.Name ??= config.DatName; //Header.ImFolder ??= config.ImFolder; // TODO: Add to internal model Header.Version = config.DatVersion; Header.System = config.System; Header.ScreenshotsWidth = config.ScreenshotsWidth; Header.ScreenshotsHeight = config.ScreenshotsHeight; ConvertInfos(config.Infos); ConvertCanOpen(config.CanOpen); ConvertNewDat(config.NewDat); ConvertSearch(config.Search); Header.RomTitle = config.RomTitle; // Handle implied SuperDAT if (config.DatName?.Contains(" - SuperDAT") == true && keep) Header.Type ??= "SuperDAT"; } /// /// Convert infos information /// /// Deserialized model to convert private void ConvertInfos(Models.OfflineList.Infos? infos) { // If the infos is missing, we can't do anything if (infos == null) return; var offlineListInfos = new List(); if (infos.Title != null) { offlineListInfos.Add(new OfflineListInfo { Name = "title", Visible = infos.Title.Visible.AsYesNo(), InNamingOption = infos.Title.InNamingOption.AsYesNo(), Default = infos.Title.Default.AsYesNo(), }); } if (infos.Location != null) { offlineListInfos.Add(new OfflineListInfo { Name = "location", Visible = infos.Location.Visible.AsYesNo(), InNamingOption = infos.Location.InNamingOption.AsYesNo(), Default = infos.Location.Default.AsYesNo(), }); } if (infos.Publisher != null) { offlineListInfos.Add(new OfflineListInfo { Name = "publisher", Visible = infos.Publisher.Visible.AsYesNo(), InNamingOption = infos.Publisher.InNamingOption.AsYesNo(), Default = infos.Publisher.Default.AsYesNo(), }); } if (infos.SourceRom != null) { offlineListInfos.Add(new OfflineListInfo { Name = "sourceRom", Visible = infos.SourceRom.Visible.AsYesNo(), InNamingOption = infos.SourceRom.InNamingOption.AsYesNo(), Default = infos.SourceRom.Default.AsYesNo(), }); } if (infos.SaveType != null) { offlineListInfos.Add(new OfflineListInfo { Name = "saveType", Visible = infos.SaveType.Visible.AsYesNo(), InNamingOption = infos.SaveType.InNamingOption.AsYesNo(), Default = infos.SaveType.Default.AsYesNo(), }); } if (infos.RomSize != null) { offlineListInfos.Add(new OfflineListInfo { Name = "romSize", Visible = infos.RomSize.Visible.AsYesNo(), InNamingOption = infos.RomSize.InNamingOption.AsYesNo(), Default = infos.RomSize.Default.AsYesNo(), }); } if (infos.ReleaseNumber != null) { offlineListInfos.Add(new OfflineListInfo { Name = "releaseNumber", Visible = infos.ReleaseNumber.Visible.AsYesNo(), InNamingOption = infos.ReleaseNumber.InNamingOption.AsYesNo(), Default = infos.ReleaseNumber.Default.AsYesNo(), }); } if (infos.LanguageNumber != null) { offlineListInfos.Add(new OfflineListInfo { Name = "languageNumber", Visible = infos.LanguageNumber.Visible.AsYesNo(), InNamingOption = infos.LanguageNumber.InNamingOption.AsYesNo(), Default = infos.LanguageNumber.Default.AsYesNo(), }); } if (infos.Comment != null) { offlineListInfos.Add(new OfflineListInfo { Name = "comment", Visible = infos.Comment.Visible.AsYesNo(), InNamingOption = infos.Comment.InNamingOption.AsYesNo(), Default = infos.Comment.Default.AsYesNo(), }); } if (infos.RomCRC != null) { offlineListInfos.Add(new OfflineListInfo { Name = "romCRC", Visible = infos.RomCRC.Visible.AsYesNo(), InNamingOption = infos.RomCRC.InNamingOption.AsYesNo(), Default = infos.RomCRC.Default.AsYesNo(), }); } if (infos.Im1CRC != null) { offlineListInfos.Add(new OfflineListInfo { Name = "im1CRC", Visible = infos.Im1CRC.Visible.AsYesNo(), InNamingOption = infos.Im1CRC.InNamingOption.AsYesNo(), Default = infos.Im1CRC.Default.AsYesNo(), }); } if (infos.Im2CRC != null) { offlineListInfos.Add(new OfflineListInfo { Name = "im2CRC", Visible = infos.Im2CRC.Visible.AsYesNo(), InNamingOption = infos.Im2CRC.InNamingOption.AsYesNo(), Default = infos.Im2CRC.Default.AsYesNo(), }); } if (infos.Languages != null) { offlineListInfos.Add(new OfflineListInfo { Name = "languages", Visible = infos.Languages.Visible.AsYesNo(), InNamingOption = infos.Languages.InNamingOption.AsYesNo(), Default = infos.Languages.Default.AsYesNo(), }); } Header.Infos = offlineListInfos; } /// /// Convert canopen information /// /// Deserialized model to convert private void ConvertCanOpen(Models.OfflineList.CanOpen? canOpen) { // If the canOpen is missing, we can't do anything if (canOpen?.Extension == null) return; Header.CanOpen = new List(canOpen.Extension); } /// /// Convert newdat information /// /// Deserialized model to convert private void ConvertNewDat(Models.OfflineList.NewDat? newDat) { // If the canOpen is missing, we can't do anything if (newDat == null) return; Header.Url = newDat.DatVersionUrl; //Header.DatUrl = newDat.DatUrl; // TODO: Add to internal model //Header.ImUrl = newDat.ImUrl; // TODO: Add to internal model } /// /// Convert search information /// /// Deserialized model to convert private static void ConvertSearch(Models.OfflineList.Search? search) { // If the search or to array is missing, we can't do anything if (search?.To == null) return; // TODO: Add to internal model } /// /// Convert games information /// /// Deserialized model to convert /// Name of the file to be parsed /// Index ID for the DAT /// True to only add item statistics while parsing, false otherwise private void ConvertGames(Models.OfflineList.Games? games, string filename, int indexId, bool statsOnly) { // If the games array is missing, we can't do anything if (games?.Game == null || !games.Game.Any()) return; foreach (var game in games.Game) { ConvertGame(game, filename, indexId, statsOnly); } } /// /// Convert game information /// /// Deserialized model to convert /// Name of the file to be parsed /// Index ID for the DAT /// True to only add item statistics while parsing, false otherwise private void ConvertGame(Models.OfflineList.Game? game, string filename, int indexId, bool statsOnly) { // If the game is missing, we can't do anything if (game == null) return; var machine = new Machine(); machine.SetFieldValue(Models.Metadata.Machine.CommentKey, game.Comment); machine.SetFieldValue(Models.Metadata.Machine.Im1CRCKey, game.Im1CRC); machine.SetFieldValue(Models.Metadata.Machine.Im2CRCKey, game.Im2CRC); machine.SetFieldValue(Models.Metadata.Machine.ImageNumberKey, game.ImageNumber); machine.SetFieldValue(Models.Metadata.Machine.LanguageKey, game.Language); machine.SetFieldValue(Models.Metadata.Machine.LocationKey, game.Location); machine.SetFieldValue(Models.Metadata.Machine.NameKey, game.Title); machine.SetFieldValue(Models.Metadata.Machine.PublisherKey, game.Publisher); machine.SetFieldValue(Models.Metadata.Machine.ReleaseNumberKey, game.ReleaseNumber); machine.SetFieldValue(Models.Metadata.Machine.SaveTypeKey, game.SaveType); machine.SetFieldValue(Models.Metadata.Machine.SourceRomKey, game.SourceRom); long? size = NumberHelper.ConvertToInt64(game.RomSize); if (game.DuplicateID != "0") machine.SetFieldValue(Models.Metadata.Machine.CloneOfKey, game.DuplicateID); // Check if there are any items bool containsItems = false; // Loop through each file ConvertFiles(game.Files, machine, size, game.ReleaseNumber, filename, indexId, statsOnly, ref containsItems); // If we had no items, create a Blank placeholder if (!containsItems) { var blank = new Blank { Source = new Source { Index = indexId, Name = filename }, }; blank.CopyMachineInformation(machine); ParseAddHelper(blank, statsOnly); } } /// /// Convert Files information /// /// Array of deserialized models to convert /// Prefilled machine to use /// Item size to use /// Release number to use /// Name of the file to be parsed /// Index ID for the DAT /// True to only add item statistics while parsing, false otherwise /// True if there were any items in the array, false otherwise private void ConvertFiles(Models.OfflineList.Files? files, Machine machine, long? size, string? releaseNumber, string filename, int indexId, bool statsOnly, ref bool containsItems) { // If the files array is missing, we can't do anything if (files?.RomCRC == null || !files.RomCRC.Any()) return; containsItems = true; foreach (var crc in files.RomCRC) { string name = string.Empty; if (!string.IsNullOrEmpty(releaseNumber) && releaseNumber != "0") name += $"{releaseNumber} - "; name += $"{machine.GetFieldValue(Models.Metadata.Machine.NameKey)}{crc.Extension}"; var item = new Rom { Source = new Source { Index = indexId, Name = filename }, }; item.SetName(name); item.SetFieldValue(Models.Metadata.Rom.CRCKey, crc.Content); item.SetFieldValue(Models.Metadata.Rom.SizeKey, size); item.SetFieldValue(Models.Metadata.Rom.StatusKey, ItemStatus.None); item.CopyMachineInformation(machine); ParseAddHelper(item, statsOnly); } } /// /// Convert GUI information /// /// Deserialized model to convert private static void ConvertGUI(Models.OfflineList.GUI? gui) { // If the gui or Images are missing, we can't do anything if (gui?.Images?.Image == null || !gui.Images.Image.Any()) return; // TODO: Add to internal model } #endregion } }