diff --git a/Barotrauma/BarotraumaClient/ClientSource/Program.cs b/Barotrauma/BarotraumaClient/ClientSource/Program.cs index ad60eb631b..9c2b1f1635 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Program.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Program.cs @@ -114,7 +114,7 @@ static void CrashDump(GameMain game, string filePath, Exception exception) try { string exePath = System.Reflection.Assembly.GetEntryAssembly().Location; - exeHash = Md5Hash.CalculateForFile(exePath, Md5Hash.StringHashOptions.BytePerfect); + exeHash = Md5Hash.CalculateForFile(exePath); } catch { diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ContentFile.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ContentFile.cs index b7d896fe60..ab21d3f3b0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ContentFile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ContentFile.cs @@ -144,7 +144,7 @@ public virtual void Preload(Action addPreloadedSprite) { } public virtual Md5Hash CalculateHash() { - return Md5Hash.CalculateForFile(Path.Value, Md5Hash.StringHashOptions.IgnoreWhitespace); + return Md5Hash.CalculateForFile(Path.Value); } public bool NotSyncedInMultiplayer => Types.Any(t => t.Type == GetType() && t.NotSyncedInMultiplayer); diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/SubmarineFile.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/SubmarineFile.cs index f24a0fc4b3..a62b43190d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/SubmarineFile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/SubmarineFile.cs @@ -31,7 +31,7 @@ public override void Sort() // Use byte-perfect hash because this is compressed, trimming whitespace is incorrect and needlessly slow here public override Md5Hash CalculateHash() - => Md5Hash.CalculateForFile(Path.FullPath, Md5Hash.StringHashOptions.BytePerfect); + => Md5Hash.CalculateForFile(Path.FullPath); } [NotSyncedInMultiplayer] diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameAnalytics/GameAnalyticsManager.cs b/Barotrauma/BarotraumaShared/SharedSource/GameAnalytics/GameAnalyticsManager.cs index 3abffee202..839c6bd3f9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameAnalytics/GameAnalyticsManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameAnalytics/GameAnalyticsManager.cs @@ -541,7 +541,7 @@ private static void Init() Md5Hash? exeHash = null; try { - exeHash = Md5Hash.CalculateForFile(exePath, Md5Hash.StringHashOptions.BytePerfect); + exeHash = Md5Hash.CalculateForFile(exePath); } catch (Exception e) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs index 2ae85e4ebb..13d0e2c3b2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs @@ -160,8 +160,7 @@ public Md5Hash MD5Hash { if (hashTask == null) { - XDocument doc = OpenFile(FilePath); - StartHashDocTask(doc); + StartHashDocTask(); } hashTask.Wait(); hashTask = null; @@ -381,7 +380,7 @@ public void Reload() } if (hash == null) { - StartHashDocTask(doc); + StartHashDocTask(); } SubmarineElement = doc.Root; } @@ -528,14 +527,14 @@ public bool IsVanillaSubmarine() return false; } - public void StartHashDocTask(XDocument doc) + public void StartHashDocTask() { if (hash != null) { return; } if (hashTask != null) { return; } hashTask = new Task(() => { - hash = Md5Hash.CalculateForString(doc.ToString(), Md5Hash.StringHashOptions.IgnoreWhitespace); + hash = Md5Hash.CalculateForFile(FilePath); }); hashTask.Start(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/Md5Hash.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/Md5Hash.cs index c672b5745e..ef837b2b68 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Utils/Md5Hash.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/Md5Hash.cs @@ -1,8 +1,8 @@ #nullable enable -using Barotrauma.IO; using System; using System.Collections.Generic; +using System.IO; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -43,6 +43,17 @@ private static void CalculateHash(byte[] bytes, out string stringRepresentation, } } + private static void CalculateHashStream(Stream stream, out string stringRepresentation, out byte[] byteRepresentation) + { + using (MD5 md5 = MD5.Create()) + { + byte[] byteHash = md5.ComputeHash(stream); + + byteRepresentation = byteHash; + stringRepresentation = ByteRepresentationToStringRepresentation(byteHash); + } + } + private static string ByteRepresentationToStringRepresentation(byte[] byteHash) => ToolBoxCore.ByteArrayToHexString(byteHash); @@ -76,6 +87,13 @@ private Md5Hash(byte[] bytes, bool calculate) ShortRepresentation = GetShortHash(StringRepresentation); } + + private Md5Hash(Stream stream) + { + CalculateHashStream(stream, out StringRepresentation, out ByteRepresentation); + + ShortRepresentation = GetShortHash(StringRepresentation); + } public static Md5Hash StringAsHash(string hash) { @@ -111,17 +129,11 @@ public enum StringHashOptions IgnoreWhitespace = 0x2 } - public static Md5Hash CalculateForFile(string path, StringHashOptions options) + public static Md5Hash CalculateForFile(string path) { - if (options.HasFlag(StringHashOptions.IgnoreWhitespace) || options.HasFlag(StringHashOptions.IgnoreCase)) - { - string str = File.ReadAllText(path, Encoding.UTF8); - return CalculateForString(str, options); - } - else + using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { - byte[] bytes = File.ReadAllBytes(path); - return CalculateForBytes(bytes); + return new Md5Hash(stream); } }