// Returns false if any db hashes disagree with the given rom hash private bool hashMatches(IList <RomHash> dbHashes, RomHash romHash) { for (int i = 0; i < dbHashes.Count; i++) { if (dbHashes[i].Type == romHash.Type) { if (dbHashes[i].Value.Length != romHash.Value.Length) { System.Diagnostics.Debug.Fail("Why would this ever happen?"); return(false); } byte[] dbh = dbHashes[i].Value; byte[] rh = romHash.Value; for (int iByte = 0; iByte < dbh.Length; iByte++) { if (dbh[iByte] != rh[iByte]) { return(false); } } } } return(true); }
/// <summary> /// Adds hashes to specified string builder for summary box. SB. /// </summary> /// <param name="hashes">A list of hashes to add. This list will be destroyed.</param> /// <param name="prefix">A string to prefix to hash name, e.g. "Patched" -> "Patched File MD5:..."</param> /// <param name="sb"></param> private void AddHashesToSB(StringBuilder sb, List <RomHash> hashes, string prefix) { // Why do I make things more complicated than they need to be? if (string.IsNullOrEmpty(prefix)) { prefix = string.Empty; } else { prefix += " "; } while (hashes.Count > 0) { // Grab last hash var hash = hashes[0]; hashes.RemoveAt(0); // For ROM/FILE hashes, if two are the same, we want to report them as one // Example: a headerless SNES ROM will have identical file and ROM hashes because the file is a plain ROM image, // so we can report it as a "File/ROM SHA-1" rather than as two seprate hashes with identical values // Get the desired type of hash we want to check, e.g. for ROM SHA-1, we want to see if File SHA-1 is the same. HashFlags altHashType = 0; if (hash.Type.GetContents() == HashFlags.FileHash) { altHashType = HashFlags.RomHash | hash.Type.GetAlgorithm(); } else if (hash.Type.GetContents() == HashFlags.RomHash) { altHashType = HashFlags.FileHash | hash.Type.GetAlgorithm(); } RomHash altHash = null; if (altHashType != 0) { for (int i = 0; i < hashes.Count; i++) { // Find the right hash, and check its value if (hashes[i].Type == altHashType && CompareByteArrays(hash.Value, hashes[i].Value)) { // Match? Cool beans altHash = hashes[i]; hashes.RemoveAt(i); break; // for } } } var hashType = hash.Type; if (altHash != null) { hashType |= altHash.Type; } string hashname = RomHash.GetHashName(hashType); sb.AppendLine(prefix + hashname + ": " + Hex.FormatHex(hash.Value)); } }
/// <summary> /// Adds standard ROM details /// </summary> /// <param name="builder">Data builder</param> /// <param name="rom">ROM image</param> /// <param name="data">ROM information</param> private void AddStandardData(RomExDataBuilder builder, byte[] rom, RomData data) { const string general = RomExDataBuilder.GeneralCat; builder.AddData(general, "Platform", data.Platform.ID.GetDescription()); builder.AddData(general, "ROM format", data.FormatName); if (data.ExternalHeader != null) { builder.AddData(general, "External Header", data.ExternalHeader.Value ? "Yes" : "No"); } builder.AddData(general, "File Size", data.FileSize.ToString() + " (" + data.FileSize.ToString("x") + ")"); builder.AddData(general, "ROM Size", data.RomSize.ToString() + " (" + data.RomSize.ToString("x") + ")"); // ROM hashes var crc32 = data.GetHash(HashFlags.RomHash | HashFlags.CRC32); var sha1 = data.GetHash(HashFlags.RomHash | HashFlags.SHA1); if (crc32 != null) { builder.AddData(general, RomHash.GetHashName(HashFlags.RomHash | HashFlags.CRC32), Hex.FormatHex(crc32.Value)); } if (sha1 != null) { builder.AddData(general, RomHash.GetHashName(HashFlags.RomHash | HashFlags.SHA1), Hex.FormatHex(sha1.Value)); } // File hashes as a last resort when ROM hashes aren't present if (crc32 == null) { crc32 = data.GetHash(HashFlags.FileHash | HashFlags.CRC32); if (crc32 != null) { builder.AddData(general, RomHash.GetHashName(HashFlags.FileHash | HashFlags.CRC32), Hex.FormatHex(crc32.Value)); } } if (sha1 == null) { sha1 = data.GetHash(HashFlags.FileHash | HashFlags.SHA1); if (sha1 != null) { builder.AddData(general, RomHash.GetHashName(HashFlags.FileHash | HashFlags.SHA1), Hex.FormatHex(sha1.Value)); } } for (int i = 0; i < data.DatabaseMatches.Count; i++) { var match = data.DatabaseMatches[i]; builder.AddData(general, match.Database.Name + " entry", match.Entry.name); } for (int i = 0; i < data.Hashes.Count; i++) { builder.AddData( RomExDataBuilder.HashesCat, RomHash.GetHashName(data.Hashes[i].Type), Hex.FormatHex(data.Hashes[i].Value)); } }
void IHashWorkManager.AddHashes(byte[] buffer, int start, int len, HASH.Platform.AsyncCancelCheck cancelCheck, HashFlags algos, HashFlags type, params HashFlags[] additionalTypes) { var allalgos = getAlgos(algos); if (allalgos.Count == 0) { throw new ArgumentException("Hash algorithm not specified."); } foreach (var algo in allalgos) { if (RomHash.IsHashRequired(Platform, algo | type)) { byte[] hash = null; if (cancelCheck == null || cancelCheck() == false) { switch (algo) { case HashFlags.MD5: hash = CalculateMD5(buffer, start, len); break; case HashFlags.SHA1: hash = CalculateSha1(buffer, start, len, cancelCheck); break; case HashFlags.SHA256: hash = CalculateSha256(buffer, start, len, cancelCheck); break; case HashFlags.CRC32: hash = CalculateCRC32(buffer, start, len); break; } } if (hash != null) { lock (HashesLock) { _Hashes.Add(new RomHash(hash, algo | type)); if (additionalTypes != null) { for (int i = 0; i < additionalTypes.Length; i++) { _Hashes.Add(new RomHash(hash, algo | additionalTypes[i])); } } } } } } }
/// <summary> /// Attempts to find the specified hash and append it to the string builder for RHDN-specific output. /// </summary> /// <param name="hashtype">The hash type (i.e. CRC32/MD5/SHA1). File/ROM/PRG/CHR should NOT be specified.</param> /// <returns>True if ANYTHING was appended to the string builder.</returns> /// <param name="rom"></param> /// <param name="sb"></param> private static bool AddHashToSB(StringBuilder sb, RomData rom, HashFlags hashtype) { string hashname = RomHash.GetHashName(HashFlags.RomHash | hashtype); var hash = rom.GetHash(HashFlags.RomHash | hashtype); if (hash == null) { hashname = hashname = RomHash.GetHashName(HashFlags.FileHash | hashtype);; hash = rom.GetHash(HashFlags.FileHash | hashtype); } if (hash == null) { return(false); } sb.AppendLine(hashname + ": " + Hex.FormatHex(hash.Value)); return(true); }
private void TryParseGame(CmpReader reader) { if (reader.OpenItem()) { RomDB.Entry entry = new RomDB.Entry(); string name = null; string crc32 = null; string sha1 = null; string md5 = null; string size = null; bool romRead = false; while (reader.NextItem()) { if (reader.SelectionName == "name" & name == null) { name = reader.SelectionValue; } else if (reader.SelectionName == "rom" & !romRead) { if (reader.OpenItem()) { romRead = true; while (reader.NextItem()) { if (reader.SelectionName == "size" & size == null) { size = reader.SelectionValue; } else if (reader.SelectionName == "crc" & crc32 == null) { crc32 = reader.SelectionValue; } else if (reader.SelectionName == "sha1" & sha1 == null) { sha1 = reader.SelectionValue; } else if (reader.SelectionName == "md5" && md5 == null) { md5 = reader.SelectionValue; } } } reader.CloseItem(); } } if (name != null) { entry.name = name; if (size != null) { entry.size = ParseInt(size); } // Todo: report invalidly sized hashes? if (crc32 != null) { var crc32hash = new RomHash(ParseHexBytes(crc32), GetHashFlags(HashFlags.CRC32)); if (crc32hash.Value.Length == 4) { entry.Hashes.Add(crc32hash); } } if (sha1 != null) { var sha1Hash = new RomHash(ParseHexBytes(sha1), GetHashFlags(HashFlags.SHA1)); if (sha1Hash.Value.Length == 20) { entry.Hashes.Add(sha1Hash); } } if (md5 != null) { var md5Hash = new RomHash(ParseHexBytes(md5), GetHashFlags(HashFlags.MD5)); if (md5Hash.Value.Length == 16) { entry.Hashes.Add(md5Hash); } } } reader.CloseItem(); result.AddEntry(entry); } }