diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
index 4b19a8e010..0ab243d6c1 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
@@ -276,14 +276,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo
///
/// looks up from the bootgod DB
///
- CartInfo IdentifyFromBootGodDB(string hash_sha1)
+ CartInfo IdentifyFromBootGodDB(IEnumerable hash_sha1)
{
BootGodDB.Initialize();
- List choices = BootGodDB.Instance.Identify(hash_sha1);
- if (choices.Count == 0) return null;
-
- //pick the first board for this hash arbitrarily. it probably doesn't make a difference
- return choices[0];
+ foreach (var hash in hash_sha1)
+ {
+ List choices = BootGodDB.Instance.Identify(hash);
+ //pick the first board for this hash arbitrarily. it probably doesn't make a difference
+ if (choices.Count != 0)
+ return choices[0];
+ }
+ return null;
}
///
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs
index e068fc9cc4..fc1abc7532 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs
@@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
case "NAMCOT-3301":
case "HVC-HROM": //Donkey Kong Jr. (J)
case "JALECO-JF-01": //Exerion (J)
- AssertPrg(16, 32); AssertChr(8); AssertVram(0); AssertWram(0, 8);
+ AssertPrg(8, 16, 32); AssertChr(8); AssertVram(0); AssertWram(0, 8);
break;
case "NROM-HOMEBREW":
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
index 1f2b9592dc..c053d1ba24 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
@@ -404,30 +404,38 @@ namespace BizHawk.Emulation.Consoles.Nintendo
header->Cleanup();
//now that we know we have an iNES header, we can try to ignore it.
- string hash_sha1;
- string hash_md5;
- using (var sha1 = System.Security.Cryptography.SHA1.Create())
- {
- sha1.TransformFinalBlock(file, 16, file.Length - 16);
- hash_sha1 = "sha1:" + Util.BytesToHexString(sha1.Hash);
- }
- using (var md5 = System.Security.Cryptography.MD5.Create())
- {
- md5.TransformFinalBlock(file, 16, file.Length - 16);
- hash_md5 = "md5:" + Util.BytesToHexString(md5.Hash);
- }
+
+ List hash_sha1_several = new List();
+ string hash_sha1 = "sha1:" + Util.Hash_SHA1(file,16,file.Length - 16);
+ hash_sha1_several.Add(hash_sha1);
+ string hash_md5 = "md5:" + Util.Hash_MD5(file, 16, file.Length - 16);
LoadWriteLine("Found iNES header:");
CartInfo iNesHeaderInfo = header->Analyze();
- LoadWriteLine("Since this is iNES we can confidently parse PRG/CHR banks to hash.");
+ LoadWriteLine("Since this is iNES we can (somewhat) confidently parse PRG/CHR banks to hash.");
LoadWriteLine("headerless rom hash: {0}", hash_sha1);
LoadWriteLine("headerless rom hash: {0}", hash_md5);
+ if (iNesHeaderInfo.prg_size == 16)
+ {
+ //8KB prg can't be stored in iNES format, which counts 16KB prg banks.
+ //so a correct hash will include only 8KB.
+ LoadWriteLine("Since this rom has a 16 KB PRG, we'll hash it as 8KB too for bootgod's DB:");
+ var msTemp = new MemoryStream();
+ msTemp.Write(file, 16, 8 * 1024); //add prg
+ msTemp.Write(file, 16 + 16 * 1024, iNesHeaderInfo.chr_size * 1024); //add chr
+ msTemp.Flush();
+ var bytes = msTemp.ToArray();
+ var hash = "sha1:" + Util.Hash_SHA1(bytes, 0, bytes.Length);
+ LoadWriteLine("PRG (8KB) + CHR hash: {0}", hash);
+ hash_sha1_several.Add(hash);
+ }
+
Type boardType = null;
CartInfo choice = null;
if (USE_DATABASE)
- choice = IdentifyFromBootGodDB(hash_sha1);
+ choice = IdentifyFromBootGodDB(hash_sha1_several);
if (choice == null)
{
LoadWriteLine("Could not locate game in nescartdb");
@@ -547,7 +555,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
if (choice.chr_size > 0)
{
board.VROM = new byte[choice.chr_size * 1024];
- Array.Copy(file, 16 + board.ROM.Length, board.VROM, 0, board.VROM.Length);
+ int vrom_offset = iNesHeaderInfo.prg_size * 1024;
+ Array.Copy(file, 16 + vrom_offset, board.VROM, 0, board.VROM.Length);
}
//create the vram and wram if necessary
diff --git a/BizHawk.Emulation/Database/Database.cs b/BizHawk.Emulation/Database/Database.cs
index 5adb014d22..de035ed5e2 100644
--- a/BizHawk.Emulation/Database/Database.cs
+++ b/BizHawk.Emulation/Database/Database.cs
@@ -5,18 +5,18 @@ using System.Threading;
namespace BizHawk
{
- internal class CompactGameInfo
- {
- public string Name;
- public string System;
- public string MetaData;
- public string Hash;
- public RomStatus Status;
- }
+ internal class CompactGameInfo
+ {
+ public string Name;
+ public string System;
+ public string MetaData;
+ public string Hash;
+ public RomStatus Status;
+ }
- public static class Database
- {
- private static Dictionary db = new Dictionary();
+ public static class Database
+ {
+ private static Dictionary db = new Dictionary();
static string RemoveHashType(string hash)
{
@@ -28,15 +28,15 @@ namespace BizHawk
public static GameInfo CheckDatabase(string hash)
{
- CompactGameInfo cgi;
+ CompactGameInfo cgi;
string hash_notype = RemoveHashType(hash);
db.TryGetValue(hash_notype, out cgi);
- if (cgi == null)
- {
- Console.WriteLine("Game with hash " + hash + " was not in game database.");
- return null;
- }
- return new GameInfo(cgi);
+ if (cgi == null)
+ {
+ Console.WriteLine("DB: hash " + hash + " not in game database.");
+ return null;
+ }
+ return new GameInfo(cgi);
}
static void LoadDatabase_Escape(string line)
@@ -52,97 +52,98 @@ namespace BizHawk
Console.WriteLine("BENIGN: missing external game database {0}", line);
}
- public static void LoadDatabase(string path)
- {
- using (var reader = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
- {
- while (reader.EndOfStream == false)
- {
- string line = reader.ReadLine();
- try
- {
+ public static void LoadDatabase(string path)
+ {
+ using (var reader = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
+ {
+ while (reader.EndOfStream == false)
+ {
+ string line = reader.ReadLine();
+ try
+ {
if (line.StartsWith(";")) continue; //comment
if (line.StartsWith("#"))
{
LoadDatabase_Escape(line);
continue;
}
- if (line.Trim().Length == 0) continue;
- string[] items = line.Split('\t');
+ if (line.Trim().Length == 0) continue;
+ string[] items = line.Split('\t');
- var Game = new CompactGameInfo();
+ var Game = new CompactGameInfo();
//remove a hash type identifier. well don't really need them for indexing (theyre just there for human purposes)
Game.Hash = RemoveHashType(items[0].ToUpper());
- switch (items[1].Trim())
- {
- case "B": Game.Status = RomStatus.BadDump; break;
- case "V": Game.Status = RomStatus.BadDump; break;
- case "T": Game.Status = RomStatus.TranslatedRom; break;
- case "O": Game.Status = RomStatus.Overdump; break;
- case "I": Game.Status = RomStatus.BIOS; break;
- case "D": Game.Status = RomStatus.Homebrew; break;
- case "H": Game.Status = RomStatus.Hack; break;
- default: Game.Status = RomStatus.GoodDump; break;
- }
- Game.Name = items[2];
- Game.System = items[3];
- Game.MetaData = items.Length >= 6 ? items[5] : null;
+ switch (items[1].Trim())
+ {
+ case "B": Game.Status = RomStatus.BadDump; break;
+ case "V": Game.Status = RomStatus.BadDump; break;
+ case "T": Game.Status = RomStatus.TranslatedRom; break;
+ case "O": Game.Status = RomStatus.Overdump; break;
+ case "I": Game.Status = RomStatus.BIOS; break;
+ case "D": Game.Status = RomStatus.Homebrew; break;
+ case "H": Game.Status = RomStatus.Hack; break;
+ default: Game.Status = RomStatus.GoodDump; break;
+ }
+ Game.Name = items[2];
+ Game.System = items[3];
+ Game.MetaData = items.Length >= 6 ? items[5] : null;
- if (db.ContainsKey(Game.Hash))
- Console.WriteLine("gamedb: Multiple hash entries {0}, duplicate detected on {1}",Game.Hash, Game.Name);
+ if (db.ContainsKey(Game.Hash))
+ Console.WriteLine("gamedb: Multiple hash entries {0}, duplicate detected on {1}", Game.Hash, Game.Name);
- db[Game.Hash] = Game;
- } catch
- {
- Console.WriteLine("Error parsing database entry: "+line);
- }
- }
- }
- }
+ db[Game.Hash] = Game;
+ }
+ catch
+ {
+ Console.WriteLine("Error parsing database entry: " + line);
+ }
+ }
+ }
+ }
- public static GameInfo GetGameInfo(byte[] RomData, string fileName)
- {
+ public static GameInfo GetGameInfo(byte[] RomData, string fileName)
+ {
CompactGameInfo cgi;
string hash = string.Format("{0:X8}", CRC32.Calculate(RomData));
- if (db.TryGetValue(hash, out cgi))
- return new GameInfo(cgi);
+ if (db.TryGetValue(hash, out cgi))
+ return new GameInfo(cgi);
- hash = Util.BytesToHexString(System.Security.Cryptography.MD5.Create().ComputeHash(RomData));
- if (db.TryGetValue(hash, out cgi))
- return new GameInfo(cgi);
+ hash = Util.BytesToHexString(System.Security.Cryptography.MD5.Create().ComputeHash(RomData));
+ if (db.TryGetValue(hash, out cgi))
+ return new GameInfo(cgi);
hash = Util.BytesToHexString(System.Security.Cryptography.SHA1.Create().ComputeHash(RomData));
- if (db.TryGetValue(hash, out cgi))
- return new GameInfo(cgi);
+ if (db.TryGetValue(hash, out cgi))
+ return new GameInfo(cgi);
- // rom is not in database. make some best-guesses
- var Game = new GameInfo { Hash = hash, Status = RomStatus.NotInDatabase, NotInDatabase = true };
- Console.WriteLine("Game was not in DB. CRC: {0:X8} MD5: {1}",
- CRC32.Calculate(RomData),
- Util.BytesToHexString(System.Security.Cryptography.MD5.Create().ComputeHash(RomData)));
+ // rom is not in database. make some best-guesses
+ var Game = new GameInfo { Hash = hash, Status = RomStatus.NotInDatabase, NotInDatabase = true };
+ Console.WriteLine("Game was not in DB. CRC: {0:X8} MD5: {1}",
+ CRC32.Calculate(RomData),
+ Util.BytesToHexString(System.Security.Cryptography.MD5.Create().ComputeHash(RomData)));
- string ext = Path.GetExtension(fileName).ToUpperInvariant();
+ string ext = Path.GetExtension(fileName).ToUpperInvariant();
- switch (ext)
- {
- case ".SMS": Game.System = "SMS"; break;
- case ".GG" : Game.System = "GG"; break;
- case ".SG" : Game.System = "SG"; break;
- case ".PCE": Game.System = "PCE"; break;
- case ".SGX": Game.System = "SGX"; break;
- case ".GB" : Game.System = "GB"; break;
- case ".BIN":
- case ".GEN":
- case ".SMD": Game.System = "GEN"; break;
- case ".NES": Game.System = "NES"; break;
- }
+ switch (ext)
+ {
+ case ".SMS": Game.System = "SMS"; break;
+ case ".GG": Game.System = "GG"; break;
+ case ".SG": Game.System = "SG"; break;
+ case ".PCE": Game.System = "PCE"; break;
+ case ".SGX": Game.System = "SGX"; break;
+ case ".GB": Game.System = "GB"; break;
+ case ".BIN":
+ case ".GEN":
+ case ".SMD": Game.System = "GEN"; break;
+ case ".NES": Game.System = "NES"; break;
+ }
- Game.Name = Path.GetFileNameWithoutExtension(fileName).Replace('_', ' ');
- // If filename is all-caps, then attempt to proper-case the title.
- if (Game.Name == Game.Name.ToUpperInvariant())
- Game.Name = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(Game.Name.ToLower());
+ Game.Name = Path.GetFileNameWithoutExtension(fileName).Replace('_', ' ');
+ // If filename is all-caps, then attempt to proper-case the title.
+ if (Game.Name == Game.Name.ToUpperInvariant())
+ Game.Name = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(Game.Name.ToLower());
- return Game;
- }
- }
+ return Game;
+ }
+ }
}