using System; using System.Collections.Generic; using System.IO; using SabreTools.Data.Models.Hashfile; using SabreTools.Hashing; #pragma warning disable CA1822 // Mark members as static namespace SabreTools.Serialization.Readers { public class Hashfile : BaseBinaryReader { #region IByteReader /// public override Data.Models.Hashfile.Hashfile? Deserialize(byte[]? data, int offset) => Deserialize(data, offset, HashType.CRC32); /// public Data.Models.Hashfile.Hashfile? Deserialize(byte[]? data, int offset, HashType hash) { // If the data is invalid if (data is null || data.Length == 0) return null; // If the offset is out of bounds if (offset < 0 || offset >= data.Length) return null; // Create a memory stream and parse that var dataStream = new MemoryStream(data, offset, data.Length - offset); return Deserialize(dataStream, hash); } #endregion #region IFileReader /// public override Data.Models.Hashfile.Hashfile? Deserialize(string? path) => Deserialize(path, HashType.CRC32); /// public Data.Models.Hashfile.Hashfile? Deserialize(string? path, HashType hash) { try { // If we don't have a file if (string.IsNullOrEmpty(path) || !File.Exists(path)) return default; // Open the file for deserialization using var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); return Deserialize(stream, hash); } catch { // TODO: Handle logging the exception return default; } } #endregion #region IStreamReader public override Data.Models.Hashfile.Hashfile? Deserialize(Stream? data) => Deserialize(data, HashType.CRC32); /// public Data.Models.Hashfile.Hashfile? Deserialize(Stream? data, HashType hash) { if (hash == HashType.CRC32) return DeserializeSFV(data); else if (hash == HashType.MD2) return DeserializeMD2(data); else if (hash == HashType.MD4) return DeserializeMD4(data); else if (hash == HashType.MD5) return DeserializeMD5(data); else if (hash == HashType.RIPEMD128) return DeserializeRIPEMD128(data); else if (hash == HashType.RIPEMD160) return DeserializeRIPEMD160(data); else if (hash == HashType.SHA1) return DeserializeSHA1(data); else if (hash == HashType.SHA256) return DeserializeSHA256(data); else if (hash == HashType.SHA384) return DeserializeSHA384(data); else if (hash == HashType.SHA512) return DeserializeSHA512(data); else if (hash == HashType.SpamSum) return DeserializeSpamSum(data); else return null; } /// public Data.Models.Hashfile.Hashfile? DeserializeSFV(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Setup the reader and output var reader = new StreamReader(data); var sfvList = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; var sfv = new SFV { File = string.Join(" ", lineParts, 0, lineParts.Length - 1), #if NETCOREAPP || NETSTANDARD2_1_OR_GREATER Hash = lineParts[^1], #else Hash = lineParts[lineParts.Length - 1], #endif }; sfvList.Add(sfv); } // Assign the hashes to the hashfile and return if (sfvList.Count > 0) return new Data.Models.Hashfile.Hashfile { SFV = [.. sfvList] }; return null; } catch { // Ignore the actual error return null; } } /// public Data.Models.Hashfile.Hashfile? DeserializeMD2(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Setup the reader and output var reader = new StreamReader(data); var md2List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var md2 = new MD2 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; md2List.Add(md2); } // Assign the hashes to the hashfile and return if (md2List.Count > 0) return new Data.Models.Hashfile.Hashfile { MD2 = [.. md2List] }; return null; } catch { // Ignore the actual error return null; } } /// public Data.Models.Hashfile.Hashfile? DeserializeMD4(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Setup the reader and output var reader = new StreamReader(data); var md4List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var md4 = new MD4 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; md4List.Add(md4); } // Assign the hashes to the hashfile and return if (md4List.Count > 0) return new Data.Models.Hashfile.Hashfile { MD4 = [.. md4List] }; return null; } catch { // Ignore the actual error return null; } } /// public Data.Models.Hashfile.Hashfile? DeserializeMD5(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; // Setup the reader and output var reader = new StreamReader(data); var md5List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var md5 = new MD5 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; md5List.Add(md5); } // Assign the hashes to the hashfile and return if (md5List.Count > 0) return new Data.Models.Hashfile.Hashfile { MD5 = [.. md5List] }; return null; } /// public Data.Models.Hashfile.Hashfile? DeserializeRIPEMD128(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; // Setup the reader and output var reader = new StreamReader(data); var ripemd128List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var ripemd128 = new RIPEMD128 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; ripemd128List.Add(ripemd128); } // Assign the hashes to the hashfile and return if (ripemd128List.Count > 0) return new Data.Models.Hashfile.Hashfile { RIPEMD128 = [.. ripemd128List] }; return null; } /// public Data.Models.Hashfile.Hashfile? DeserializeRIPEMD160(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; // Setup the reader and output var reader = new StreamReader(data); var ripemd160List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var ripemd160 = new RIPEMD160 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; ripemd160List.Add(ripemd160); } // Assign the hashes to the hashfile and return if (ripemd160List.Count > 0) return new Data.Models.Hashfile.Hashfile { RIPEMD160 = [.. ripemd160List] }; return null; } /// public Data.Models.Hashfile.Hashfile? DeserializeSHA1(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Setup the reader and output var reader = new StreamReader(data); var sha1List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var sha1 = new SHA1 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; sha1List.Add(sha1); } // Assign the hashes to the hashfile and return if (sha1List.Count > 0) return new Data.Models.Hashfile.Hashfile { SHA1 = [.. sha1List] }; return null; } catch { // Ignore the actual error return null; } } /// public Data.Models.Hashfile.Hashfile? DeserializeSHA256(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Setup the reader and output var reader = new StreamReader(data); var sha256List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var sha256 = new SHA256 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; sha256List.Add(sha256); } // Assign the hashes to the hashfile and return if (sha256List.Count > 0) return new Data.Models.Hashfile.Hashfile { SHA256 = [.. sha256List] }; return null; } catch { // Ignore the actual error return null; } } /// public Data.Models.Hashfile.Hashfile? DeserializeSHA384(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Setup the reader and output var reader = new StreamReader(data); var sha384List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var sha384 = new SHA384 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; sha384List.Add(sha384); } // Assign the hashes to the hashfile and return if (sha384List.Count > 0) return new Data.Models.Hashfile.Hashfile { SHA384 = [.. sha384List] }; return null; } catch { // Ignore the actual error return null; } } /// public Data.Models.Hashfile.Hashfile? DeserializeSHA512(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Setup the reader and output var reader = new StreamReader(data); var sha512List = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var sha512 = new SHA512 { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; sha512List.Add(sha512); } // Assign the hashes to the hashfile and return if (sha512List.Count > 0) return new Data.Models.Hashfile.Hashfile { SHA512 = [.. sha512List] }; return null; } catch { // Ignore the actual error return null; } } /// public Data.Models.Hashfile.Hashfile? DeserializeSpamSum(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return default; try { // Setup the reader and output var reader = new StreamReader(data); var spamsumList = new List(); // Loop through the rows and parse out values while (!reader.EndOfStream) { // Read and split the line string? line = reader.ReadLine(); string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries); if (lineParts is null || lineParts.Length < 2) continue; // Parse the line into a hash var spamSum = new SpamSum { Hash = lineParts[0], File = string.Join(" ", lineParts, 1, lineParts.Length - 1), }; spamsumList.Add(spamSum); } // Assign the hashes to the hashfile and return if (spamsumList.Count > 0) return new Data.Models.Hashfile.Hashfile { SpamSum = [.. spamsumList] }; return null; } catch { // Ignore the actual error return null; } } #endregion } }