From 6695bfc3d6bb8061edf637daaa174f794644ae7b Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 19 Jan 2019 17:39:31 +0000 Subject: [PATCH] Support verifying CDRWin images using trurip disc hashes extensions. --- .../.idea/contentModel.xml | 2 +- DiscImageChef.DiscImages/CDRWin/Read.cs | 73 ------ .../CDRWin/Unsupported.cs | 39 --- DiscImageChef.DiscImages/CDRWin/Verify.cs | 222 ++++++++++++++++++ .../DiscImageChef.DiscImages.csproj | 2 +- 5 files changed, 224 insertions(+), 114 deletions(-) delete mode 100644 DiscImageChef.DiscImages/CDRWin/Unsupported.cs create mode 100644 DiscImageChef.DiscImages/CDRWin/Verify.cs diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml index 9c914fa5c..0ca8d8024 100644 --- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml +++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml @@ -713,7 +713,7 @@ - + diff --git a/DiscImageChef.DiscImages/CDRWin/Read.cs b/DiscImageChef.DiscImages/CDRWin/Read.cs index 4b1532b5a..4516113e0 100644 --- a/DiscImageChef.DiscImages/CDRWin/Read.cs +++ b/DiscImageChef.DiscImages/CDRWin/Read.cs @@ -36,7 +36,6 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; -using DiscImageChef.Checksums; using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Exceptions; @@ -1544,77 +1543,5 @@ namespace DiscImageChef.DiscImages return tracks; } - - public bool? VerifySector(ulong sectorAddress) - { - byte[] buffer = ReadSectorLong(sectorAddress); - return CdChecksums.CheckCdSector(buffer); - } - - public bool? VerifySector(ulong sectorAddress, uint track) - { - byte[] buffer = ReadSectorLong(sectorAddress, track); - return CdChecksums.CheckCdSector(buffer); - } - - public bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas, - out List unknownLbas) - { - byte[] buffer = ReadSectorsLong(sectorAddress, length); - int bps = (int)(buffer.Length / length); - byte[] sector = new byte[bps]; - failingLbas = new List(); - unknownLbas = new List(); - - for(int i = 0; i < length; i++) - { - Array.Copy(buffer, i * bps, sector, 0, bps); - bool? sectorStatus = CdChecksums.CheckCdSector(sector); - - switch(sectorStatus) - { - case null: - unknownLbas.Add((ulong)i + sectorAddress); - break; - case false: - failingLbas.Add((ulong)i + sectorAddress); - break; - } - } - - if(unknownLbas.Count > 0) return null; - - return failingLbas.Count <= 0; - } - - public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, - out List unknownLbas) - { - byte[] buffer = ReadSectorsLong(sectorAddress, length, track); - int bps = (int)(buffer.Length / length); - byte[] sector = new byte[bps]; - failingLbas = new List(); - unknownLbas = new List(); - - for(int i = 0; i < length; i++) - { - Array.Copy(buffer, i * bps, sector, 0, bps); - bool? sectorStatus = CdChecksums.CheckCdSector(sector); - - switch(sectorStatus) - { - case null: - unknownLbas.Add((ulong)i + sectorAddress); - break; - case false: - failingLbas.Add((ulong)i + sectorAddress); - break; - } - } - - if(unknownLbas.Count > 0) return null; - - return failingLbas.Count <= 0; - } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/CDRWin/Unsupported.cs b/DiscImageChef.DiscImages/CDRWin/Unsupported.cs deleted file mode 100644 index 1762f4fe3..000000000 --- a/DiscImageChef.DiscImages/CDRWin/Unsupported.cs +++ /dev/null @@ -1,39 +0,0 @@ -// /*************************************************************************** -// The Disc Image Chef -// ---------------------------------------------------------------------------- -// -// Filename : Unsupported.cs -// Author(s) : Natalia Portillo -// -// Component : Disk image plugins. -// -// --[ Description ] ---------------------------------------------------------- -// -// Contains features unsupported by CDRWin cuesheets (cue/bin). -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2019 Natalia Portillo -// ****************************************************************************/ - -namespace DiscImageChef.DiscImages -{ - public partial class CdrWin - { - public bool? VerifyMediaImage() => null; - } -} \ No newline at end of file diff --git a/DiscImageChef.DiscImages/CDRWin/Verify.cs b/DiscImageChef.DiscImages/CDRWin/Verify.cs new file mode 100644 index 000000000..311fed934 --- /dev/null +++ b/DiscImageChef.DiscImages/CDRWin/Verify.cs @@ -0,0 +1,222 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Verify.cs +// Author(s) : Natalia Portillo +// +// Component : Disk image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Verifies CDRWin format disc images. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2019 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using DiscImageChef.Checksums; +using DiscImageChef.CommonTypes.Interfaces; +using DiscImageChef.Console; + +namespace DiscImageChef.DiscImages +{ + public partial class CdrWin + { + public bool? VerifySector(ulong sectorAddress) + { + byte[] buffer = ReadSectorLong(sectorAddress); + return CdChecksums.CheckCdSector(buffer); + } + + public bool? VerifySector(ulong sectorAddress, uint track) + { + byte[] buffer = ReadSectorLong(sectorAddress, track); + return CdChecksums.CheckCdSector(buffer); + } + + public bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas, + out List unknownLbas) + { + byte[] buffer = ReadSectorsLong(sectorAddress, length); + int bps = (int)(buffer.Length / length); + byte[] sector = new byte[bps]; + failingLbas = new List(); + unknownLbas = new List(); + + for(int i = 0; i < length; i++) + { + Array.Copy(buffer, i * bps, sector, 0, bps); + bool? sectorStatus = CdChecksums.CheckCdSector(sector); + + switch(sectorStatus) + { + case null: + unknownLbas.Add((ulong)i + sectorAddress); + break; + case false: + failingLbas.Add((ulong)i + sectorAddress); + break; + } + } + + if(unknownLbas.Count > 0) return null; + + return failingLbas.Count <= 0; + } + + public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, + out List unknownLbas) + { + byte[] buffer = ReadSectorsLong(sectorAddress, length, track); + int bps = (int)(buffer.Length / length); + byte[] sector = new byte[bps]; + failingLbas = new List(); + unknownLbas = new List(); + + for(int i = 0; i < length; i++) + { + Array.Copy(buffer, i * bps, sector, 0, bps); + bool? sectorStatus = CdChecksums.CheckCdSector(sector); + + switch(sectorStatus) + { + case null: + unknownLbas.Add((ulong)i + sectorAddress); + break; + case false: + failingLbas.Add((ulong)i + sectorAddress); + break; + } + } + + if(unknownLbas.Count > 0) return null; + + return failingLbas.Count <= 0; + } + + public bool? VerifyMediaImage() + { + if(discimage.DiscHashes.Count == 0) return null; + + // Read up to 1MiB at a time for verification + const int VERIFY_SIZE = 1024 * 1024; + long readBytes; + byte[] verifyBytes; + + IFilter[] filters = discimage.Tracks.OrderBy(t => t.Sequence).Select(t => t.Trackfile.Datafilter).Distinct() + .ToArray(); + + if(discimage.DiscHashes.TryGetValue("sha1", out string sha1)) + { + Sha1Context ctx = new Sha1Context(); + + foreach(IFilter filter in filters) + { + Stream stream = filter.GetDataForkStream(); + readBytes = 0; + verifyBytes = new byte[VERIFY_SIZE]; + + while(readBytes + VERIFY_SIZE < stream.Length) + { + stream.Read(verifyBytes, 0, verifyBytes.Length); + ctx.Update(verifyBytes); + readBytes += verifyBytes.LongLength; + } + + verifyBytes = new byte[stream.Length - readBytes]; + stream.Read(verifyBytes, 0, verifyBytes.Length); + ctx.Update(verifyBytes); + } + + string verifySha1 = ctx.End(); + DicConsole.DebugWriteLine("CDRWin plugin", "Calculated SHA1: {0}", verifySha1); + DicConsole.DebugWriteLine("CDRWin plugin", "Expected SHA1: {0}", sha1); + + return verifySha1 == sha1; + } + + if(discimage.DiscHashes.TryGetValue("md5", out string md5)) + { + Md5Context ctx = new Md5Context(); + + foreach(IFilter filter in filters) + { + Stream stream = filter.GetDataForkStream(); + readBytes = 0; + verifyBytes = new byte[VERIFY_SIZE]; + + while(readBytes + VERIFY_SIZE < stream.Length) + { + stream.Read(verifyBytes, 0, verifyBytes.Length); + ctx.Update(verifyBytes); + readBytes += verifyBytes.LongLength; + } + + verifyBytes = new byte[stream.Length - readBytes]; + stream.Read(verifyBytes, 0, verifyBytes.Length); + ctx.Update(verifyBytes); + } + + string verifyMd5 = ctx.End(); + DicConsole.DebugWriteLine("CDRWin plugin", "Calculated MD5: {0}", verifyMd5); + DicConsole.DebugWriteLine("CDRWin plugin", "Expected MD5: {0}", md5); + + return verifyMd5 == md5; + } + + if(discimage.DiscHashes.TryGetValue("crc32", out string crc32)) + { + Crc32Context ctx = new Crc32Context(); + + foreach(IFilter filter in filters) + { + Stream stream = filter.GetDataForkStream(); + readBytes = 0; + verifyBytes = new byte[VERIFY_SIZE]; + + while(readBytes + VERIFY_SIZE < stream.Length) + { + stream.Read(verifyBytes, 0, verifyBytes.Length); + ctx.Update(verifyBytes); + readBytes += verifyBytes.LongLength; + } + + verifyBytes = new byte[stream.Length - readBytes]; + stream.Read(verifyBytes, 0, verifyBytes.Length); + ctx.Update(verifyBytes); + } + + string verifyCrc = ctx.End(); + DicConsole.DebugWriteLine("CDRWin plugin", "Calculated CRC32: {0}", verifyCrc); + DicConsole.DebugWriteLine("CDRWin plugin", "Expected CRC32: {0}", crc32); + + return verifyCrc == crc32; + } + + foreach(string hash in discimage.DiscHashes.Keys) + DicConsole.DebugWriteLine("CDRWin plugin", "Found unsupported hash {0}", hash); + + return null; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj index 4269b3252..e86573a65 100644 --- a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj +++ b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj @@ -138,7 +138,7 @@ - +