262 lines
6.3 KiB
C#
262 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using BizHawk.Emulation.Common;
|
|
using BizHawk.Emulation.DiscSystem;
|
|
|
|
namespace BizHawk.Client.DBMan
|
|
{
|
|
public class InitialRomInfo
|
|
{
|
|
public string FileName;
|
|
public string Name;
|
|
public string VersionTags;
|
|
public string GuessedSystem;
|
|
public string GuessedRegion;
|
|
public string CRC32;
|
|
public string MD5;
|
|
public string SHA1;
|
|
public long Size;
|
|
|
|
public override string ToString()
|
|
{
|
|
return FileName;
|
|
}
|
|
}
|
|
|
|
public static class RomHasher
|
|
{
|
|
public static InitialRomInfo Generate(string file)
|
|
{
|
|
//if (isDiscImage(file))
|
|
// return HashDiscImage(file);
|
|
|
|
return GenerateRomHashDirect(file, File.ReadAllBytes(file));
|
|
}
|
|
|
|
static char[] modifierStartChars = { '(', '[' };
|
|
static InitialRomInfo GenerateRomHashDirect(string file, byte[] filebytes)
|
|
{
|
|
var info = new InitialRomInfo();
|
|
var fileInfo = new FileInfo(file);
|
|
string ext = fileInfo.Extension.ToLowerInvariant().Replace(".", "");
|
|
info.FileName = fileInfo.Name;
|
|
|
|
// Parse the filename to guess things about the rom
|
|
var name = Path.GetFileNameWithoutExtension(fileInfo.Name);
|
|
if (name.StartsWith("[BIOS] "))
|
|
name = name.Replace("[BIOS] ","") + " [BIOS]";
|
|
|
|
string modifiers = "";
|
|
int modIndex = name.IndexOfAny(modifierStartChars);
|
|
if (modIndex > 0)
|
|
{
|
|
modifiers = name.Substring(modIndex);
|
|
name = name.Substring(0, modIndex);
|
|
}
|
|
info.Name = name.Trim();
|
|
|
|
// parse out modifiers
|
|
var mods = new List<string>();
|
|
modifiers = modifiers.Replace(")", ";").Replace("]",";");
|
|
modifiers = modifiers.Replace("(", "").Replace("[", "");
|
|
var m_ = modifiers.Split(';');
|
|
foreach (var mi in m_)
|
|
{
|
|
var m = mi.Trim();
|
|
if (m.Length == 0) continue;
|
|
mods.Add(m);
|
|
}
|
|
|
|
info.VersionTags = "";
|
|
foreach (var mi in mods)
|
|
{
|
|
if (info.VersionTags.Length != 0)
|
|
info.VersionTags += ";";
|
|
|
|
switch (mi.ToLower())
|
|
{
|
|
case "j":
|
|
case "jp":
|
|
case "jpn":
|
|
case "japan":
|
|
info.GuessedRegion = "Japan";
|
|
break;
|
|
case "usa":
|
|
case "us":
|
|
case "u":
|
|
info.GuessedRegion = "USA";
|
|
break;
|
|
case "europe":
|
|
case "eur":
|
|
case "e":
|
|
info.GuessedRegion = "Europe";
|
|
break;
|
|
case "world":
|
|
case "w":
|
|
info.GuessedRegion = "World";
|
|
break;
|
|
case "korea":
|
|
case "kr":
|
|
case "k":
|
|
info.GuessedRegion = "Korea";
|
|
break;
|
|
case "brazil":
|
|
case "br":
|
|
info.GuessedRegion = "Brazil";
|
|
break;
|
|
case "taiwan":
|
|
case "tw":
|
|
info.GuessedRegion = "Taiwan";
|
|
break;
|
|
case "usa, europe":
|
|
info.GuessedRegion = "USA;Europe";
|
|
break;
|
|
case "japan, europe":
|
|
info.GuessedRegion = "Europe;Japan";
|
|
break;
|
|
case "japan, usa":
|
|
info.GuessedRegion = "USA;Japan";
|
|
break;
|
|
|
|
default:
|
|
info.VersionTags += mi;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// transform binary to canonical binary representation (de-header/de-stripe/de-swap)
|
|
byte[] romBytes = filebytes;
|
|
switch (ext)
|
|
{
|
|
case "sms":
|
|
case "gg":
|
|
case "sg":
|
|
case "pce":
|
|
case "sgx":
|
|
romBytes = MaybeStripHeader512(filebytes);
|
|
break;
|
|
|
|
case "smd":
|
|
if (filebytes.Length % 1024 == 512)
|
|
System.Windows.Forms.MessageBox.Show("derp");
|
|
romBytes = DeInterleaveSMD(filebytes);
|
|
break;
|
|
|
|
case "z64":
|
|
case "n64":
|
|
case "v64":
|
|
throw new NotImplementedException("n64 demutate not done");
|
|
}
|
|
|
|
// guess system
|
|
switch (ext)
|
|
{
|
|
case "sms": info.GuessedSystem = "SMS"; break;
|
|
case "gg": info.GuessedSystem = "GG"; break;
|
|
case "sg": info.GuessedSystem = "SG"; break;
|
|
case "pce": info.GuessedSystem = "PCE"; break;
|
|
case "sgx": info.GuessedSystem = "SGX"; break;
|
|
case "smd":
|
|
case "gen": info.GuessedSystem = "GEN"; break;
|
|
case "nes": info.GuessedSystem = "NES"; break;
|
|
default: info.GuessedSystem = "Unknown"; break;
|
|
}
|
|
|
|
// Perform hashing
|
|
info.CRC32 = Hash_CRC32(romBytes);
|
|
info.MD5 = Hash_MD5(romBytes);
|
|
info.SHA1 = Hash_SHA1(romBytes);
|
|
info.Size = romBytes.Length;
|
|
|
|
return info;
|
|
}
|
|
|
|
static string HashDiscImage(string file)
|
|
{
|
|
try
|
|
{
|
|
string ext = new FileInfo(file).Extension.ToLowerInvariant();
|
|
using (var disc = ext == ".iso" ? Disc.FromIsoPath(file) : Disc.FromCuePath(file, new CueBinPrefs()))
|
|
{
|
|
return disc.GetHash();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
return "Error Hashing Disc";
|
|
}
|
|
}
|
|
|
|
static string Hash_CRC32(byte[] data)
|
|
{
|
|
return string.Format("{0:X8}", CRC32.Calculate(data));
|
|
}
|
|
|
|
static string Hash_SHA1(byte[] data)
|
|
{
|
|
using (var sha1 = System.Security.Cryptography.SHA1.Create())
|
|
{
|
|
sha1.TransformFinalBlock(data, 0, data.Length);
|
|
return BytesToHexString(sha1.Hash);
|
|
}
|
|
}
|
|
|
|
static string Hash_MD5(byte[] data)
|
|
{
|
|
using (var md5 = System.Security.Cryptography.MD5.Create())
|
|
{
|
|
md5.TransformFinalBlock(data, 0, data.Length);
|
|
return BytesToHexString(md5.Hash);
|
|
}
|
|
}
|
|
|
|
static string BytesToHexString(byte[] bytes)
|
|
{
|
|
var sb = new StringBuilder();
|
|
foreach (var b in bytes)
|
|
sb.AppendFormat("{0:X2}", b);
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
static byte[] MaybeStripHeader512(byte[] fileBytes)
|
|
{
|
|
if (fileBytes.Length % 1024 != 512)
|
|
return fileBytes;
|
|
|
|
var romBytes = new byte[fileBytes.Length - 512];
|
|
Array.Copy(fileBytes, 512, romBytes, 0, fileBytes.Length - 512);
|
|
return romBytes;
|
|
}
|
|
|
|
static byte[] DeInterleaveSMD(byte[] source)
|
|
{
|
|
int size = source.Length;
|
|
if (size > 0x400000)
|
|
size = 0x400000;
|
|
|
|
int pages = size / 0x4000;
|
|
var output = new byte[size];
|
|
|
|
for (int page = 0; page < pages; page++)
|
|
{
|
|
for (int i = 0; i < 0x2000; i++)
|
|
{
|
|
output[(page * 0x4000) + (i * 2) + 0] = source[(page * 0x4000) + 0x2000 + i];
|
|
output[(page * 0x4000) + (i * 2) + 1] = source[(page * 0x4000) + 0x0000 + i];
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
static bool isDiscImage(string file)
|
|
{
|
|
var ext = new FileInfo(file).Extension.ToLowerInvariant();
|
|
if (ext == ".cue" || ext == ".iso")
|
|
return true;
|
|
return false;
|
|
}
|
|
}
|
|
} |