/// <summary>
        /// Fix ROM header using database of popular incorrect ROMs
        /// </summary>
        /// <returns>Flags showing what has been changed</returns>
        public static NesFixType CorrectRom(this NesFile nes)
        {
            NesFixType fixType = NesFixType.NoFix;
            var        crc32   = nes.CalculateCRC32();

            for (int i = 0; i < correct.GetLength(0); i++)
            {
                if (crc32 == correct[i, 0])
                {
                    var mapper    = correct[i, 1] & 0x3FF;
                    var mask      = ((correct[i, 1] & 0x1000) != 0) ? 0xFFF : 0xFF;
                    var mirroring = correct[i, 2];
                    if ((correct[i, 1] >= 0) && (mapper >= 0) && (nes.Mapper != (mapper & mask)))
                    {
                        // invalid mapper
                        nes.Mapper = (ushort)(mapper & mask);
                        fixType   |= NesFixType.Mapper;
                    }
                    if (mirroring >= 0)
                    {
                        if (mirroring == 8 && nes.Mirroring == NesFile.MirroringType.FourScreenVram)
                        {
                            // no four-screen
                            nes.Mirroring = NesFile.MirroringType.Horizontal;
                            fixType      |= NesFixType.Mirroring;
                        }
                        NesFile.MirroringType needMirroring = NesFile.MirroringType.Unknown;
                        switch (mirroring)
                        {
                        case 0:
                            needMirroring = NesFile.MirroringType.Horizontal;
                            break;

                        case 1:
                            needMirroring = NesFile.MirroringType.Vertical;
                            break;

                        case 2:
                            needMirroring = NesFile.MirroringType.FourScreenVram;
                            break;
                        }
                        if (needMirroring != NesFile.MirroringType.Unknown && needMirroring != nes.Mirroring)
                        {
                            nes.Mirroring = needMirroring;
                            fixType      |= NesFixType.Mirroring;
                        }
                    }
                    if ((correct[i, 1] >= 0) && ((correct[i, 1] & 0x800) != 0) && (nes.CHR.Count() > 0))
                    {
                        // no CHR
                        nes.CHR  = Array.Empty <byte>();
                        fixType |= NesFixType.NoChr;
                    }
                }
            }

            var   md5        = nes.CalculateMD5();
            ulong partialmd5 = 0;

            for (int x = 0; x < 8; x++)
            {
                partialmd5 |= (ulong)md5[15 - x] << (x * 8);
            }
            // maybe this games uses battery saves?
            foreach (var sav in savie)
            {
                if (!nes.Battery && sav == partialmd5)
                {
                    nes.Battery = true;
                    fixType    |= NesFixType.Battery;
                }
            }

            return(fixType);
        }
