mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Add support for calculating, and storing, checksums for DiscImageChef format.
This commit is contained in:
@@ -117,6 +117,7 @@ namespace DiscImageChef.DiscImages
|
|||||||
/// smaller than 256.
|
/// smaller than 256.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const int MIN_FLAKE_BLOCK = 256;
|
const int MIN_FLAKE_BLOCK = 256;
|
||||||
|
bool alreadyWrittenZero;
|
||||||
|
|
||||||
/// <summary>Cache of uncompressed blocks.</summary>
|
/// <summary>Cache of uncompressed blocks.</summary>
|
||||||
Dictionary<ulong, byte[]> blockCache;
|
Dictionary<ulong, byte[]> blockCache;
|
||||||
@@ -154,22 +155,28 @@ namespace DiscImageChef.DiscImages
|
|||||||
List<IndexEntry> index;
|
List<IndexEntry> index;
|
||||||
/// <summary>If set to <c>true</c>, the DDT entries are in-memory.</summary>
|
/// <summary>If set to <c>true</c>, the DDT entries are in-memory.</summary>
|
||||||
bool inMemoryDdt;
|
bool inMemoryDdt;
|
||||||
|
ulong lastWrittenBlock;
|
||||||
/// <summary>LZMA stream.</summary>
|
/// <summary>LZMA stream.</summary>
|
||||||
LzmaStream lzmaBlockStream;
|
LzmaStream lzmaBlockStream;
|
||||||
/// <summary>LZMA properties.</summary>
|
/// <summary>LZMA properties.</summary>
|
||||||
LzmaEncoderProperties lzmaEncoderProperties;
|
LzmaEncoderProperties lzmaEncoderProperties;
|
||||||
|
Md5Context md5Provider;
|
||||||
/// <summary>Cache of media tags.</summary>
|
/// <summary>Cache of media tags.</summary>
|
||||||
Dictionary<MediaTagType, byte[]> mediaTags;
|
Dictionary<MediaTagType, byte[]> mediaTags;
|
||||||
/// <summary>If DDT is on-disk, this is the image stream offset at which it starts.</summary>
|
/// <summary>If DDT is on-disk, this is the image stream offset at which it starts.</summary>
|
||||||
long outMemoryDdtPosition;
|
long outMemoryDdtPosition;
|
||||||
|
bool rewinded;
|
||||||
/// <summary>Cache for data that prefixes the user data on a sector (e.g. sync).</summary>
|
/// <summary>Cache for data that prefixes the user data on a sector (e.g. sync).</summary>
|
||||||
byte[] sectorPrefix;
|
byte[] sectorPrefix;
|
||||||
/// <summary>Cache for data that goes side by side with user data (e.g. CompactDisc subchannel).</summary>
|
/// <summary>Cache for data that goes side by side with user data (e.g. CompactDisc subchannel).</summary>
|
||||||
byte[] sectorSubchannel;
|
byte[] sectorSubchannel;
|
||||||
/// <summary>Cache for data that suffixes the user data on a sector (e.g. edc, ecc).</summary>
|
/// <summary>Cache for data that suffixes the user data on a sector (e.g. edc, ecc).</summary>
|
||||||
byte[] sectorSuffix;
|
byte[] sectorSuffix;
|
||||||
|
Sha1Context sha1Provider;
|
||||||
|
Sha256Context sha256Provider;
|
||||||
/// <summary>Shift for calculating number of sectors in a block.</summary>
|
/// <summary>Shift for calculating number of sectors in a block.</summary>
|
||||||
byte shift;
|
byte shift;
|
||||||
|
SpamSumContext spamsumProvider;
|
||||||
/// <summary>Cache for bytes to write/rad on-disk.</summary>
|
/// <summary>Cache for bytes to write/rad on-disk.</summary>
|
||||||
byte[] structureBytes;
|
byte[] structureBytes;
|
||||||
/// <summary>Cache for pointer for marshaling structures.</summary>
|
/// <summary>Cache for pointer for marshaling structures.</summary>
|
||||||
@@ -180,6 +187,7 @@ namespace DiscImageChef.DiscImages
|
|||||||
Dictionary<byte, string> trackIsrcs;
|
Dictionary<byte, string> trackIsrcs;
|
||||||
/// <summary>In-memory deduplication table</summary>
|
/// <summary>In-memory deduplication table</summary>
|
||||||
ulong[] userDataDdt;
|
ulong[] userDataDdt;
|
||||||
|
bool writingLong;
|
||||||
|
|
||||||
public DiscImageChef()
|
public DiscImageChef()
|
||||||
{
|
{
|
||||||
@@ -1862,7 +1870,11 @@ namespace DiscImageChef.DiscImages
|
|||||||
"How many sectors to store per block (will be rounded to next power of two)"),
|
"How many sectors to store per block (will be rounded to next power of two)"),
|
||||||
("dictionary", typeof(uint), "Size, in bytes, of the LZMA dictionary"),
|
("dictionary", typeof(uint), "Size, in bytes, of the LZMA dictionary"),
|
||||||
("max_ddt_size", typeof(uint),
|
("max_ddt_size", typeof(uint),
|
||||||
"Maximum size, in mebibytes, for in-memory DDT. If image needs a bigger one, it will be on-disk")
|
"Maximum size, in mebibytes, for in-memory DDT. If image needs a bigger one, it will be on-disk"),
|
||||||
|
("md5", typeof(bool), "Calculate and store MD5 of image's user data"),
|
||||||
|
("sha1", typeof(bool), "Calculate and store SHA1 of image's user data"),
|
||||||
|
("sha256", typeof(bool), "Calculate and store SHA256 of image's user data"),
|
||||||
|
("spamsum", typeof(bool), "Calculate and store SpamSum of image's user data")
|
||||||
};
|
};
|
||||||
public IEnumerable<string> KnownExtensions => new[] {".dicf"};
|
public IEnumerable<string> KnownExtensions => new[] {".dicf"};
|
||||||
public bool IsWriting { get; private set; }
|
public bool IsWriting { get; private set; }
|
||||||
@@ -1874,6 +1886,10 @@ namespace DiscImageChef.DiscImages
|
|||||||
uint sectorsPerBlock;
|
uint sectorsPerBlock;
|
||||||
uint dictionary;
|
uint dictionary;
|
||||||
uint maxDdtSize;
|
uint maxDdtSize;
|
||||||
|
bool doMd5;
|
||||||
|
bool doSha1;
|
||||||
|
bool doSha256;
|
||||||
|
bool doSpamsum;
|
||||||
|
|
||||||
if(options != null)
|
if(options != null)
|
||||||
{
|
{
|
||||||
@@ -1906,12 +1922,56 @@ namespace DiscImageChef.DiscImages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else maxDdtSize = 256;
|
else maxDdtSize = 256;
|
||||||
|
|
||||||
|
if(options.TryGetValue("md5", out tmpValue))
|
||||||
|
{
|
||||||
|
if(!bool.TryParse(tmpValue, out doMd5))
|
||||||
|
{
|
||||||
|
ErrorMessage = "Invalid value for md5 option";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else doMd5 = false;
|
||||||
|
|
||||||
|
if(options.TryGetValue("sha1", out tmpValue))
|
||||||
|
{
|
||||||
|
if(!bool.TryParse(tmpValue, out doSha1))
|
||||||
|
{
|
||||||
|
ErrorMessage = "Invalid value for sha1 option";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else doSha1 = false;
|
||||||
|
|
||||||
|
if(options.TryGetValue("sha256", out tmpValue))
|
||||||
|
{
|
||||||
|
if(!bool.TryParse(tmpValue, out doSha256))
|
||||||
|
{
|
||||||
|
ErrorMessage = "Invalid value for sha256 option";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else doSha256 = false;
|
||||||
|
|
||||||
|
if(options.TryGetValue("spamsum", out tmpValue))
|
||||||
|
{
|
||||||
|
if(!bool.TryParse(tmpValue, out doSpamsum))
|
||||||
|
{
|
||||||
|
ErrorMessage = "Invalid value for spamsum option";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else doSpamsum = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sectorsPerBlock = 4096;
|
sectorsPerBlock = 4096;
|
||||||
dictionary = 1 << 25;
|
dictionary = 1 << 25;
|
||||||
maxDdtSize = 256;
|
maxDdtSize = 256;
|
||||||
|
doMd5 = false;
|
||||||
|
doSha1 = false;
|
||||||
|
doSha256 = false;
|
||||||
|
doSpamsum = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This really, cannot happen
|
// This really, cannot happen
|
||||||
@@ -2001,6 +2061,12 @@ namespace DiscImageChef.DiscImages
|
|||||||
// If there exists an index, we are appending, so read index
|
// If there exists an index, we are appending, so read index
|
||||||
if(header.indexOffset > 0)
|
if(header.indexOffset > 0)
|
||||||
{
|
{
|
||||||
|
// Can't calculate checksum of an appended image
|
||||||
|
md5Provider = null;
|
||||||
|
sha1Provider = null;
|
||||||
|
sha256Provider = null;
|
||||||
|
spamsumProvider = null;
|
||||||
|
|
||||||
imageStream.Position = (long)header.indexOffset;
|
imageStream.Position = (long)header.indexOffset;
|
||||||
IndexHeader idxHeader = new IndexHeader();
|
IndexHeader idxHeader = new IndexHeader();
|
||||||
structureBytes = new byte[Marshal.SizeOf(idxHeader)];
|
structureBytes = new byte[Marshal.SizeOf(idxHeader)];
|
||||||
@@ -2034,6 +2100,9 @@ namespace DiscImageChef.DiscImages
|
|||||||
index.Add(entry);
|
index.Add(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate previous checksum block
|
||||||
|
index.RemoveAll(t => t.blockType == BlockType.ChecksumBlock && t.dataType == DataType.NoData);
|
||||||
|
|
||||||
bool foundUserDataDdt = false;
|
bool foundUserDataDdt = false;
|
||||||
foreach(IndexEntry entry in index)
|
foreach(IndexEntry entry in index)
|
||||||
{
|
{
|
||||||
@@ -2399,6 +2468,30 @@ namespace DiscImageChef.DiscImages
|
|||||||
imageStream.Position += (long)(sectors * sizeof(ulong)) - 1;
|
imageStream.Position += (long)(sectors * sizeof(ulong)) - 1;
|
||||||
imageStream.WriteByte(0);
|
imageStream.WriteByte(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(doMd5)
|
||||||
|
{
|
||||||
|
md5Provider = new Md5Context();
|
||||||
|
md5Provider.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(doSha1)
|
||||||
|
{
|
||||||
|
sha1Provider = new Sha1Context();
|
||||||
|
sha1Provider.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(doSha256)
|
||||||
|
{
|
||||||
|
sha256Provider = new Sha256Context();
|
||||||
|
sha256Provider.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(doSpamsum)
|
||||||
|
{
|
||||||
|
spamsumProvider = new SpamSumContext();
|
||||||
|
spamsumProvider.Init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("DiscImageChef format plugin", "In memory DDT?: {0}", inMemoryDdt);
|
DicConsole.DebugWriteLine("DiscImageChef format plugin", "In memory DDT?: {0}", inMemoryDdt);
|
||||||
@@ -2475,8 +2568,28 @@ namespace DiscImageChef.DiscImages
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((imageInfo.XmlMediaType != XmlMediaType.OpticalDisc || !writingLong) && !rewinded)
|
||||||
|
{
|
||||||
|
if(sectorAddress <= lastWrittenBlock && alreadyWrittenZero)
|
||||||
|
{
|
||||||
|
rewinded = true;
|
||||||
|
md5Provider = null;
|
||||||
|
sha1Provider = null;
|
||||||
|
sha256Provider = null;
|
||||||
|
spamsumProvider = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
md5Provider?.Update(data);
|
||||||
|
sha1Provider?.Update(data);
|
||||||
|
sha256Provider?.Update(data);
|
||||||
|
spamsumProvider?.Update(data);
|
||||||
|
lastWrittenBlock = sectorAddress;
|
||||||
|
}
|
||||||
|
|
||||||
byte[] hash = checksumProvider.ComputeHash(data);
|
byte[] hash = checksumProvider.ComputeHash(data);
|
||||||
|
|
||||||
|
if(sectorAddress == 0) alreadyWrittenZero = true;
|
||||||
|
|
||||||
if(deduplicationTable.TryGetValue(hash, out ulong pointer))
|
if(deduplicationTable.TryGetValue(hash, out ulong pointer))
|
||||||
{
|
{
|
||||||
SetDdtEntry(sectorAddress, pointer);
|
SetDdtEntry(sectorAddress, pointer);
|
||||||
@@ -2660,6 +2773,25 @@ namespace DiscImageChef.DiscImages
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writingLong = true;
|
||||||
|
if(!rewinded)
|
||||||
|
{
|
||||||
|
if(sectorAddress <= lastWrittenBlock && alreadyWrittenZero)
|
||||||
|
{
|
||||||
|
rewinded = true;
|
||||||
|
md5Provider = null;
|
||||||
|
sha1Provider = null;
|
||||||
|
sha256Provider = null;
|
||||||
|
spamsumProvider = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
md5Provider?.Update(data);
|
||||||
|
sha1Provider?.Update(data);
|
||||||
|
sha256Provider?.Update(data);
|
||||||
|
spamsumProvider?.Update(data);
|
||||||
|
lastWrittenBlock = sectorAddress;
|
||||||
|
}
|
||||||
|
|
||||||
// Split raw cd sector data in prefix (sync, header), user data and suffix (edc, ecc p, ecc q)
|
// Split raw cd sector data in prefix (sync, header), user data and suffix (edc, ecc p, ecc q)
|
||||||
switch(track.TrackType)
|
switch(track.TrackType)
|
||||||
{
|
{
|
||||||
@@ -3213,6 +3345,99 @@ namespace DiscImageChef.DiscImages
|
|||||||
index.Add(idxEntry);
|
index.Add(idxEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have checksums, write it to disk
|
||||||
|
if(md5Provider != null || sha1Provider != null || sha256Provider != null || spamsumProvider != null)
|
||||||
|
{
|
||||||
|
MemoryStream chkMs = new MemoryStream();
|
||||||
|
ChecksumHeader chkHeader = new ChecksumHeader {identifier = BlockType.ChecksumBlock};
|
||||||
|
|
||||||
|
if(md5Provider != null)
|
||||||
|
{
|
||||||
|
byte[] md5 = md5Provider.Final();
|
||||||
|
ChecksumEntry md5Entry =
|
||||||
|
new ChecksumEntry {type = ChecksumAlgorithm.Md5, length = (uint)md5.Length};
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(md5Entry));
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(md5Entry)];
|
||||||
|
Marshal.StructureToPtr(md5Entry, structurePointer, true);
|
||||||
|
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
chkMs.Write(structureBytes, 0, structureBytes.Length);
|
||||||
|
chkMs.Write(md5, 0, md5.Length);
|
||||||
|
chkHeader.entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sha1Provider != null)
|
||||||
|
{
|
||||||
|
byte[] sha1 = sha1Provider.Final();
|
||||||
|
ChecksumEntry sha1Entry =
|
||||||
|
new ChecksumEntry {type = ChecksumAlgorithm.Sha1, length = (uint)sha1.Length};
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(sha1Entry));
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(sha1Entry)];
|
||||||
|
Marshal.StructureToPtr(sha1Entry, structurePointer, true);
|
||||||
|
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
chkMs.Write(structureBytes, 0, structureBytes.Length);
|
||||||
|
chkMs.Write(sha1, 0, sha1.Length);
|
||||||
|
chkHeader.entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sha256Provider != null)
|
||||||
|
{
|
||||||
|
byte[] sha256 = sha256Provider.Final();
|
||||||
|
ChecksumEntry sha256Entry =
|
||||||
|
new ChecksumEntry {type = ChecksumAlgorithm.Sha256, length = (uint)sha256.Length};
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(sha256Entry));
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(sha256Entry)];
|
||||||
|
Marshal.StructureToPtr(sha256Entry, structurePointer, true);
|
||||||
|
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
chkMs.Write(structureBytes, 0, structureBytes.Length);
|
||||||
|
chkMs.Write(sha256, 0, sha256.Length);
|
||||||
|
chkHeader.entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(spamsumProvider != null)
|
||||||
|
{
|
||||||
|
byte[] spamsum = Encoding.ASCII.GetBytes(spamsumProvider.End());
|
||||||
|
ChecksumEntry spamsumEntry =
|
||||||
|
new ChecksumEntry {type = ChecksumAlgorithm.SpamSum, length = (uint)spamsum.Length};
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(spamsumEntry));
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(spamsumEntry)];
|
||||||
|
Marshal.StructureToPtr(spamsumEntry, structurePointer, true);
|
||||||
|
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
chkMs.Write(structureBytes, 0, structureBytes.Length);
|
||||||
|
chkMs.Write(spamsum, 0, spamsum.Length);
|
||||||
|
chkHeader.entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(chkHeader.entries > 0)
|
||||||
|
{
|
||||||
|
chkHeader.length = (uint)chkMs.Length;
|
||||||
|
idxEntry = new IndexEntry
|
||||||
|
{
|
||||||
|
blockType = BlockType.ChecksumBlock,
|
||||||
|
dataType = DataType.NoData,
|
||||||
|
offset = (ulong)imageStream.Position
|
||||||
|
};
|
||||||
|
|
||||||
|
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Writing checksum block to position {0}",
|
||||||
|
idxEntry.offset);
|
||||||
|
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(chkHeader));
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(chkHeader)];
|
||||||
|
Marshal.StructureToPtr(chkHeader, structurePointer, true);
|
||||||
|
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
imageStream.Write(structureBytes, 0, structureBytes.Length);
|
||||||
|
imageStream.Write(chkMs.ToArray(), 0, (int)chkMs.Length);
|
||||||
|
|
||||||
|
index.RemoveAll(t => t.blockType == BlockType.ChecksumBlock && t.dataType == DataType.NoData);
|
||||||
|
|
||||||
|
index.Add(idxEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the DDT is in-memory, write it to disk
|
// If the DDT is in-memory, write it to disk
|
||||||
if(inMemoryDdt)
|
if(inMemoryDdt)
|
||||||
{
|
{
|
||||||
@@ -4506,7 +4731,7 @@ namespace DiscImageChef.DiscImages
|
|||||||
TracksBlock = 0x534B5254,
|
TracksBlock = 0x534B5254,
|
||||||
/// <summary>Block containing CICM XML metadata</summary>
|
/// <summary>Block containing CICM XML metadata</summary>
|
||||||
CicmBlock = 0x4D434943,
|
CicmBlock = 0x4D434943,
|
||||||
/// <summary>TODO: Block containing contents checksums</summary>
|
/// <summary>Block containing contents checksums</summary>
|
||||||
ChecksumBlock = 0x4D534B43,
|
ChecksumBlock = 0x4D534B43,
|
||||||
/// <summary>TODO: Block containing data position measurements</summary>
|
/// <summary>TODO: Block containing data position measurements</summary>
|
||||||
DataPositionMeasurementBlock = 0x2A4D5044,
|
DataPositionMeasurementBlock = 0x2A4D5044,
|
||||||
@@ -4779,5 +5004,39 @@ namespace DiscImageChef.DiscImages
|
|||||||
public ulong start;
|
public ulong start;
|
||||||
public ulong end;
|
public ulong end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checksum block, contains a checksum of all user data sectors (except for optical discs that is 2352 bytes raw
|
||||||
|
/// sector if available
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct ChecksumHeader
|
||||||
|
{
|
||||||
|
/// <summary>Identifier, <see cref="BlockType.ChecksumBlock" /></summary>
|
||||||
|
public BlockType identifier;
|
||||||
|
/// <summary>Length in bytes of the block</summary>
|
||||||
|
public uint length;
|
||||||
|
/// <summary>How many checksums follow</summary>
|
||||||
|
public byte entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ChecksumAlgorithm : byte
|
||||||
|
{
|
||||||
|
Invalid = 0,
|
||||||
|
Md5 = 1,
|
||||||
|
Sha1 = 2,
|
||||||
|
Sha256 = 3,
|
||||||
|
SpamSum = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Checksum entry, followed by checksum data itself</summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct ChecksumEntry
|
||||||
|
{
|
||||||
|
/// <summary>Checksum algorithm</summary>
|
||||||
|
public ChecksumAlgorithm type;
|
||||||
|
/// <summary>Length in bytes of checksum that follows this structure</summary>
|
||||||
|
public uint length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -645,6 +645,15 @@ enum <byte> TrackType
|
|||||||
CdMode2Form2 = 5
|
CdMode2Form2 = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum <byte> ChecksumAlgorithm
|
||||||
|
{
|
||||||
|
Invalid = 0,
|
||||||
|
Md5 = 1,
|
||||||
|
Sha1 = 2,
|
||||||
|
Sha256 = 3,
|
||||||
|
SpamSum = 4
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char identifier[8];
|
char identifier[8];
|
||||||
@@ -803,6 +812,24 @@ typedef struct
|
|||||||
DumpHardwareEntry dumpHardware[entries];
|
DumpHardwareEntry dumpHardware[entries];
|
||||||
} DumpHardwareHeader;
|
} DumpHardwareHeader;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ChecksumAlgorithm type;
|
||||||
|
uint length;
|
||||||
|
if(type == 4)
|
||||||
|
char checksum[length] <format=hex>;
|
||||||
|
else
|
||||||
|
byte checksum[length];
|
||||||
|
} ChecksumEntry <optimize=false>;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
BlockType identifier;
|
||||||
|
uint length;
|
||||||
|
byte entries;
|
||||||
|
ChecksumEntry checksums[entries];
|
||||||
|
} ChecksumHeader;
|
||||||
|
|
||||||
LittleEndian();
|
LittleEndian();
|
||||||
|
|
||||||
local int i;
|
local int i;
|
||||||
@@ -899,5 +926,8 @@ for(i = 0; i < index.entries; i++)
|
|||||||
case 0x2A504D44:
|
case 0x2A504D44:
|
||||||
DumpHardwareHeader dumpHardware;
|
DumpHardwareHeader dumpHardware;
|
||||||
break;
|
break;
|
||||||
|
case 0x4D534B43:
|
||||||
|
ChecksumHeader checksum;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user