/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle Chip-specific fields if (mappings.Keys.Contains(Field.DatItem_Name)) { Name = mappings[Field.DatItem_Name]; } if (mappings.Keys.Contains(Field.DatItem_Tag)) { Tag = mappings[Field.DatItem_Tag]; } if (mappings.Keys.Contains(Field.DatItem_ChipType)) { ChipType = mappings[Field.DatItem_ChipType].AsChipType(); } if (mappings.Keys.Contains(Field.DatItem_Clock)) { Clock = Sanitizer.CleanLong(mappings[Field.DatItem_Clock]); } }
/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle DataArea-specific fields if (mappings.Keys.Contains(Field.DatItem_AreaName)) { Name = mappings[Field.DatItem_AreaName]; } if (mappings.Keys.Contains(Field.DatItem_AreaSize)) { Size = Sanitizer.CleanLong(mappings[Field.DatItem_AreaSize]); } if (mappings.Keys.Contains(Field.DatItem_AreaWidth)) { Width = Sanitizer.CleanLong(mappings[Field.DatItem_AreaWidth]); } if (mappings.Keys.Contains(Field.DatItem_AreaEndianness)) { Endianness = mappings[Field.DatItem_AreaEndianness].AsEndianness(); } }
/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle Input-specific fields if (mappings.Keys.Contains(Field.DatItem_Service)) { Service = mappings[Field.DatItem_Service].AsYesNo(); } if (mappings.Keys.Contains(Field.DatItem_Tilt)) { Tilt = mappings[Field.DatItem_Tilt].AsYesNo(); } if (mappings.Keys.Contains(Field.DatItem_Players)) { Players = Sanitizer.CleanLong(mappings[Field.DatItem_Players]); } if (mappings.Keys.Contains(Field.DatItem_Coins)) { Coins = Sanitizer.CleanLong(mappings[Field.DatItem_Coins]); } if (ControlsSpecified) { foreach (Control control in Controls) { control.SetFields(mappings); } } }
/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle Sound-specific fields if (mappings.Keys.Contains(Field.DatItem_Channels)) { Channels = Sanitizer.CleanLong(mappings[Field.DatItem_Channels]); } }
/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle Device-specific fields if (mappings.Keys.Contains(Field.DatItem_DeviceType)) { DeviceType = mappings[Field.DatItem_DeviceType].AsDeviceType(); } if (mappings.Keys.Contains(Field.DatItem_Tag)) { Tag = mappings[Field.DatItem_Tag]; } if (mappings.Keys.Contains(Field.DatItem_FixedImage)) { FixedImage = mappings[Field.DatItem_FixedImage]; } if (mappings.Keys.Contains(Field.DatItem_Mandatory)) { Mandatory = Sanitizer.CleanLong(mappings[Field.DatItem_Mandatory]); } if (mappings.Keys.Contains(Field.DatItem_Interface)) { Interface = mappings[Field.DatItem_Interface]; } if (InstancesSpecified) { foreach (Instance instance in Instances) { instance.SetFields(mappings); } } if (ExtensionsSpecified) { foreach (Extension extension in Extensions) { extension.SetFields(mappings); } } }
/// <summary> /// Read dataarea information /// </summary> /// <param name="reader">XmlReader representing a dataarea block</param> /// <param name="dataArea">DataArea representing the enclosing area</param> private List <DatItem> ReadDataArea(XmlReader reader, DataArea dataArea) { List <DatItem> items = new List <DatItem>(); while (!reader.EOF) { // We only want elements if (reader.NodeType != XmlNodeType.Element) { reader.Read(); continue; } // Get the elements from the software switch (reader.Name) { case "rom": var rom = new Rom { Name = reader.GetAttribute("name"), Size = Sanitizer.CleanLong(reader.GetAttribute("size")), CRC = reader.GetAttribute("crc"), SHA1 = reader.GetAttribute("sha1"), Offset = reader.GetAttribute("offset"), Value = reader.GetAttribute("value"), ItemStatus = reader.GetAttribute("status").AsItemStatus(), LoadFlag = reader.GetAttribute("loadflag").AsLoadFlag(), DataArea = dataArea, }; items.Add(rom); reader.Read(); break; default: reader.Read(); break; } } return(items); }
/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle Location-specific fields if (mappings.Keys.Contains(Field.DatItem_Location_Name)) { Name = mappings[Field.DatItem_Location_Name]; } if (mappings.Keys.Contains(Field.DatItem_Location_Number)) { Number = Sanitizer.CleanLong(mappings[Field.DatItem_Location_Number]); } if (mappings.Keys.Contains(Field.DatItem_Location_Inverted)) { Inverted = mappings[Field.DatItem_Location_Inverted].AsYesNo(); } }
/// <summary> /// Read part information /// </summary> /// <param name="reader">XmlReader representing a part block</param> /// <param name="machine">Machine information to pass to contained items</param> /// <param name="part">Part information to pass to contained items</param> /// <param name="filename">Name of the file to be parsed</param> /// <param name="indexId">Index ID for the DAT</param> private bool ReadPart(XmlReader reader, Machine machine, Part part, string filename, int indexId) { // If we have an empty port, skip it if (reader == null) { return(false); } // Get lists ready part.Features = new List <PartFeature>(); List <DatItem> items = new List <DatItem>(); while (!reader.EOF) { // We only want elements if (reader.NodeType != XmlNodeType.Element) { reader.Read(); continue; } // Get the elements from the software switch (reader.Name) { case "feature": var feature = new PartFeature() { Name = reader.GetAttribute("name"), Value = reader.GetAttribute("value"), }; part.Features.Add(feature); reader.Read(); break; case "dataarea": var dataArea = new DataArea { Name = reader.GetAttribute("name"), Size = Sanitizer.CleanLong(reader.GetAttribute("size")), Width = Sanitizer.CleanLong(reader.GetAttribute("width")), Endianness = reader.GetAttribute("endianness").AsEndianness(), }; List <DatItem> roms = ReadDataArea(reader.ReadSubtree(), dataArea); // If we got valid roms, add them to the list if (roms != null) { items.AddRange(roms); } // Skip the dataarea now that we've processed it reader.Skip(); break; case "diskarea": var diskArea = new DiskArea { Name = reader.GetAttribute("name"), }; List <DatItem> disks = ReadDiskArea(reader.ReadSubtree(), diskArea); // If we got valid disks, add them to the list if (disks != null) { items.AddRange(disks); } // Skip the diskarea now that we've processed it reader.Skip(); break; case "dipswitch": var dipSwitch = new DipSwitch { Name = reader.GetAttribute("name"), Tag = reader.GetAttribute("tag"), Mask = reader.GetAttribute("mask"), }; // Now read the internal tags ReadDipSwitch(reader.ReadSubtree(), dipSwitch); items.Add(dipSwitch); // Skip the dipswitch now that we've processed it reader.Skip(); break; default: reader.Read(); break; } } // Loop over all of the items, if they exist string key = string.Empty; foreach (DatItem item in items) { // Add all missing information switch (item.ItemType) { case ItemType.DipSwitch: (item as DipSwitch).Part = part; break; case ItemType.Disk: (item as Disk).Part = part; break; case ItemType.Rom: (item as Rom).Part = part; // If the rom is continue or ignore, add the size to the previous rom // TODO: Can this be done on write? We technically lose information this way. // Order is not guaranteed, and since these don't tend to have any way // of determining what the "previous" item was after this, that info would // have to be stored *with* the item somehow if ((item as Rom).LoadFlag == LoadFlag.Continue || (item as Rom).LoadFlag == LoadFlag.Ignore) { int index = Items[key].Count - 1; DatItem lastrom = Items[key][index]; if (lastrom.ItemType == ItemType.Rom) { (lastrom as Rom).Size += (item as Rom).Size; Items[key].RemoveAt(index); Items[key].Add(lastrom); } continue; } break; } item.Source = new Source(indexId, filename); item.CopyMachineInformation(machine); // Finally add each item key = ParseAddHelper(item); } return(items.Any()); }
/// <summary> /// Read games information /// </summary> /// <param name="reader">IniReader to use to parse the credits</param> /// <param name="filename">Name of the file to be parsed</param> /// <param name="indexId">Index ID for the DAT</param> private void ReadGamesSection(IniReader reader, string filename, int indexId) { // If the reader is somehow null, skip it if (reader == null) { return; } reader.ReadNextLine(); while (!reader.EndOfStream && reader.Section.ToLowerInvariant() == "games") { // We don't care about whitespace or comments // We're keeping keyvalue in case a file has '=' in the row if (reader.RowType != IniRowType.Invalid && reader.RowType != IniRowType.KeyValue) { reader.ReadNextLine(); continue; } // Roms are not valid row formats, usually string line = reader.CurrentLine; // If we don't have a valid game, keep reading if (!line.StartsWith("¬")) { reader.ReadNextLine(); continue; } // Some old RC DATs have this behavior if (line.Contains("¬N¬O")) { line = line.Replace("¬N¬O", string.Empty) + "¬¬"; } /* * The rominfo order is as follows: * 1 - parent name * 2 - parent description * 3 - game name * 4 - game description * 5 - rom name * 6 - rom crc * 7 - rom size * 8 - romof name * 9 - merge name */ string[] rominfo = line.Split('¬'); Rom rom = new Rom { Name = rominfo[5], Size = Sanitizer.CleanLong(rominfo[7]), CRC = rominfo[6], ItemStatus = ItemStatus.None, Machine = new Machine { Name = rominfo[3], Description = rominfo[4], CloneOf = rominfo[1], RomOf = rominfo[8], }, MergeTag = rominfo[9], Source = new Source { Index = indexId, Name = filename, }, }; // Now process and add the rom ParseAddHelper(rom); reader.ReadNextLine(); } }
/// <summary> /// Parse a MAME Listrom DAT and return all found games and roms within /// </summary> /// <param name="filename">Name of the file to be parsed</param> /// <param name="indexId">Index ID for the DAT</param> /// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param> /// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param> /// <remarks> /// In a new style MAME listrom DAT, each game has the following format: /// /// ROMs required for driver "005". /// Name Size Checksum /// 1346b.cpu-u25 2048 CRC(8e68533e) SHA1(a257c556d31691068ed5c991f1fb2b51da4826db) /// 6331.sound-u8 32 BAD CRC(1d298cb0) SHA1(bb0bb62365402543e3154b9a77be9c75010e6abc) BAD_DUMP /// 16v8h-blue.u24 279 NO GOOD DUMP KNOWN /// </remarks> protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false) { // Open a file reader Encoding enc = FileExtensions.GetEncoding(filename); StreamReader sr = new StreamReader(FileExtensions.TryOpenRead(filename), enc); string gamename = string.Empty; while (!sr.EndOfStream) { try { string line = sr.ReadLine().Trim(); // If we have a blank line, we just skip it if (string.IsNullOrWhiteSpace(line)) { continue; } // If we have the descriptor line, ignore it else if (line == "Name Size Checksum") { continue; } // If we have the beginning of a game, set the name of the game else if (line.StartsWith("ROMs required for")) { gamename = Regex.Match(line, @"^ROMs required for \S*? string.Empty(.*?)string.Empty\.").Groups[1].Value; } // If we have a machine with no required roms (usually internal devices), skip it else if (line.StartsWith("No ROMs required for")) { continue; } // Otherwise, we assume we have a rom that we need to add else { // First, we preprocess the line so that the rom name is consistently correct string[] split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); // If the line doesn't have the 4 spaces of padding, check for 3 if (split.Length == 1) { split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); } // If the split is still unsuccessful, log it and skip if (split.Length == 1) { logger.Warning($"Possibly malformed line: '{line}'"); } string romname = split[0]; line = line.Substring(romname.Length); // Next we separate the ROM into pieces split = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); // Standard Disks have 2 pieces (name, sha1) if (split.Length == 1) { Disk disk = new Disk() { Name = romname, SHA1 = Sanitizer.CleanListromHashData(split[0]), Machine = new Machine { Name = gamename, }, Source = new Source { Index = indexId, Name = filename, }, }; ParseAddHelper(disk); } // Baddump Disks have 4 pieces (name, BAD, sha1, BAD_DUMP) else if (split.Length == 3 && line.EndsWith("BAD_DUMP")) { Disk disk = new Disk() { Name = romname, SHA1 = Sanitizer.CleanListromHashData(split[1]), ItemStatus = ItemStatus.BadDump, Machine = new Machine { Name = gamename, }, Source = new Source { Index = indexId, Name = filename, }, }; ParseAddHelper(disk); } // Standard ROMs have 4 pieces (name, size, crc, sha1) else if (split.Length == 3) { Rom rom = new Rom() { Name = romname, Size = Sanitizer.CleanLong(split[0]), CRC = Sanitizer.CleanListromHashData(split[1]), SHA1 = Sanitizer.CleanListromHashData(split[2]), Machine = new Machine { Name = gamename, }, Source = new Source { Index = indexId, Name = filename, }, }; ParseAddHelper(rom); } // Nodump Disks have 5 pieces (name, NO, GOOD, DUMP, KNOWN) else if (split.Length == 4 && line.EndsWith("NO GOOD DUMP KNOWN")) { Disk disk = new Disk() { Name = romname, ItemStatus = ItemStatus.Nodump, Machine = new Machine { Name = gamename, }, Source = new Source { Index = indexId, Name = filename, }, }; ParseAddHelper(disk); } // Baddump ROMs have 6 pieces (name, size, BAD, crc, sha1, BAD_DUMP) else if (split.Length == 5 && line.EndsWith("BAD_DUMP")) { Rom rom = new Rom() { Name = romname, Size = Sanitizer.CleanLong(split[0]), CRC = Sanitizer.CleanListromHashData(split[2]), SHA1 = Sanitizer.CleanListromHashData(split[3]), ItemStatus = ItemStatus.BadDump, Machine = new Machine { Name = gamename, }, Source = new Source { Index = indexId, Name = filename, }, }; ParseAddHelper(rom); } // Nodump ROMs have 6 pieces (name, size, NO, GOOD, DUMP, KNOWN) else if (split.Length == 5 && line.EndsWith("NO GOOD DUMP KNOWN")) { Rom rom = new Rom() { Name = romname, Size = Sanitizer.CleanLong(split[0]), ItemStatus = ItemStatus.Nodump, Machine = new Machine { Name = gamename, }, Source = new Source { Index = indexId, Name = filename, }, }; ParseAddHelper(rom); } // If we have something else, it's invalid else { logger.Warning($"Invalid line detected: '{romname} {line}'"); } } } catch (Exception ex) { string message = $"'{filename}' - There was an error parsing at position {sr.BaseStream.Position}"; logger.Error(ex, message); if (throwOnError) { sr.Dispose(); throw new Exception(message, ex); } } } }
/// <summary> /// Read set information /// </summary> /// <param name="cmpr">ClrMameProReader to use to parse the header</param> /// <param name="resource">True if the item is a resource (bios), false otherwise</param> /// <param name="filename">Name of the file to be parsed</param> /// <param name="indexId">Index ID for the DAT</param> private void ReadSet( ClrMameProReader cmpr, bool resource, // Standard Dat parsing string filename, int indexId) { // Prepare all internal variables bool containsItems = false; Machine machine = new Machine() { MachineType = (resource ? MachineType.Bios : MachineType.NULL), }; // If there's no subtree to the header, skip it if (cmpr == null || cmpr.EndOfStream) { return; } // While we don't hit an end element or end of stream while (!cmpr.EndOfStream) { cmpr.ReadNextLine(); // Ignore comments and nothingness if (cmpr.RowType == CmpRowType.None || cmpr.RowType == CmpRowType.Comment) { continue; } // If we reached the end of a section, break if (cmpr.RowType == CmpRowType.EndTopLevel) { break; } // Handle any standalone items if (cmpr.RowType == CmpRowType.Standalone && cmpr.Standalone != null) { string itemKey = cmpr.Standalone?.Key.ToLowerInvariant(); string itemVal = cmpr.Standalone?.Value; switch (itemKey) { case "name": machine.Name = itemVal; break; case "description": machine.Description = itemVal; break; case "year": machine.Year = itemVal; break; case "manufacturer": machine.Manufacturer = itemVal; break; case "category": machine.Category = itemVal; break; case "cloneof": machine.CloneOf = itemVal; break; case "romof": machine.RomOf = itemVal; break; case "sampleof": machine.SampleOf = itemVal; break; } } // Handle any internal items else if (cmpr.RowType == CmpRowType.Internal && !string.IsNullOrWhiteSpace(cmpr.InternalName) && cmpr.Internal != null) { containsItems = true; string itemKey = cmpr.InternalName; // Create the proper DatItem based on the type ItemType itemType = itemKey.AsItemType() ?? ItemType.Rom; DatItem item = DatItem.Create(itemType); // Then populate it with information item.CopyMachineInformation(machine); item.Source.Index = indexId; item.Source.Name = filename; // Loop through all of the attributes foreach (var kvp in cmpr.Internal) { string attrKey = kvp.Key; string attrVal = kvp.Value; switch (attrKey) { //If the item is empty, we automatically skip it because it's a fluke case "": continue; // Regular attributes case "name": item.SetFields(new Dictionary <Field, string> { [Field.DatItem_Name] = attrVal }); break; case "size": if (item.ItemType == ItemType.Rom) { (item as Rom).Size = Sanitizer.CleanLong(attrVal); } break; case "crc": if (item.ItemType == ItemType.Rom) { (item as Rom).CRC = attrVal; } break; case "md5": if (item.ItemType == ItemType.Disk) { (item as Disk).MD5 = attrVal; } else if (item.ItemType == ItemType.Media) { (item as Media).MD5 = attrVal; } else if (item.ItemType == ItemType.Rom) { (item as Rom).MD5 = attrVal; } break; #if NET_FRAMEWORK case "ripemd160": if (item.ItemType == ItemType.Rom) { (item as Rom).RIPEMD160 = attrVal; } break; #endif case "sha1": if (item.ItemType == ItemType.Disk) { (item as Disk).SHA1 = attrVal; } else if (item.ItemType == ItemType.Media) { (item as Media).SHA1 = attrVal; } else if (item.ItemType == ItemType.Rom) { (item as Rom).SHA1 = attrVal; } break; case "sha256": if (item.ItemType == ItemType.Media) { (item as Media).SHA256 = attrVal; } else if (item.ItemType == ItemType.Rom) { (item as Rom).SHA256 = attrVal; } break; case "sha384": if (item.ItemType == ItemType.Rom) { (item as Rom).SHA384 = attrVal; } break; case "sha512": if (item.ItemType == ItemType.Rom) { (item as Rom).SHA512 = attrVal; } break; case "spamsum": if (item.ItemType == ItemType.Media) { (item as Media).SpamSum = attrVal; } else if (item.ItemType == ItemType.Rom) { (item as Rom).SpamSum = attrVal; } break; case "status": ItemStatus tempFlagStatus = attrVal.AsItemStatus(); if (item.ItemType == ItemType.Disk) { (item as Disk).ItemStatus = tempFlagStatus; } else if (item.ItemType == ItemType.Rom) { (item as Rom).ItemStatus = tempFlagStatus; } break; case "date": if (item.ItemType == ItemType.Release) { (item as Release).Date = attrVal; } else if (item.ItemType == ItemType.Rom) { (item as Rom).Date = attrVal; } break; case "default": if (item.ItemType == ItemType.BiosSet) { (item as BiosSet).Default = attrVal.AsYesNo(); } else if (item.ItemType == ItemType.Release) { (item as Release).Default = attrVal.AsYesNo(); } break; case "description": if (item.ItemType == ItemType.BiosSet) { (item as BiosSet).Description = attrVal; } break; case "region": if (item.ItemType == ItemType.Release) { (item as Release).Region = attrVal; } break; case "language": if (item.ItemType == ItemType.Release) { (item as Release).Language = attrVal; } break; } } // Now process and add the rom ParseAddHelper(item); } } // If no items were found for this machine, add a Blank placeholder if (!containsItems) { Blank blank = new Blank() { Source = new Source { Index = indexId, Name = filename, }, }; blank.CopyMachineInformation(machine); // Now process and add the rom ParseAddHelper(blank); } }
/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle Control-specific fields if (mappings.Keys.Contains(Field.DatItem_Control_Type)) { ControlType = mappings[Field.DatItem_Control_Type].AsControlType(); } if (mappings.Keys.Contains(Field.DatItem_Control_Player)) { Player = Sanitizer.CleanLong(mappings[Field.DatItem_Control_Player]); } if (mappings.Keys.Contains(Field.DatItem_Control_Buttons)) { Buttons = Sanitizer.CleanLong(mappings[Field.DatItem_Control_Buttons]); } if (mappings.Keys.Contains(Field.DatItem_Control_RequiredButtons)) { RequiredButtons = Sanitizer.CleanLong(mappings[Field.DatItem_Control_RequiredButtons]); } if (mappings.Keys.Contains(Field.DatItem_Control_Minimum)) { Minimum = Sanitizer.CleanLong(mappings[Field.DatItem_Control_Minimum]); } if (mappings.Keys.Contains(Field.DatItem_Control_Maximum)) { Maximum = Sanitizer.CleanLong(mappings[Field.DatItem_Control_Maximum]); } if (mappings.Keys.Contains(Field.DatItem_Control_Sensitivity)) { Sensitivity = Sanitizer.CleanLong(mappings[Field.DatItem_Control_Sensitivity]); } if (mappings.Keys.Contains(Field.DatItem_Control_KeyDelta)) { KeyDelta = Sanitizer.CleanLong(mappings[Field.DatItem_Control_KeyDelta]); } if (mappings.Keys.Contains(Field.DatItem_Control_Reverse)) { Reverse = mappings[Field.DatItem_Control_Reverse].AsYesNo(); } if (mappings.Keys.Contains(Field.DatItem_Control_Ways)) { Ways = mappings[Field.DatItem_Control_Ways]; } if (mappings.Keys.Contains(Field.DatItem_Control_Ways2)) { Ways2 = mappings[Field.DatItem_Control_Ways2]; } if (mappings.Keys.Contains(Field.DatItem_Control_Ways3)) { Ways3 = mappings[Field.DatItem_Control_Ways3]; } }
/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle Display-specific fields if (mappings.Keys.Contains(Field.DatItem_Tag)) { Tag = mappings[Field.DatItem_Tag]; } if (mappings.Keys.Contains(Field.DatItem_DisplayType)) { DisplayType = mappings[Field.DatItem_DisplayType].AsDisplayType(); } if (mappings.Keys.Contains(Field.DatItem_Rotate)) { Rotate = Sanitizer.CleanLong(mappings[Field.DatItem_Rotate]); } if (mappings.Keys.Contains(Field.DatItem_FlipX)) { FlipX = mappings[Field.DatItem_FlipX].AsYesNo(); } if (mappings.Keys.Contains(Field.DatItem_Width)) { Width = Sanitizer.CleanLong(mappings[Field.DatItem_Width]); } if (mappings.Keys.Contains(Field.DatItem_Height)) { Height = Sanitizer.CleanLong(mappings[Field.DatItem_Height]); } if (mappings.Keys.Contains(Field.DatItem_Refresh)) { if (Double.TryParse(mappings[Field.DatItem_Refresh], out double refresh)) { Refresh = refresh; } } if (mappings.Keys.Contains(Field.DatItem_PixClock)) { PixClock = Sanitizer.CleanLong(mappings[Field.DatItem_PixClock]); } if (mappings.Keys.Contains(Field.DatItem_HTotal)) { HTotal = Sanitizer.CleanLong(mappings[Field.DatItem_HTotal]); } if (mappings.Keys.Contains(Field.DatItem_HBEnd)) { HBEnd = Sanitizer.CleanLong(mappings[Field.DatItem_HBEnd]); } if (mappings.Keys.Contains(Field.DatItem_HBStart)) { HBStart = Sanitizer.CleanLong(mappings[Field.DatItem_HBStart]); } if (mappings.Keys.Contains(Field.DatItem_VTotal)) { VTotal = Sanitizer.CleanLong(mappings[Field.DatItem_VTotal]); } if (mappings.Keys.Contains(Field.DatItem_VBEnd)) { VBEnd = Sanitizer.CleanLong(mappings[Field.DatItem_VBEnd]); } if (mappings.Keys.Contains(Field.DatItem_VBStart)) { VBStart = Sanitizer.CleanLong(mappings[Field.DatItem_VBStart]); } }
/// <summary> /// Set fields with given values /// </summary> /// <param name="mappings">Mappings dictionary</param> public override void SetFields(Dictionary <Field, string> mappings) { // Set base fields base.SetFields(mappings); // Handle Rom-specific fields #region Common if (mappings.Keys.Contains(Field.DatItem_Name)) { Name = mappings[Field.DatItem_Name]; } if (mappings.Keys.Contains(Field.DatItem_Bios)) { Bios = mappings[Field.DatItem_Bios]; } if (mappings.Keys.Contains(Field.DatItem_Size)) { Size = Sanitizer.CleanLong(mappings[Field.DatItem_Size]); } if (mappings.Keys.Contains(Field.DatItem_CRC)) { CRC = mappings[Field.DatItem_CRC]; } if (mappings.Keys.Contains(Field.DatItem_MD5)) { MD5 = mappings[Field.DatItem_MD5]; } #if NET_FRAMEWORK if (mappings.Keys.Contains(Field.DatItem_RIPEMD160)) { RIPEMD160 = mappings[Field.DatItem_RIPEMD160]; } #endif if (mappings.Keys.Contains(Field.DatItem_SHA1)) { SHA1 = mappings[Field.DatItem_SHA1]; } if (mappings.Keys.Contains(Field.DatItem_SHA256)) { SHA256 = mappings[Field.DatItem_SHA256]; } if (mappings.Keys.Contains(Field.DatItem_SHA384)) { SHA384 = mappings[Field.DatItem_SHA384]; } if (mappings.Keys.Contains(Field.DatItem_SHA512)) { SHA512 = mappings[Field.DatItem_SHA512]; } if (mappings.Keys.Contains(Field.DatItem_SpamSum)) { SpamSum = mappings[Field.DatItem_SpamSum]; } if (mappings.Keys.Contains(Field.DatItem_Merge)) { MergeTag = mappings[Field.DatItem_Merge]; } if (mappings.Keys.Contains(Field.DatItem_Region)) { Region = mappings[Field.DatItem_Region]; } if (mappings.Keys.Contains(Field.DatItem_Offset)) { Offset = mappings[Field.DatItem_Offset]; } if (mappings.Keys.Contains(Field.DatItem_Date)) { Date = mappings[Field.DatItem_Date]; } if (mappings.Keys.Contains(Field.DatItem_Status)) { ItemStatus = mappings[Field.DatItem_Status].AsItemStatus(); } if (mappings.Keys.Contains(Field.DatItem_Optional)) { Optional = mappings[Field.DatItem_Optional].AsYesNo(); } if (mappings.Keys.Contains(Field.DatItem_Inverted)) { Inverted = mappings[Field.DatItem_Optional].AsYesNo(); } #endregion #region AttractMode if (mappings.Keys.Contains(Field.DatItem_AltName)) { AltName = mappings[Field.DatItem_AltName]; } if (mappings.Keys.Contains(Field.DatItem_AltTitle)) { AltTitle = mappings[Field.DatItem_AltTitle]; } #endregion #region OpenMSX if (mappings.Keys.Contains(Field.DatItem_Original)) { Original = new Original() { Content = mappings[Field.DatItem_Original] } } ; if (mappings.Keys.Contains(Field.DatItem_OpenMSXSubType)) { OpenMSXSubType = mappings[Field.DatItem_OpenMSXSubType].AsOpenMSXSubType(); } if (mappings.Keys.Contains(Field.DatItem_OpenMSXType)) { OpenMSXType = mappings[Field.DatItem_OpenMSXType]; } if (mappings.Keys.Contains(Field.DatItem_Remark)) { Remark = mappings[Field.DatItem_Remark]; } if (mappings.Keys.Contains(Field.DatItem_Boot)) { Boot = mappings[Field.DatItem_Boot]; } #endregion #region SoftwareList if (mappings.Keys.Contains(Field.DatItem_LoadFlag)) { LoadFlag = mappings[Field.DatItem_LoadFlag].AsLoadFlag(); } if (mappings.Keys.Contains(Field.DatItem_Value)) { Value = mappings[Field.DatItem_Value]; } // Handle DataArea-specific fields if (DataArea == null) { DataArea = new DataArea(); } DataArea.SetFields(mappings); // Handle Part-specific fields if (Part == null) { Part = new Part(); } Part.SetFields(mappings); #endregion }
/// <summary> /// Read game information /// </summary> /// <param name="reader">XmlReader to use to parse the header</param> /// <param name="filename">Name of the file to be parsed</param> /// <param name="indexId">Index ID for the DAT</param> private void ReadGame(XmlReader reader, string filename, int indexId) { // Prepare all internal variables string releaseNumber = string.Empty, duplicateid; long? size = null; List <Rom> datItems = new List <Rom>(); Machine machine = new Machine(); // If there's no subtree to the configuration, skip it if (reader == null) { return; } // Otherwise, add what is possible reader.MoveToContent(); // Otherwise, read what we can from the header while (!reader.EOF) { // We only want elements if (reader.NodeType != XmlNodeType.Element) { reader.Read(); continue; } // Get all games items switch (reader.Name.ToLowerInvariant()) { case "imagenumber": // TODO: Read this into a field reader.ReadElementContentAsString(); break; case "releasenumber": // TODO: Read this into a field releaseNumber = reader.ReadElementContentAsString(); break; case "title": machine.Name = reader.ReadElementContentAsString(); break; case "savetype": // TODO: Read this into a field reader.ReadElementContentAsString(); break; case "romsize": size = Sanitizer.CleanLong(reader.ReadElementContentAsString()); break; case "publisher": machine.Publisher = reader.ReadElementContentAsString(); break; case "location": // TODO: Read this into a field reader.ReadElementContentAsString(); break; case "sourcerom": // TODO: Read this into a field reader.ReadElementContentAsString(); break; case "language": // TODO: Read this into a field reader.ReadElementContentAsString(); break; case "files": datItems = ReadFiles(reader.ReadSubtree(), releaseNumber, machine.Name, filename, indexId); // Skip the files node now that we've processed it reader.Skip(); break; case "im1crc": // TODO: Read this into a field reader.ReadElementContentAsString(); break; case "im2crc": // TODO: Read this into a field reader.ReadElementContentAsString(); break; case "comment": machine.Comment = reader.ReadElementContentAsString(); break; case "duplicateid": duplicateid = reader.ReadElementContentAsString(); if (duplicateid != "0") { machine.CloneOf = duplicateid; } break; default: reader.Read(); break; } } // Add information accordingly for each rom for (int i = 0; i < datItems.Count; i++) { datItems[i].Size = size; datItems[i].CopyMachineInformation(machine); // Now process and add the rom ParseAddHelper(datItems[i]); } }
/// <summary> /// Read set information /// </summary> /// <param name="cmpr">ClrMameProReader to use to parse the header</param> /// <param name="filename">Name of the file to be parsed</param> /// <param name="indexId">Index ID for the DAT</param> private void ReadGame(ClrMameProReader cmpr, string filename, int indexId) { // Prepare all internal variables bool containsItems = false; Machine machine = new Machine() { MachineType = MachineType.NULL, }; // If there's no subtree to the header, skip it if (cmpr == null || cmpr.EndOfStream) { return; } // While we don't hit an end element or end of stream while (!cmpr.EndOfStream) { cmpr.ReadNextLine(); // Ignore comments and nothingness if (cmpr.RowType == CmpRowType.None || cmpr.RowType == CmpRowType.Comment) { continue; } // If we reached the end of a section, break if (cmpr.RowType == CmpRowType.EndTopLevel) { break; } // Handle any standalone items if (cmpr.RowType == CmpRowType.Standalone && cmpr.Standalone != null) { string itemKey = cmpr.Standalone?.Key.ToLowerInvariant(); string itemVal = cmpr.Standalone?.Value; switch (itemKey) { case "name": machine.Name = (itemVal.ToLowerInvariant().EndsWith(".zip") ? itemVal.Remove(itemVal.Length - 4) : itemVal); machine.Description = (itemVal.ToLowerInvariant().EndsWith(".zip") ? itemVal.Remove(itemVal.Length - 4) : itemVal); break; } } // Handle any internal items else if (cmpr.RowType == CmpRowType.Internal && string.Equals(cmpr.InternalName, "file", StringComparison.OrdinalIgnoreCase) && cmpr.Internal != null) { containsItems = true; // Create the proper DatItem based on the type Rom item = DatItem.Create(ItemType.Rom) as Rom; // Then populate it with information item.CopyMachineInformation(machine); item.Source = new Source { Index = indexId, Name = filename, }; // Loop through all of the attributes foreach (var kvp in cmpr.Internal) { string attrKey = kvp.Key; string attrVal = kvp.Value; switch (attrKey) { //If the item is empty, we automatically skip it because it's a fluke case "": continue; // Regular attributes case "name": item.Name = attrVal; break; case "size": item.Size = Sanitizer.CleanLong(attrVal); break; case "crc": item.CRC = attrVal; break; case "date": item.Date = attrVal; break; } } // Now process and add the rom ParseAddHelper(item); } } // If no items were found for this machine, add a Blank placeholder if (!containsItems) { Blank blank = new Blank() { Source = new Source { Index = indexId, Name = filename, }, }; blank.CopyMachineInformation(machine); // Now process and add the rom ParseAddHelper(blank); } }
/// <summary> /// Read game/machine information /// </summary> /// <param name="reader">XmlReader to use to parse the machine</param> /// <param name="dirs">List of dirs to prepend to the game name</param> /// <param name="filename">Name of the file to be parsed</param> /// <param name="indexId">Index ID for the DAT</param> /// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param> private void ReadMachine( XmlReader reader, List <string> dirs, // Standard Dat parsing string filename, int indexId, // Miscellaneous bool keep) { // If we have an empty machine, skip it if (reader == null) { return; } // Otherwise, add what is possible reader.MoveToContent(); string key = string.Empty; string temptype = reader.Name; bool containsItems = false; // Create a new machine MachineType machineType = 0x0; if (reader.GetAttribute("isbios").AsYesNo() == true) { machineType |= MachineType.Bios; } if (reader.GetAttribute("isdevice").AsYesNo() == true) // Listxml-specific, used by older DATs { machineType |= MachineType.Device; } if (reader.GetAttribute("ismechanical").AsYesNo() == true) // Listxml-specific, used by older DATs { machineType |= MachineType.Mechanical; } string dirsString = (dirs != null && dirs.Count() > 0 ? string.Join("/", dirs) + "/" : string.Empty); Machine machine = new Machine { Name = dirsString + reader.GetAttribute("name"), Description = dirsString + reader.GetAttribute("name"), SourceFile = reader.GetAttribute("sourcefile"), Board = reader.GetAttribute("board"), RebuildTo = reader.GetAttribute("rebuildto"), Runnable = reader.GetAttribute("runnable").AsRunnable(), // Used by older DATs CloneOf = reader.GetAttribute("cloneof"), RomOf = reader.GetAttribute("romof"), SampleOf = reader.GetAttribute("sampleof"), MachineType = (machineType == 0x0 ? MachineType.NULL : machineType), }; if (Header.Type == "SuperDAT" && !keep) { string tempout = Regex.Match(machine.Name, @".*?\\(.*)").Groups[1].Value; if (!string.IsNullOrWhiteSpace(tempout)) { machine.Name = tempout; } } while (!reader.EOF) { // We only want elements if (reader.NodeType != XmlNodeType.Element) { reader.Read(); continue; } // Get the roms from the machine switch (reader.Name) { case "comment": // There can be multiple comments by spec machine.Comment += reader.ReadElementContentAsString(); break; case "description": machine.Description = reader.ReadElementContentAsString(); break; case "year": machine.Year = reader.ReadElementContentAsString(); break; case "manufacturer": machine.Manufacturer = reader.ReadElementContentAsString(); break; case "publisher": // Not technically supported but used by some legacy DATs machine.Publisher = reader.ReadElementContentAsString(); break; case "category": // Not technically supported but used by some legacy DATs machine.Category = reader.ReadElementContentAsString(); break; case "trurip": // This is special metadata unique to EmuArc ReadTruRip(reader.ReadSubtree(), machine); // Skip the trurip node now that we've processed it reader.Skip(); break; case "archive": containsItems = true; DatItem archive = new Archive { Name = reader.GetAttribute("name"), Source = new Source { Index = indexId, Name = filename, }, }; archive.CopyMachineInformation(machine); // Now process and add the archive key = ParseAddHelper(archive); reader.Read(); break; case "biosset": containsItems = true; DatItem biosSet = new BiosSet { Name = reader.GetAttribute("name"), Description = reader.GetAttribute("description"), Default = reader.GetAttribute("default").AsYesNo(), Source = new Source { Index = indexId, Name = filename, }, }; biosSet.CopyMachineInformation(machine); // Now process and add the biosSet key = ParseAddHelper(biosSet); reader.Read(); break; case "disk": containsItems = true; DatItem disk = new Disk { Name = reader.GetAttribute("name"), MD5 = reader.GetAttribute("md5"), SHA1 = reader.GetAttribute("sha1"), MergeTag = reader.GetAttribute("merge"), ItemStatus = reader.GetAttribute("status").AsItemStatus(), Source = new Source { Index = indexId, Name = filename, }, }; disk.CopyMachineInformation(machine); // Now process and add the disk key = ParseAddHelper(disk); reader.Read(); break; case "media": containsItems = true; DatItem media = new Media { Name = reader.GetAttribute("name"), MD5 = reader.GetAttribute("md5"), SHA1 = reader.GetAttribute("sha1"), SHA256 = reader.GetAttribute("sha256"), SpamSum = reader.GetAttribute("spamsum"), Source = new Source { Index = indexId, Name = filename, }, }; media.CopyMachineInformation(machine); // Now process and add the media key = ParseAddHelper(media); reader.Read(); break; case "release": containsItems = true; DatItem release = new Release { Name = reader.GetAttribute("name"), Region = reader.GetAttribute("region"), Language = reader.GetAttribute("language"), Date = reader.GetAttribute("date"), Default = reader.GetAttribute("default").AsYesNo(), }; release.CopyMachineInformation(machine); // Now process and add the release key = ParseAddHelper(release); reader.Read(); break; case "rom": containsItems = true; DatItem rom = new Rom { Name = reader.GetAttribute("name"), Size = Sanitizer.CleanLong(reader.GetAttribute("size")), CRC = reader.GetAttribute("crc"), MD5 = reader.GetAttribute("md5"), #if NET_FRAMEWORK RIPEMD160 = reader.GetAttribute("ripemd160"), #endif SHA1 = reader.GetAttribute("sha1"), SHA256 = reader.GetAttribute("sha256"), SHA384 = reader.GetAttribute("sha384"), SHA512 = reader.GetAttribute("sha512"), SpamSum = reader.GetAttribute("spamsum"), MergeTag = reader.GetAttribute("merge"), ItemStatus = reader.GetAttribute("status").AsItemStatus(), Date = Sanitizer.CleanDate(reader.GetAttribute("date")), Inverted = reader.GetAttribute("inverted").AsYesNo(), Source = new Source { Index = indexId, Name = filename, }, }; rom.CopyMachineInformation(machine); // Now process and add the rom key = ParseAddHelper(rom); reader.Read(); break; case "sample": containsItems = true; DatItem sample = new Sample { Name = reader.GetAttribute("name"), Source = new Source { Index = indexId, Name = filename, }, }; sample.CopyMachineInformation(machine); // Now process and add the sample key = ParseAddHelper(sample); reader.Read(); break; default: reader.Read(); break; } } // If no items were found for this machine, add a Blank placeholder if (!containsItems) { Blank blank = new Blank() { Source = new Source { Index = indexId, Name = filename, }, }; blank.CopyMachineInformation(machine); // Now process and add the rom ParseAddHelper(blank); } }