using System; using System.IO; using System.Linq; using SabreTools.Hashing; using SabreTools.IO.Extensions; namespace SabreTools.Core.Tools { /// /// Static utility functions used throughout the library /// public static class Utilities { /// /// Determine if two hashes are equal for the purposes of merging /// public static bool ConditionalHashEquals(byte[]? firstHash, byte[]? secondHash) { // If either hash is empty, we say they're equal for merging if (firstHash.IsNullOrEmpty() || secondHash.IsNullOrEmpty()) return true; // If they're different sizes, they can't match if (firstHash!.Length != secondHash!.Length) return false; // Otherwise, they need to match exactly return firstHash.SequenceEqual(secondHash); } /// /// Determine if two hashes are equal for the purposes of merging /// public static bool ConditionalHashEquals(string? firstHash, string? secondHash) { // If either hash is empty, we say they're equal for merging if (string.IsNullOrEmpty(firstHash) || string.IsNullOrEmpty(secondHash)) return true; // If they're different sizes, they can't match if (firstHash!.Length != secondHash!.Length) return false; // Otherwise, they need to match exactly return string.Equals(firstHash, secondHash, StringComparison.OrdinalIgnoreCase); } /// /// Get a proper romba sub path /// /// SHA-1 hash to get the path for /// Positive value representing the depth of the depot /// Subfolder path for the given hash public static string? GetDepotPath(byte[]? hash, int depth) { string? sha1 = hash.ToHexString(); return GetDepotPath(sha1, depth); } /// /// Get a proper romba sub path /// /// SHA-1 hash to get the path for /// Positive value representing the depth of the depot /// Subfolder path for the given hash public static string? GetDepotPath(string? hash, int depth) { // If the hash is null or empty, then we return null if (string.IsNullOrEmpty(hash)) return null; // If the hash isn't the right size, then we return null if (hash!.Length != Constants.SHA1Length) return null; // Cap the depth between 0 and 20, for now if (depth < 0) depth = 0; else if (depth > ZeroHash.SHA1Arr.Length) depth = ZeroHash.SHA1Arr.Length; // Loop through and generate the subdirectory string path = string.Empty; for (int i = 0; i < depth; i++) { path += hash.Substring(i * 2, 2) + Path.DirectorySeparatorChar; } // Now append the filename path += $"{hash}.gz"; return path; } /// /// Get if the given path has a valid DAT extension /// /// Path to check /// True if the extension is valid, false otherwise public static bool HasValidDatExtension(string? path) { // If the path is null or empty, then we return false if (string.IsNullOrEmpty(path)) return false; // Get the extension from the path, if possible string ext = Path.GetExtension(path).TrimStart('.').ToLowerInvariant(); // Check against the list of known DAT extensions return ext switch { "csv" => true, "dat" => true, "json" => true, "md2" => true, "md4" => true, "md5" => true, "sfv" => true, "sha1" => true, "sha256" => true, "sha384" => true, "sha512" => true, "spamsum" => true, "ssv" => true, "tsv" => true, "txt" => true, "xml" => true, _ => false, }; } } }