diff --git a/SabreTools.Helper/Data/Flags.cs b/SabreTools.Helper/Data/Flags.cs index 9e07744f..af9e65e6 100644 --- a/SabreTools.Helper/Data/Flags.cs +++ b/SabreTools.Helper/Data/Flags.cs @@ -262,6 +262,7 @@ namespace SabreTools.Helper.Data SHA256 = SHA1 << 1, SHA384 = SHA256 << 1, SHA512 = SHA384 << 1, + xxHash = SHA512 << 1, // Special combinations Standard = CRC | MD5 | SHA1, diff --git a/SabreTools.Helper/External/xxHash.cs b/SabreTools.Helper/External/xxHash.cs new file mode 100644 index 00000000..dd86db78 --- /dev/null +++ b/SabreTools.Helper/External/xxHash.cs @@ -0,0 +1,252 @@ +/* +xxHashSharp - A pure C# implementation of xxhash +Copyright (C) 2014, Seok-Ju, Yun. (https://github.com/noricube/xxHashSharp) +Original C Implementation Copyright (C) 2012-2014, Yann Collet. (https://code.google.com/p/xxhash/) +BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; + +namespace xxHashSharp +{ + public class xxHash + { + public struct XXH_State + { + public ulong total_len; + public uint seed; + public uint v1; + public uint v2; + public uint v3; + public uint v4; + public int memsize; + public byte[] memory; + }; + + const uint PRIME32_1 = 2654435761U; + const uint PRIME32_2 = 2246822519U; + const uint PRIME32_3 = 3266489917U; + const uint PRIME32_4 = 668265263U; + const uint PRIME32_5 = 374761393U; + + protected XXH_State _state; + public xxHash() + { + + } + + public static uint CalculateHash(byte[] buf, int len = -1, uint seed = 0) + { + uint h32; + int index = 0; + if (len == -1) + { + len = buf.Length; + } + + + if (len >= 16) + { + int limit = len - 16; + uint v1 = seed + PRIME32_1 + PRIME32_2; + uint v2 = seed + PRIME32_2; + uint v3 = seed + 0; + uint v4 = seed - PRIME32_1; + + do + { + v1 = CalcSubHash(v1, buf, index); + index += 4; + v2 = CalcSubHash(v2, buf, index); + index += 4; + v3 = CalcSubHash(v3, buf, index); + index += 4; + v4 = CalcSubHash(v4, buf, index); + index += 4; + } while (index <= limit); + + h32 = RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18); + } + else + { + h32 = seed + PRIME32_5; + } + + h32 += (uint)len; + + while (index <= len - 4) + { + h32 += BitConverter.ToUInt32(buf, index) * PRIME32_3; + h32 = RotateLeft(h32, 17) * PRIME32_4; + index += 4; + } + + while (index < len) + { + h32 += buf[index] * PRIME32_5; + h32 = RotateLeft(h32, 11) * PRIME32_1; + index++; + } + + h32 ^= h32 >> 15; + h32 *= PRIME32_2; + h32 ^= h32 >> 13; + h32 *= PRIME32_3; + h32 ^= h32 >> 16; + + return h32; + } + + public void Init(uint seed = 0) + { + _state.seed = seed; + _state.v1 = seed + PRIME32_1 + PRIME32_2; + _state.v2 = seed + PRIME32_2; + _state.v3 = seed + 0; + _state.v4 = seed - PRIME32_1; + _state.total_len = 0; + _state.memsize = 0; + _state.memory = new byte[16]; + } + + public bool Update(byte[] input, int len) + { + int index = 0; + + _state.total_len += (uint)len; + + if (_state.memsize + len < 16) // 버퍼 + 입력길이가 16바이트 이하일경우 버퍼에 저장만 해둔다 + { + Array.Copy(input, 0, _state.memory, _state.memsize, len); + _state.memsize += len; + + return true; + } + + if (_state.memsize > 0) // 이전데이터가 남아있을경우 먼저 처리한다. + { + Array.Copy(input, 0, _state.memory, _state.memsize, 16 - _state.memsize); + + _state.v1 = CalcSubHash(_state.v1, _state.memory, index); + index += 4; + _state.v2 = CalcSubHash(_state.v2, _state.memory, index); + index += 4; + _state.v3 = CalcSubHash(_state.v3, _state.memory, index); + index += 4; + _state.v4 = CalcSubHash(_state.v4, _state.memory, index); + index += 4; + + index = 0; + _state.memsize = 0; + } + + if (index <= len - 16) + { + int limit = len - 16; + uint v1 = _state.v1; + uint v2 = _state.v2; + uint v3 = _state.v3; + uint v4 = _state.v4; + + do + { + v1 = CalcSubHash(v1, input, index); + index += 4; + v2 = CalcSubHash(v2, input, index); + index += 4; + v3 = CalcSubHash(v3, input, index); + index += 4; + v4 = CalcSubHash(v4, input, index); + index += 4; + } while (index <= limit); + + _state.v1 = v1; + _state.v2 = v2; + _state.v3 = v3; + _state.v4 = v4; + } + + if (index < len) + { + Array.Copy(input, index, _state.memory, 0, len - index); + _state.memsize = len - index; + } + return true; + } + + public uint Digest() + { + uint h32; + int index = 0; + if (_state.total_len >= 16) + { + h32 = RotateLeft(_state.v1, 1) + RotateLeft(_state.v2, 7) + RotateLeft(_state.v3, 12) + RotateLeft(_state.v4, 18); + } + else + { + h32 = _state.seed + PRIME32_5; + } + + h32 += (UInt32)_state.total_len; + + while (index <= _state.memsize - 4) + { + h32 += BitConverter.ToUInt32(_state.memory, index) * PRIME32_3; + h32 = RotateLeft(h32, 17) * PRIME32_4; + index += 4; + } + + while (index < _state.memsize) + { + h32 += _state.memory[index] * PRIME32_5; + h32 = RotateLeft(h32, 11) * PRIME32_1; + index++; + } + + h32 ^= h32 >> 15; + h32 *= PRIME32_2; + h32 ^= h32 >> 13; + h32 *= PRIME32_3; + h32 ^= h32 >> 16; + + return h32; + } + private static uint CalcSubHash(uint value, byte[] buf, int index) + { + uint read_value = BitConverter.ToUInt32(buf, index); + value += read_value * PRIME32_2; + value = RotateLeft(value, 13); + value *= PRIME32_1; + return value; + } + + private static uint RotateLeft(uint value, int count) + { + return (value << count) | (value >> (32 - count)); + } + + } +} \ No newline at end of file diff --git a/SabreTools.Helper/SabreTools.Helper.csproj b/SabreTools.Helper/SabreTools.Helper.csproj index e04633a5..a1d66a43 100644 --- a/SabreTools.Helper/SabreTools.Helper.csproj +++ b/SabreTools.Helper/SabreTools.Helper.csproj @@ -124,6 +124,7 @@ + diff --git a/SabreTools.Helper/Tools/FileTools.cs b/SabreTools.Helper/Tools/FileTools.cs index 6e45b4bd..624419ff 100644 --- a/SabreTools.Helper/Tools/FileTools.cs +++ b/SabreTools.Helper/Tools/FileTools.cs @@ -27,6 +27,7 @@ using StreamReader = System.IO.StreamReader; #endif using NaturalSort; using OCRC; +using xxHashSharp; namespace SabreTools.Helper.Tools { @@ -536,6 +537,8 @@ namespace SabreTools.Helper.Tools SHA256 sha256 = SHA256.Create(); SHA384 sha384 = SHA384.Create(); SHA512 sha512 = SHA512.Create(); + xxHash xxHash = new xxHash(); + xxHash.Init(); // Seek to the starting position, if one is set if (offset < 0) @@ -572,6 +575,10 @@ namespace SabreTools.Helper.Tools { sha512.TransformBlock(buffer, 0, read, buffer, 0); } + if ((omitFromScan & Hash.xxHash) == 0) + { + xxHash.Update(buffer, read); + } } crc.Update(buffer, 0, 0); @@ -602,6 +609,10 @@ namespace SabreTools.Helper.Tools sha512.TransformFinalBlock(buffer, 0, 0); rom.SHA512 = BitConverter.ToString(sha512.Hash).Replace("-", "").ToLowerInvariant(); } + if ((omitFromScan & Hash.xxHash) == 0) + { + rom.SHA512 = xxHash.Digest().ToString("X").ToLowerInvariant(); + } // Dispose of the hashers crc.Dispose();