Start introducing concept of internal hashes

This commit is contained in:
Matt Nadareski
2025-01-05 21:11:14 -05:00
parent 39f02b3ee1
commit fe78a5532f
6 changed files with 175 additions and 140 deletions

View File

@@ -12,6 +12,30 @@ namespace SabreTools.FileTypes.Aaru
/// </summary>
public class AaruFormat : BaseFile
{
#region Fields
/// <summary>
/// Internal MD5 hash of the file
/// </summary>
public byte[]? InternalMD5 { get; set; }
/// <summary>
/// Internal SHA-1 hash of the file
/// </summary>
public byte[]? InternalSHA1 { get; set; }
/// <summary>
/// Internal SHA-256 hash of the file
/// </summary>
public byte[]? InternalSHA256 { get; set; }
/// <summary>
/// Internal SpamSum fuzzy hash of the file
/// </summary>
public byte[]? InternalSpamSum { get; set; }
#endregion
#region Private instance variables
#region Header
@@ -113,102 +137,100 @@ namespace SabreTools.FileTypes.Aaru
{
try
{
AaruFormat aif = new();
var aif = new AaruFormat();
#if NET20 || NET35 || NET40
using (BinaryReader br = new(stream, Encoding.Default))
#else
using (BinaryReader br = new(stream, Encoding.Default, true))
#endif
aif.Identifier = stream.ReadUInt64();
byte[] applicationBytes = stream.ReadBytes(64);
aif.Application = Encoding.Unicode.GetString(applicationBytes);
aif.ImageMajorVersion = stream.ReadByteValue();
aif.ImageMinorVersion = stream.ReadByteValue();
aif.ApplicationMajorVersion = stream.ReadByteValue();
aif.ApplicationMinorVersion = stream.ReadByteValue();
aif.MediaType = (AaruMediaType)stream.ReadUInt32();
aif.IndexOffset = stream.ReadUInt64();
aif.CreationTime = stream.ReadInt64();
aif.LastWrittenTime = stream.ReadInt64();
// If the offset is bigger than the stream, we can't read it
if (aif.IndexOffset > (ulong)stream.Length)
return null;
// Otherwise, we read in the index header
stream.Seek((long)aif.IndexOffset, SeekOrigin.Begin);
aif.IndexHeader = IndexHeader.Deserialize(stream);
if (aif.IndexHeader.entries == 0)
return null;
// Get the list of entries
aif.IndexEntries = new IndexEntry[aif.IndexHeader.entries];
for (ushort index = 0; index < aif.IndexHeader.entries; index++)
{
aif.Identifier = br.ReadUInt64();
aif.Application = Encoding.Unicode.GetString(br.ReadBytes(64), 0, 64);
aif.ImageMajorVersion = br.ReadByte();
aif.ImageMinorVersion = br.ReadByte();
aif.ApplicationMajorVersion = br.ReadByte();
aif.ApplicationMinorVersion = br.ReadByte();
aif.MediaType = (AaruMediaType)br.ReadUInt32();
aif.IndexOffset = br.ReadUInt64();
aif.CreationTime = br.ReadInt64();
aif.LastWrittenTime = br.ReadInt64();
// If the offset is bigger than the stream, we can't read it
if (aif.IndexOffset > (ulong)stream.Length)
return null;
// Otherwise, we read in the index header
stream.Seek((long)aif.IndexOffset, SeekOrigin.Begin);
aif.IndexHeader = IndexHeader.Deserialize(stream);
if (aif.IndexHeader.entries == 0)
return null;
// Get the list of entries
aif.IndexEntries = new IndexEntry[aif.IndexHeader.entries];
for (ushort index = 0; index < aif.IndexHeader.entries; index++)
aif.IndexEntries[index] = IndexEntry.Deserialize(stream);
switch (aif.IndexEntries[index].blockType)
{
aif.IndexEntries[index] = IndexEntry.Deserialize(stream);
switch (aif.IndexEntries[index].blockType)
{
// We don't do anything with these block types currently
case AaruBlockType.DataBlock:
case AaruBlockType.DeDuplicationTable:
case AaruBlockType.Index:
case AaruBlockType.Index2:
case AaruBlockType.GeometryBlock:
case AaruBlockType.MetadataBlock:
case AaruBlockType.TracksBlock:
case AaruBlockType.CicmBlock:
case AaruBlockType.DataPositionMeasurementBlock:
case AaruBlockType.SnapshotBlock:
case AaruBlockType.ParentBlock:
case AaruBlockType.DumpHardwareBlock:
case AaruBlockType.TapeFileBlock:
case AaruBlockType.TapePartitionBlock:
case AaruBlockType.CompactDiscIndexesBlock:
// No-op
break;
// We don't do anything with these block types currently
case AaruBlockType.DataBlock:
case AaruBlockType.DeDuplicationTable:
case AaruBlockType.Index:
case AaruBlockType.Index2:
case AaruBlockType.GeometryBlock:
case AaruBlockType.MetadataBlock:
case AaruBlockType.TracksBlock:
case AaruBlockType.CicmBlock:
case AaruBlockType.DataPositionMeasurementBlock:
case AaruBlockType.SnapshotBlock:
case AaruBlockType.ParentBlock:
case AaruBlockType.DumpHardwareBlock:
case AaruBlockType.TapeFileBlock:
case AaruBlockType.TapePartitionBlock:
case AaruBlockType.CompactDiscIndexesBlock:
// No-op
break;
// Read in all available hashes
case AaruBlockType.ChecksumBlock:
// If the offset is bigger than the stream, we can't read it
if (aif.IndexEntries[index].offset > (ulong)stream.Length)
return null;
// Read in all available hashes
case AaruBlockType.ChecksumBlock:
// If the offset is bigger than the stream, we can't read it
if (aif.IndexEntries[index].offset > (ulong)stream.Length)
return null;
// Otherwise, we read in the block
stream.Seek((long)aif.IndexEntries[index].offset, SeekOrigin.Begin);
ChecksumHeader checksumHeader = ChecksumHeader.Deserialize(stream);
if (checksumHeader.entries == 0)
return null;
// Otherwise, we read in the block
stream.Seek((long)aif.IndexEntries[index].offset, SeekOrigin.Begin);
ChecksumHeader checksumHeader = ChecksumHeader.Deserialize(stream);
if (checksumHeader.entries == 0)
return null;
// Read through each and pick out the ones we care about
for (byte entry = 0; entry < checksumHeader.entries; entry++)
// Read through each and pick out the ones we care about
for (byte entry = 0; entry < checksumHeader.entries; entry++)
{
ChecksumEntry? checksumEntry = ChecksumEntry.Deserialize(stream);
if (checksumEntry == null)
continue;
switch (checksumEntry.type)
{
ChecksumEntry? checksumEntry = ChecksumEntry.Deserialize(stream);
if (checksumEntry == null)
continue;
switch (checksumEntry.type)
{
case AaruChecksumAlgorithm.Invalid:
break;
case AaruChecksumAlgorithm.Md5:
aif.MD5 = checksumEntry.checksum;
break;
case AaruChecksumAlgorithm.Sha1:
aif.SHA1 = checksumEntry.checksum;
break;
case AaruChecksumAlgorithm.Sha256:
aif.SHA256 = checksumEntry.checksum;
break;
case AaruChecksumAlgorithm.SpamSum:
aif.SpamSum = checksumEntry.checksum;
break;
}
case AaruChecksumAlgorithm.Invalid:
break;
case AaruChecksumAlgorithm.Md5:
aif.MD5 = checksumEntry.checksum;
aif.InternalMD5 = checksumEntry.checksum;
break;
case AaruChecksumAlgorithm.Sha1:
aif.SHA1 = checksumEntry.checksum;
aif.InternalSHA1 = checksumEntry.checksum;
break;
case AaruChecksumAlgorithm.Sha256:
aif.SHA256 = checksumEntry.checksum;
aif.InternalSHA256 = checksumEntry.checksum;
break;
case AaruChecksumAlgorithm.SpamSum:
aif.SpamSum = checksumEntry.checksum;
aif.InternalSpamSum = checksumEntry.checksum;
break;
}
}
// Once we got hashes, we return early
return aif;
}
// Once we got hashes, we return early
return aif;
}
}

View File

@@ -1,5 +1,5 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
namespace SabreTools.FileTypes.Aaru
{
@@ -25,19 +25,12 @@ namespace SabreTools.FileTypes.Aaru
{
var checksumEntry = new ChecksumEntry();
#if NET20 || NET35 || NET40
using (var br = new BinaryReader(stream, Encoding.Default))
#else
using (var br = new BinaryReader(stream, Encoding.Default, true))
#endif
{
checksumEntry.type = (AaruChecksumAlgorithm)br.ReadByte();
checksumEntry.length = br.ReadUInt32();
if (checksumEntry.length == 0)
return null;
checksumEntry.type = (AaruChecksumAlgorithm)stream.ReadByteValue();
checksumEntry.length = stream.ReadUInt32();
if (checksumEntry.length == 0)
return null;
checksumEntry.checksum = br.ReadBytes((int)checksumEntry.length);
}
checksumEntry.checksum = stream.ReadBytes((int)checksumEntry.length);
return checksumEntry;
}

View File

@@ -1,5 +1,5 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
namespace SabreTools.FileTypes.Aaru
{
@@ -24,18 +24,11 @@ namespace SabreTools.FileTypes.Aaru
/// <returns>Populated ChecksumHeader, null on failure</returns>
public static ChecksumHeader Deserialize(Stream stream)
{
ChecksumHeader checksumHeader = new ChecksumHeader();
var checksumHeader = new ChecksumHeader();
#if NET20 || NET35 || NET40
using (var br = new BinaryReader(stream, Encoding.Default))
#else
using (var br = new BinaryReader(stream, Encoding.Default, true))
#endif
{
checksumHeader.identifier = (AaruBlockType)br.ReadUInt32();
checksumHeader.length = br.ReadUInt32();
checksumHeader.entries = br.ReadByte();
}
checksumHeader.identifier = (AaruBlockType)stream.ReadUInt32();
checksumHeader.length = stream.ReadUInt32();
checksumHeader.entries = stream.ReadByteValue();
return checksumHeader;
}

View File

@@ -1,5 +1,5 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
namespace SabreTools.FileTypes.Aaru
{
@@ -23,18 +23,11 @@ namespace SabreTools.FileTypes.Aaru
/// <returns>Populated IndexHeader, null on failure</returns>
public static IndexEntry Deserialize(Stream stream)
{
IndexEntry indexEntry = new IndexEntry();
var indexEntry = new IndexEntry();
#if NET20 || NET35 || NET40
using (var br = new BinaryReader(stream, Encoding.Default))
#else
using (var br = new BinaryReader(stream, Encoding.Default, true))
#endif
{
indexEntry.blockType = (AaruBlockType)br.ReadUInt32();
indexEntry.dataType = (AaruDataType)br.ReadUInt16();
indexEntry.offset = br.ReadUInt64();
}
indexEntry.blockType = (AaruBlockType)stream.ReadUInt32();
indexEntry.dataType = (AaruDataType)stream.ReadUInt16();
indexEntry.offset = stream.ReadUInt64();
return indexEntry;
}

View File

@@ -1,5 +1,5 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
namespace SabreTools.FileTypes.Aaru
{
@@ -25,16 +25,9 @@ namespace SabreTools.FileTypes.Aaru
{
var indexHeader = new IndexHeader();
#if NET20 || NET35 || NET40
using (var br = new BinaryReader(stream, Encoding.Default))
#else
using (var br = new BinaryReader(stream, Encoding.Default, true))
#endif
{
indexHeader.identifier = (AaruBlockType)br.ReadUInt32();
indexHeader.entries = br.ReadUInt16();
indexHeader.crc64 = br.ReadUInt64();
}
indexHeader.identifier = (AaruBlockType)stream.ReadUInt32();
indexHeader.entries = stream.ReadUInt16();
indexHeader.crc64 = stream.ReadUInt64();
return indexHeader;
}

View File

@@ -5,6 +5,20 @@ namespace SabreTools.FileTypes.CHD
{
public class CHDFile : BaseFile
{
#region Fields
/// <summary>
/// Internal MD5 hash of the file
/// </summary>
public byte[]? InternalMD5 { get; set; }
/// <summary>
/// Internal SHA-1 hash of the file
/// </summary>
public byte[]? InternalSHA1 { get; set; }
#endregion
#region Private instance variables
/// <summary>
@@ -37,11 +51,38 @@ namespace SabreTools.FileTypes.CHD
var header = Serialization.Deserializers.CHD.DeserializeStream(stream);
return header switch
{
HeaderV1 v1 => new CHDFile { _header = header, MD5 = v1.MD5 },
HeaderV2 v2 => new CHDFile { _header = header, MD5 = v2.MD5 },
HeaderV3 v3 => new CHDFile { _header = header, MD5 = v3.MD5, SHA1 = v3.SHA1 },
HeaderV4 v4 => new CHDFile { _header = header, SHA1 = v4.SHA1 },
HeaderV5 v5 => new CHDFile { _header = header, SHA1 = v5.SHA1 },
HeaderV1 v1 => new CHDFile
{
_header = header,
MD5 = v1.MD5,
InternalMD5 = v1.MD5,
},
HeaderV2 v2 => new CHDFile
{
_header = header,
MD5 = v2.MD5,
InternalMD5 = v2.MD5,
},
HeaderV3 v3 => new CHDFile
{
_header = header,
MD5 = v3.MD5,
InternalMD5 = v3.MD5,
SHA1 = v3.SHA1,
InternalSHA1 = v3.SHA1,
},
HeaderV4 v4 => new CHDFile
{
_header = header,
SHA1 = v4.SHA1,
InternalSHA1 = v4.SHA1,
},
HeaderV5 v5 => new CHDFile
{
_header = header,
SHA1 = v5.SHA1,
InternalSHA1 = v5.SHA1,
},
_ => null,
};
}