Exemple #2
0
 public Game(string fileName, string menuName = null, Dictionary <uint, GameFix> fixes = null)
 {
     // Separators
     if (fileName == "-")
     {
         MenuName = (string.IsNullOrWhiteSpace(menuName) || menuName == "-") ? "" : menuName;
         FileName = "";
         Flags   |= GameFlags.Separator;
     }
     else
     {
         Console.WriteLine("Loading {0}...", Path.GetFileName(fileName));
         FileName = fileName;
         if (string.IsNullOrWhiteSpace(menuName))
         {
             // Menu name based on filename
             MenuName = Regex.Replace(Path.GetFileNameWithoutExtension(fileName), @"( ?\[.*?\])|( \(.\))", string.Empty).Replace("_", " ").ToUpper().Replace(", THE", "").Trim();
         }
         else
         {
             MenuName = menuName.Trim();
             if (MenuName == "?")
             {
                 Flags |= GameFlags.Hidden;
             }
         }
         // Strip long names
         if (MenuName.Length > 28)
         {
             MenuName = MenuName.Substring(0, 25).Trim() + "...";
         }
         uint crc;
         try
         {
             var nesFile   = new NesFile(fileName);
             var fixResult = nesFile.CorrectRom();
             if (fixResult != 0)
             {
                 Console.WriteLine(" Invalid header. Fix: " + fixResult);
             }
             PRG           = nesFile.PRG;
             PrgSize       = (uint)nesFile.PRG.Count();
             CHR           = nesFile.CHR;
             ChrSize       = (uint)nesFile.CHR.Count();
             Battery       = nesFile.Battery;
             Mapper        = $"{nesFile.Mapper:D3}" + ((nesFile.Submapper > 0) ? $":{nesFile.Submapper}" : "");
             Mirroring     = nesFile.Mirroring;
             ContainerType = NesContainerType.iNES;
             if (nesFile.Trainer != null && nesFile.Trainer.Count() > 0)
             {
                 throw new NotImplementedException(string.Format("{0} - trained games are not supported yet", Path.GetFileName(fileName)));
             }
             if (nesFile.Version == NesFile.iNesVersion.NES20)
             {
                 PrgRamSize = nesFile.PrgRamSize + nesFile.PrgNvRamSize;
                 ChrRamSize = nesFile.ChrRamSize + nesFile.ChrNvRamSize;
             }
             crc = nesFile.CalculateCRC32();
         }
         catch (InvalidDataException)
         {
             var unifFile = new UnifFile(fileName);
             PRG     = unifFile.Fields.Where(k => k.Key.StartsWith("PRG")).OrderBy(k => k.Key).SelectMany(i => i.Value);
             PrgSize = (uint)PRG.Count();
             CHR     = unifFile.Fields.Where(k => k.Key.StartsWith("CHR")).OrderBy(k => k.Key).SelectMany(i => i.Value);
             ChrSize = (uint)CHR.Count();
             Battery = unifFile.Battery;
             var mapper = unifFile.Mapper;
             if (mapper.StartsWith("NES-") || mapper.StartsWith("UNL-") || mapper.StartsWith("HVC-") || mapper.StartsWith("BTL-") || mapper.StartsWith("BMC-"))
             {
                 mapper = mapper.Substring(4);
             }
             Mapper        = mapper;
             Mirroring     = unifFile.Mirroring;
             ContainerType = NesContainerType.UNIF;
             crc           = unifFile.CalculateCRC32();
         }
         // Check for fixes database
         if (fixes != null)
         {
             GameFix fix = null;
             if (fixes.TryGetValue(crc, out fix))
             {
                 if (fix.PrgRamSize.HasValue)
                 {
                     PrgRamSize = fix.PrgRamSize * 1024;
                 }
                 if (fix.ChrRamSize.HasValue)
                 {
                     ChrRamSize = fix.ChrRamSize * 1024;
                 }
                 if (fix.Battery.HasValue)
                 {
                     Battery = fix.Battery.Value;
                 }
                 if (fix.WillNotWorkOnPal)
                 {
                     Flags |= GameFlags.WillNotWorkOnPal;
                 }
                 if (fix.WillNotWorkOnNtsc)
                 {
                     Flags |= GameFlags.WillNotWorkOnNtsc;
                 }
                 if (fix.WillNotWorkOnDendy)
                 {
                     Flags |= GameFlags.WillNotWorkOnDendy;
                 }
                 if (fix.WillNotWorkOnNewFamiclone)
                 {
                     Flags |= GameFlags.WillNotWorkOnNewFamiclone;
                 }
             }
         }
         // External NTRAM is not supported on new famiclones
         if (Mirroring == NesFile.MirroringType.FourScreenVram)
         {
             Flags |= GameFlags.WillNotWorkOnNewFamiclone;
         }
         // Check for round sizes
         if (PrgSize > 0)
         {
             uint roundSize = 1;
             while (roundSize < PrgSize)
             {
                 roundSize <<= 1;
             }
             if (roundSize > PrgSize)
             {
                 var newPrg = new byte[roundSize];
                 for (uint i = PrgSize; i < roundSize; i++)
                 {
                     newPrg[i] = 0xFF;
                 }
                 Array.Copy(PRG.ToArray(), newPrg, PrgSize);
                 PRG     = newPrg;
                 PrgSize = roundSize;
             }
         }
         if (ChrSize > 0)
         {
             uint roundSize = 1;
             while (roundSize < ChrSize)
             {
                 roundSize <<= 1;
             }
             if (roundSize > ChrSize)
             {
                 var newChr = new byte[roundSize];
                 for (uint i = ChrSize; i < roundSize; i++)
                 {
                     newChr[i] = 0xFF;
                 }
                 Array.Copy(CHR.ToArray(), newChr, ChrSize);
                 CHR     = newChr;
                 ChrSize = roundSize;
             }
         }
     }
 }