Ejemplo n.º 1
0
        /// <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);
                    }
                }
            }
        }