/// <summary> /// Given a HashFlags value, applies DB hints provided in DB config /// </summary> /// <remarks>Some Examples: CRC32 will be converted to RomHash | CRC32 for No-Intro, /// or RomHash_ByteSwapped | CRC32 for No-Intro N64</remarks> private HashFlags GetHashFlags(HashFlags hashFlags) { if ((hashFlags & (HashFlags.FileHash | HashFlags.RomHash)) == 0) { // File or ROM not specified? Use DB default. if ((info.Hints & DBHints.ByteSwapped) != 0) { return(hashFlags | HashFlags.RomHash_ByteSwap); } else if ((info.Hints & DBHints.DefaultHash_ROM) != 0) { return(hashFlags | HashFlags.RomHash); } else if ((info.Hints & DBHints.DefaultHash_File) != 0) { return(hashFlags | HashFlags.FileHash); } // No specified for DB? Guess. return(hashFlags | HashFlags.FileHash); } else { return(hashFlags); } }
/// <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> /// Gets a friendly name for a ROM hash type /// </summary> /// <param name="flags">Hash type</param> /// <returns>A string representation of the hash type</returns> public static string GetHashName(HashFlags flags) { string result; if (NamedHashFlags.TryGetValue(flags, out result)) { return(result); } return("(" + flags.ToString() + ")"); }
/// <summary> /// Returns a ROM hash specified, or null if it is not found. If multiple applicable hashes are found, the first one is returned. /// </summary> /// <param name="hashType">The hash to retreive.</param> /// <returns>A RomHash object.</returns> public RomHash GetHash(HashFlags hashType) { for (int i = 0; i < Hashes.Count; i++) { if (Hashes[i].Type == hashType) { return(Hashes[i]); } } return(null); }
/// <summary> /// Returns a set of hashes that match the specified filter. /// </summary> /// <param name="filter">A filter that specifies which flags are required for a hash.</param> /// <returns></returns> public IList <RomHash> GetHashes(HashFlags filter) { List <RomHash> result = new List <RomHash>(); if ((int)filter != 0) { for (int i = 0; i < Hashes.Count; i++) { if ((Hashes[i].Type & filter) != 0) { result.Add(Hashes[i]); } } } return(result); }
/// <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); }
/// <summary> /// Identifies whether the program configuration requres the specified hash for a given platform /// </summary> /// <param name="p">The platform in question</param> /// <param name="hash">The hash algorithm and type</param> /// <returns>True if the hash is required, otherwise false.</returns> public static bool IsHashRequired(Platform p, HashFlags hash) { if (Program.Config.SkipExtraHashes) { // Skip PRG, CHR, and if ((hash & HashFlags.SHA256) != 0) { return(false); } if ((hash & (HashFlags.ChrHash | HashFlags.PrgHash)) != 0) { return(false); } return(true); } else { return(true); } }
/// <summary> /// Converts a bit-field into an array of single-bit values /// </summary> /// <param name="allAlgos"></param> /// <returns></returns> IList <HashFlags> getAlgos(HashFlags allAlgos) { List <HashFlags> result = new List <HashFlags>(); if ((allAlgos & HashFlags.CRC32) != 0) { result.Add(HashFlags.CRC32); } if ((allAlgos & HashFlags.SHA1) != 0) { result.Add(HashFlags.SHA1); } if ((allAlgos & HashFlags.SHA256) != 0) { result.Add(HashFlags.SHA256); } if ((allAlgos & HashFlags.MD5) != 0) { result.Add(HashFlags.MD5); } return(result); }
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])); } } } } } } }
void IHashWorkManager.AddHashes(byte[] buffer, int start, int len, HashFlags algso, HashFlags type) { ((IHashWorkManager)this).AddHashes(buffer, start, len, null, algso, type); }
/// <summary> /// Gets the content this hash is for, i.e. ROM, entire file, etc /// </summary> public static HashFlags GetContents(this HashFlags h) { return(h & HashContentFilter); }
/// <summary> /// Creates a RomHash object with the specified data /// </summary> /// <param name="value">Hash value</param> /// <param name="type">Hash type</param> public RomHash(byte[] value, HashFlags type) { this.Value = value; this.Type = type; }
/// <summary> /// Gets the algorithm for this hash, i.e. MD5, SHA1, etc /// </summary> public static HashFlags GetAlgorithm(this HashFlags h) { return(h & HashAlgorithmFilter); }
public override void CalculateHashes(byte[] rom, IHashWorkManager worker, float startProgress, float endProgress) { // N64 hashes are calculated using the thread pool because the ROMs tend to be large bool byteswapped = N64.IsByteswapped(rom) == N64ByteSwap.Swapped; byte[] swappedRom = new byte[rom.Length]; // Watch out for odd # of bytes! int len = rom.Length & (~1); for (int i = 0; i < len; i += 2) { swappedRom[i] = rom[i + 1]; swappedRom[i + 1] = rom[i]; } HashFlags originalType = byteswapped ? HashFlags.RomHash_ByteSwap : HashFlags.RomHash; HashFlags swappedType = byteswapped ? HashFlags.RomHash : HashFlags.RomHash_ByteSwap; worker.QueueTask((SimpleDelegate) delegate { if (!worker.AbortPending) { worker.AddHashes(rom, 0, rom.Length, () => worker.AbortPending, HashFlags.SHA256, originalType, HashFlags.FileHash); } }); worker.QueueTask((SimpleDelegate) delegate { if (!worker.AbortPending) { worker.AddHashes(rom, 0, rom.Length, () => worker.AbortPending, HashFlags.SHA1, originalType, HashFlags.FileHash); } }); worker.QueueTask((SimpleDelegate) delegate { if (!worker.AbortPending) { worker.AddHashes(rom, 0, rom.Length, () => worker.AbortPending, HashFlags.CRC32, originalType, HashFlags.FileHash); } }); worker.QueueTask((SimpleDelegate) delegate { if (!worker.AbortPending) { worker.AddHashes(rom, 0, rom.Length, () => worker.AbortPending, HashFlags.MD5, originalType, HashFlags.FileHash); } }); // We can not byte-swap the ROM while it is being hashed worker.WaitAll(); worker.QueueTask((SimpleDelegate) delegate { if (!worker.AbortPending) { worker.AddHashes(swappedRom, 0, swappedRom.Length, () => worker.AbortPending, HashFlags.SHA256, swappedType); } }); worker.QueueTask((SimpleDelegate) delegate { if (!worker.AbortPending) { worker.AddHashes(swappedRom, 0, swappedRom.Length, () => worker.AbortPending, HashFlags.SHA1, swappedType); } }); worker.QueueTask((SimpleDelegate) delegate { if (!worker.AbortPending) { worker.AddHashes(swappedRom, 0, swappedRom.Length, () => worker.AbortPending, HashFlags.CRC32, swappedType); } }); worker.QueueTask((SimpleDelegate) delegate { if (!worker.AbortPending) { worker.AddHashes(swappedRom, 0, swappedRom.Length, () => worker.AbortPending, HashFlags.MD5, swappedType); } }); // We can not return until all hashes are calculated worker.WaitAll(); }