nes-support 8KB PRG roms
This commit is contained in:
parent
e7e8402af0
commit
7d263c9a10
|
@ -276,14 +276,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
/// <summary>
|
||||
/// looks up from the bootgod DB
|
||||
/// </summary>
|
||||
CartInfo IdentifyFromBootGodDB(string hash_sha1)
|
||||
CartInfo IdentifyFromBootGodDB(IEnumerable<string> hash_sha1)
|
||||
{
|
||||
BootGodDB.Initialize();
|
||||
List<CartInfo> 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<CartInfo> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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<string> hash_sha1_several = new List<string>();
|
||||
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
|
||||
|
|
|
@ -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<string, CompactGameInfo> db = new Dictionary<string, CompactGameInfo>();
|
||||
public static class Database
|
||||
{
|
||||
private static Dictionary<string, CompactGameInfo> db = new Dictionary<string, CompactGameInfo>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue