using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace SabreTools.Core.Tools { public static class Converters { #region Enum to Enum /// /// Get the DatItemFields associated with each hash type /// public static List AsDatItemFields(this Hash hash) { List fields = new(); if (hash.HasFlag(Hash.CRC)) fields.Add(DatItemField.CRC); if (hash.HasFlag(Hash.MD5)) fields.Add(DatItemField.MD5); if (hash.HasFlag(Hash.SHA1)) fields.Add(DatItemField.SHA1); if (hash.HasFlag(Hash.SHA256)) fields.Add(DatItemField.SHA256); if (hash.HasFlag(Hash.SHA384)) fields.Add(DatItemField.SHA384); if (hash.HasFlag(Hash.SHA512)) fields.Add(DatItemField.SHA512); if (hash.HasFlag(Hash.SpamSum)) fields.Add(DatItemField.SpamSum); return fields; } #endregion #region String to Enum /// /// Get ChipType value from input string /// /// String to get value from /// ChipType value corresponding to the string public static ChipType AsChipType(this string chipType) => AsEnumValue(chipType); /// /// Get ControlType value from input string /// /// String to get value from /// ControlType value corresponding to the string public static ControlType AsControlType(this string controlType) => AsEnumValue(controlType); /// /// Get DatHeaderField value from input string /// /// String to get value from /// DatHeaderField value corresponding to the string public static DatHeaderField AsDatHeaderField(this string input) { // If the input is empty, we return null if (string.IsNullOrEmpty(input)) return DatHeaderField.NULL; // Normalize the input input = input.ToLowerInvariant(); // Create regex string headerRegex = @"^(dat|header|datheader)[.\-_\s]"; // If we don't have a header field, skip if (!Regex.IsMatch(input, headerRegex)) return DatHeaderField.NULL; // Replace the match and re-normalize string headerInput = Regex.Replace(input, headerRegex, string.Empty) .Replace(' ', '_') .Replace('-', '_') .Replace('.', '_'); return AsEnumValue(headerInput); } /// /// Get DatItemField value from input string /// /// String to get value from /// DatItemField value corresponding to the string public static DatItemField AsDatItemField(this string input) { // If the input is empty, we return null if (string.IsNullOrEmpty(input)) return DatItemField.NULL; // Normalize the input input = input.ToLowerInvariant(); // Create regex string datItemRegex = @"^(item|datitem)[.\-_\s]"; // If we don't have an item field, skip if (!Regex.IsMatch(input, datItemRegex)) return DatItemField.NULL; // Replace the match and re-normalize string itemInput = Regex.Replace(input, datItemRegex, string.Empty) .Replace(' ', '_') .Replace('-', '_') .Replace('.', '_'); return AsEnumValue(itemInput); } /// /// Get DeviceType value from input string /// /// String to get value from /// DeviceType value corresponding to the string public static DeviceType AsDeviceType(this string deviceType) => AsEnumValue(deviceType); /// /// Get DisplayType value from input string /// /// String to get value from /// DisplayType value corresponding to the string public static DisplayType AsDisplayType(this string displayType) => AsEnumValue(displayType); /// /// Get Endianness value from input string /// /// String to get value from /// Endianness value corresponding to the string public static Endianness AsEndianness(this string endianness) => AsEnumValue(endianness); /// /// Get FeatureStatus value from input string /// /// String to get value from /// FeatureStatus value corresponding to the string public static FeatureStatus AsFeatureStatus(this string featureStatus) => AsEnumValue(featureStatus); /// /// Get FeatureType value from input string /// /// String to get value from /// FeatureType value corresponding to the string public static FeatureType AsFeatureType(this string featureType) => AsEnumValue(featureType); /// /// Get ItemStatus value from input string /// /// String to get value from /// ItemStatus value corresponding to the string public static ItemStatus AsItemStatus(this string status) => AsEnumValue(status); /// /// Get ItemType? value from input string /// /// String to get value from /// ItemType? value corresponding to the string public static ItemType AsItemType(this string itemType) => AsEnumValue(itemType); /// /// Get LoadFlag value from input string /// /// String to get value from /// LoadFlag value corresponding to the string public static LoadFlag AsLoadFlag(this string loadFlag) => AsEnumValue(loadFlag); /// /// Get LogLevel value from input string /// /// String to get value from /// LogLevel value corresponding to the string public static LogLevel AsLogLevel(this string logLevel) => AsEnumValue(logLevel); /// /// Get MachineField value from input string /// /// String to get value from /// MachineField value corresponding to the string public static MachineField AsMachineField(this string input) { // If the input is empty, we return null if (string.IsNullOrEmpty(input)) return MachineField.NULL; // Normalize the input input = input.ToLowerInvariant(); // Create regex string machineRegex = @"^(game|machine)[.\-_\s]"; // If we don't have a machine field, skip if (!Regex.IsMatch(input, machineRegex)) return MachineField.NULL; // Replace the match and re-normalize string machineInput = Regex.Replace(input, machineRegex, string.Empty) .Replace(' ', '_') .Replace('-', '_') .Replace('.', '_'); return AsEnumValue(machineInput); } /// /// Get MachineType value from input string /// /// String to get value from /// MachineType value corresponding to the string public static MachineType AsMachineType(this string gametype) => AsEnumValue(gametype); /// /// Get MergingFlag value from input string /// /// String to get value from /// MergingFlag value corresponding to the string public static MergingFlag AsMergingFlag(this string merging) => AsEnumValue(merging); /// /// Get NodumpFlag value from input string /// /// String to get value from /// NodumpFlag value corresponding to the string public static NodumpFlag AsNodumpFlag(this string nodump) => AsEnumValue(nodump); /// /// Get OpenMSXSubType value from input string /// /// String to get value from /// OpenMSXSubType value corresponding to the string public static OpenMSXSubType AsOpenMSXSubType(this string subType) => AsEnumValue(subType); /// /// Get PackingFlag value from input string /// /// String to get value from /// PackingFlag value corresponding to the string public static PackingFlag AsPackingFlag(this string packing) => AsEnumValue(packing); /// /// Get Relation value from input string /// /// String to get value from /// Relation value corresponding to the string public static Relation AsRelation(this string relation) => AsEnumValue(relation); /// /// Get Runnable value from input string /// /// String to get value from /// Runnable value corresponding to the string public static Runnable AsRunnable(this string runnable) => AsEnumValue(runnable); /// /// Get SoftwareListStatus value from input string /// /// String to get value from /// SoftwareListStatus value corresponding to the string public static SoftwareListStatus AsSoftwareListStatus(this string status) => AsEnumValue(status); /// /// Get Supported value from input string /// /// String to get value from /// Supported value corresponding to the string public static Supported AsSupported(this string supported) => AsEnumValue(supported); /// /// Get SupportStatus value from input string /// /// String to get value from /// SupportStatus value corresponding to the string public static SupportStatus AsSupportStatus(this string supportStatus) => AsEnumValue(supportStatus); /// /// Get bool? value from input string /// /// String to get value from /// bool? corresponding to the string public static bool? AsYesNo(this string yesno) { return yesno?.ToLowerInvariant() switch { "yes" or "true" => true, "no" or "false" => false, _ => null, }; } /// /// Get the enum value for an input string, if possible /// /// String value to parse/param> /// Enum type that is expected /// Enum value representing the input, default on error private static T AsEnumValue(string value) { // Get the mapping dictionary var mappings = GenerateToEnum(); // Normalize the input value value = value?.ToLowerInvariant(); if (value == null) return default; // Try to get the value from the mappings if (mappings.ContainsKey(value)) return mappings[value]; // Otherwise, return the default value for the enum return default; } /// /// Get a set of mappings from strings to enum values /// /// Enum type that is expected /// Dictionary of string to enum values private static Dictionary GenerateToEnum() { try { // Get all of the values for the enum type var values = Enum.GetValues(typeof(T)); // Build the output dictionary Dictionary mappings = new(); foreach (T value in values) { // Try to get the mapping attribute MappingAttribute attr = AttributeHelper.GetAttribute(value); if (attr?.Mappings == null || !attr.Mappings.Any()) continue; // Loop through the mappings and add each foreach (string mapString in attr.Mappings) { mappings[mapString] = value; } } // Return the output dictionary return mappings; } catch { // This should not happen, only if the type was not an enum return new Dictionary(); } } #endregion #region Enum to String /// /// Get string value from input ChipType /// /// ChipType to get value from /// String value corresponding to the ChipType public static string FromChipType(this ChipType chipType) { return chipType switch { ChipType.CPU => "cpu", ChipType.Audio => "audio", _ => null, }; } /// /// Get string value from input ControlType /// /// ControlType to get value from /// String value corresponding to the ControlType public static string FromControlType(this ControlType controlType) { return controlType switch { ControlType.Joy => "joy", ControlType.Stick => "stick", ControlType.Paddle => "paddle", ControlType.Pedal => "pedal", ControlType.Lightgun => "lightgun", ControlType.Positional => "positional", ControlType.Dial => "dial", ControlType.Trackball => "trackball", ControlType.Mouse => "mouse", ControlType.OnlyButtons => "only_buttons", ControlType.Keypad => "keypad", ControlType.Keyboard => "keyboard", ControlType.Mahjong => "mahjong", ControlType.Hanafuda => "hanafuda", ControlType.Gambling => "gambling", _ => null, }; } /// /// Get string value from input DeviceType /// /// vDeviceType to get value from /// String value corresponding to the DeviceType public static string FromDeviceType(this DeviceType deviceType) { return deviceType switch { DeviceType.Unknown => "unknown", DeviceType.Cartridge => "cartridge", DeviceType.FloppyDisk => "floppydisk", DeviceType.HardDisk => "harddisk", DeviceType.Cylinder => "cylinder", DeviceType.Cassette => "cassette", DeviceType.PunchCard => "punchcard", DeviceType.PunchTape => "punchtape", DeviceType.Printout => "printout", DeviceType.Serial => "serial", DeviceType.Parallel => "parallel", DeviceType.Snapshot => "snapshot", DeviceType.QuickLoad => "quickload", DeviceType.MemCard => "memcard", DeviceType.CDROM => "cdrom", DeviceType.MagTape => "magtape", DeviceType.ROMImage => "romimage", DeviceType.MIDIIn => "midiin", DeviceType.MIDIOut => "midiout", DeviceType.Picture => "picture", DeviceType.VidFile => "vidfile", _ => null, }; } /// /// Get string value from input DisplayType /// /// DisplayType to get value from /// String value corresponding to the DisplayType public static string FromDisplayType(this DisplayType displayType) { return displayType switch { DisplayType.Raster => "raster", DisplayType.Vector => "vector", DisplayType.LCD => "lcd", DisplayType.SVG => "svg", DisplayType.Unknown => "unknown", _ => null, }; } /// /// Get string value from input Endianness /// /// Endianness to get value from /// String value corresponding to the Endianness public static string FromEndianness(this Endianness endianness) { return endianness switch { Endianness.Big => "big", Endianness.Little => "little", _ => null, }; } /// /// Get string value from input FeatureStatus /// /// FeatureStatus to get value from /// String value corresponding to the FeatureStatus public static string FromFeatureStatus(this FeatureStatus featureStatus) { return featureStatus switch { FeatureStatus.Unemulated => "unemulated", FeatureStatus.Imperfect => "imperfect", _ => null, }; } /// /// Get string value from input FeatureType /// /// FeatureType to get value from /// String value corresponding to the FeatureType public static string FromFeatureType(this FeatureType featureType) { return featureType switch { FeatureType.Protection => "protection", FeatureType.Palette => "palette", FeatureType.Graphics => "graphics", FeatureType.Sound => "sound", FeatureType.Controls => "controls", FeatureType.Keyboard => "keyboard", FeatureType.Mouse => "mouse", FeatureType.Microphone => "microphone", FeatureType.Camera => "camera", FeatureType.Disk => "disk", FeatureType.Printer => "printer", FeatureType.Lan => "lan", FeatureType.Wan => "wan", FeatureType.Timing => "timing", _ => null, }; } /// /// Get string value from input ItemStatus /// /// ItemStatus to get value from /// True to use Yes/No format instead /// String value corresponding to the ItemStatus public static string FromItemStatus(this ItemStatus status, bool yesno) { return status switch { ItemStatus.Good => "good", ItemStatus.BadDump => "baddump", ItemStatus.Nodump => yesno ? "yes" : "nodump", ItemStatus.Verified => "verified", _ => null, }; } /// /// Get string value from input LoadFlag /// /// LoadFlag to get value from /// String value corresponding to the LoadFlag public static string FromLoadFlag(this LoadFlag loadFlag) { return loadFlag switch { LoadFlag.Load16Byte => "load16_byte", LoadFlag.Load16Word => "load16_word", LoadFlag.Load16WordSwap => "load16_word_swap", LoadFlag.Load32Byte => "load32_byte", LoadFlag.Load32Word => "load32_word", LoadFlag.Load32WordSwap => "load32_word_swap", LoadFlag.Load32DWord => "load32_dword", LoadFlag.Load64Word => "load64_word", LoadFlag.Load64WordSwap => "load64_word_swap", LoadFlag.Reload => "reload", LoadFlag.Fill => "fill", LoadFlag.Continue => "continue", LoadFlag.ReloadPlain => "reload_plain", LoadFlag.Ignore => "ignore", _ => null, }; } /// /// Get string value from input ItemType? /// /// ItemType? to get value from /// String value corresponding to the ItemType? public static string FromItemType(this ItemType? itemType) { return itemType switch { ItemType.Adjuster => "adjuster", ItemType.Analog => "analog", ItemType.Archive => "archive", ItemType.BiosSet => "biosset", ItemType.Blank => "blank", ItemType.Chip => "chip", ItemType.Condition => "condition", ItemType.Configuration => "configuration", ItemType.Control => "control", ItemType.DataArea => "dataarea", ItemType.Device => "device", ItemType.DeviceReference => "device_ref", ItemType.DipSwitch => "dipswitch", ItemType.Disk => "disk", ItemType.DiskArea => "diskarea", ItemType.Display => "display", ItemType.Driver => "driver", ItemType.Extension => "extension", ItemType.Feature => "feature", ItemType.Info => "info", ItemType.Input => "input", ItemType.Instance => "instance", ItemType.Location => "location", ItemType.Media => "media", ItemType.Part => "part", ItemType.PartFeature => "part_feature", ItemType.Port => "port", ItemType.RamOption => "ramoption", ItemType.Release => "release", ItemType.ReleaseDetails => "release_details", ItemType.Rom => "rom", ItemType.Sample => "sample", ItemType.Serials => "serials", ItemType.Setting => "setting", ItemType.SharedFeature => "sharedfeat", ItemType.Slot => "slot", ItemType.SlotOption => "slotoption", ItemType.SoftwareList => "softwarelist", ItemType.Sound => "sound", ItemType.SourceDetails => "source_details", _ => null, }; } /// /// Get string value from input MachineType /// /// MachineType to get value from /// True to use old naming instead /// String value corresponding to the MachineType public static string FromMachineType(this MachineType gametype, bool old) { return gametype switch { MachineType.Bios => "bios", MachineType.Device => old ? "dev" : "device", MachineType.Mechanical => old ? "mech" : "mechanical", _ => null, }; } /// /// Get string value from input MergingFlag /// /// MergingFlag to get value from /// True to use RomCenter naming instead /// String value corresponding to the MergingFlag public static string FromMergingFlag(this MergingFlag merging, bool romCenter) { return merging switch { MergingFlag.Split => "split", MergingFlag.Merged => "merged", MergingFlag.FullMerged => "fullmerged", MergingFlag.NonMerged => romCenter ? "unmerged" : "nonmerged", MergingFlag.FullNonMerged => "full", MergingFlag.DeviceNonMerged => "device", _ => null, }; } /// /// Get string value from input NodumpFlag /// /// NodumpFlag to get value from /// String value corresponding to the NodumpFlag public static string FromNodumpFlag(this NodumpFlag nodump) { return nodump switch { NodumpFlag.Obsolete => "obsolete", NodumpFlag.Required => "required", NodumpFlag.Ignore => "ignore", _ => null, }; } /// /// Get string value from input OpenMSXSubType /// /// OpenMSXSubType to get value from /// String value corresponding to the OpenMSXSubType public static string FromOpenMSXSubType(this OpenMSXSubType itemType) { return itemType switch { OpenMSXSubType.Rom => "rom", OpenMSXSubType.MegaRom => "megarom", OpenMSXSubType.SCCPlusCart => "sccpluscart", _ => null, }; } /// /// Get string value from input PackingFlag /// /// PackingFlag to get value from /// True to use Yes/No format instead /// String value corresponding to the PackingFlag public static string FromPackingFlag(this PackingFlag packing, bool yesno) { return packing switch { PackingFlag.Zip => yesno ? "yes" : "zip", PackingFlag.Unzip => yesno ? "no" : "unzip", PackingFlag.Partial => "partial", PackingFlag.Flat => "flat", _ => null, }; } /// /// Get string value from input Relation /// /// Relation to get value from /// String value corresponding to the Relation public static string FromRelation(this Relation relation) { return relation switch { Relation.Equal => "eq", Relation.NotEqual => "ne", Relation.GreaterThan => "gt", Relation.LessThanOrEqual => "le", Relation.LessThan => "lt", Relation.GreaterThanOrEqual => "ge", _ => null, }; } /// /// Get string value from input Runnable /// /// Runnable to get value from /// String value corresponding to the Runnable public static string FromRunnable(this Runnable runnable) { return runnable switch { Runnable.No => "no", Runnable.Partial => "partial", Runnable.Yes => "yes", _ => null, }; } /// /// Get string value from input SoftwareListStatus /// /// SoftwareListStatus to get value from /// String value corresponding to the SoftwareListStatus public static string FromSoftwareListStatus(this SoftwareListStatus status) { return status switch { SoftwareListStatus.Original => "original", SoftwareListStatus.Compatible => "compatible", _ => null, }; } /// /// Get string value from input Supported /// /// Supported to get value from /// True to use verbose output, false otherwise /// String value corresponding to the Supported public static string FromSupported(this Supported supported, bool verbose) { return supported switch { Supported.No => verbose ? "unsupported" : "no", Supported.Partial => "partial", Supported.Yes => verbose ? "supported" : "yes", _ => null, }; } /// /// Get string value from input SupportStatus /// /// SupportStatus to get value from /// String value corresponding to the SupportStatus public static string FromSupportStatus(this SupportStatus supportStatus) { return supportStatus switch { SupportStatus.Good => "good", SupportStatus.Imperfect => "imperfect", SupportStatus.Preliminary => "preliminary", _ => null, }; } /// /// Get string value from input bool? /// /// bool? to get value from /// String corresponding to the bool? public static string FromYesNo(this bool? yesno) { return yesno switch { true => "yes", false => "no", _ => null, }; } /// /// Get the string value for an input enum, if possible /// /// Enum value to parse/param> /// Enum type that is expected /// String value representing the input, default on error private static string? AsStringValue(T value) { // Get the mapping dictionary var mappings = GenerateToString(); // Try to get the value from the mappings if (mappings.ContainsKey(value)) return mappings[value]; // Otherwise, return null return null; } /// /// Get a set of mappings from enum values to string /// /// Enum type to generate from /// Dictionary of enum to string values private static Dictionary GenerateToString() { try { // Get all of the values for the enum type var values = Enum.GetValues(typeof(T)); // Build the output dictionary Dictionary mappings = new(); foreach (T value in values) { // Try to get the mapping attribute MappingAttribute attr = AttributeHelper.GetAttribute(value); if (attr?.Mappings == null || !attr.Mappings.Any()) continue; // Always use the first value in the list mappings[value] = attr.Mappings[0]; } // Return the output dictionary return mappings; } catch { // This should not happen, only if the type was not an enum return new Dictionary(); } } #endregion } }