Renamed Aaru.DiscImages to Aaru.Images.

This commit is contained in:
2020-02-26 19:28:59 +00:00
parent 428e53a76f
commit 8a05685e33
466 changed files with 590 additions and 590 deletions

View File

@@ -0,0 +1,308 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : ClauniaSubchannelTransform.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains the CD ECC algorithm.
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ECC algorithm from ECM(c) 2002-2011 Neill Corlett
// ****************************************************************************/
using System;
using DiscImageChef.CommonTypes.Enums;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
byte[] eccBTable;
byte[] eccFTable;
uint[] edcTable;
bool initedEdc;
void EccInit()
{
if(initedEdc) return;
eccFTable = new byte[256];
eccBTable = new byte[256];
edcTable = new uint[256];
for(uint i = 0; i < 256; i++)
{
uint edc = i;
uint j = (uint)((i << 1) ^ ((i & 0x80) == 0x80 ? 0x11D : 0));
eccFTable[i] = (byte)j;
eccBTable[i ^ j] = (byte)i;
for(j = 0; j < 8; j++) edc = (edc >> 1) ^ ((edc & 1) > 0 ? 0xD8018001 : 0);
edcTable[i] = edc;
}
initedEdc = true;
}
bool SuffixIsCorrect(byte[] sector)
{
if(!initedEdc) EccInit();
if(sector[0x814] != 0x00 || // reserved (8 bytes)
sector[0x815] != 0x00 || sector[0x816] != 0x00 || sector[0x817] != 0x00 || sector[0x818] != 0x00 ||
sector[0x819] != 0x00 || sector[0x81A] != 0x00 || sector[0x81B] != 0x00) return false;
bool correctEccP = CheckEcc(sector, sector, 86, 24, 2, 86, sector, 0xC, 0x10, 0x81C);
if(!correctEccP) return false;
bool correctEccQ = CheckEcc(sector, sector, 52, 43, 86, 88, sector, 0xC, 0x10, 0x81C + 0xAC);
if(!correctEccQ) return false;
uint storedEdc = BitConverter.ToUInt32(sector, 0x810);
uint edc = 0;
int size = 0x810;
int pos = 0;
for(; size > 0; size--) edc = (edc >> 8) ^ edcTable[(edc ^ sector[pos++]) & 0xFF];
uint calculatedEdc = edc;
return calculatedEdc == storedEdc;
}
bool SuffixIsCorrectMode2(byte[] sector)
{
if(!initedEdc) EccInit();
byte[] zeroaddress = new byte[4];
bool correctEccP = CheckEcc(zeroaddress, sector, 86, 24, 2, 86, sector, 0, 0x10, 0x81C);
if(!correctEccP) return false;
bool correctEccQ = CheckEcc(zeroaddress, sector, 52, 43, 86, 88, sector, 0, 0x10, 0x81C + 0xAC);
if(!correctEccQ) return false;
uint storedEdc = BitConverter.ToUInt32(sector, 0x818);
uint edc = 0;
int size = 0x808;
int pos = 0x10;
for(; size > 0; size--) edc = (edc >> 8) ^ edcTable[(edc ^ sector[pos++]) & 0xFF];
uint calculatedEdc = edc;
return calculatedEdc == storedEdc;
}
bool CheckEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult,
uint minorInc,
byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
{
uint size = majorCount * minorCount;
uint major;
for(major = 0; major < majorCount; major++)
{
uint idx = (major >> 1) * majorMult + (major & 1);
byte eccA = 0;
byte eccB = 0;
uint minor;
for(minor = 0; minor < minorCount; minor++)
{
byte temp = idx < 4 ? address[idx + addressOffset] : data[idx + dataOffset - 4];
idx += minorInc;
if(idx >= size) idx -= size;
eccA ^= temp;
eccB ^= temp;
eccA = eccFTable[eccA];
}
eccA = eccBTable[eccFTable[eccA] ^ eccB];
if(ecc[major + eccOffset] != eccA || ecc[major + majorCount + eccOffset] != (eccA ^ eccB)) return false;
}
return true;
}
void WriteEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult,
uint minorInc,
ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
{
uint size = majorCount * minorCount;
uint major;
for(major = 0; major < majorCount; major++)
{
uint idx = (major >> 1) * majorMult + (major & 1);
byte eccA = 0;
byte eccB = 0;
uint minor;
for(minor = 0; minor < minorCount; minor++)
{
byte temp = idx < 4 ? address[idx + addressOffset] : data[idx + dataOffset - 4];
idx += minorInc;
if(idx >= size) idx -= size;
eccA ^= temp;
eccB ^= temp;
eccA = eccFTable[eccA];
}
eccA = eccBTable[eccFTable[eccA] ^ eccB];
ecc[major + eccOffset] = eccA;
ecc[major + majorCount + eccOffset] = (byte)(eccA ^ eccB);
}
}
void EccWriteSector(byte[] address, byte[] data, ref byte[] ecc, int addressOffset, int dataOffset,
int eccOffset)
{
WriteEcc(address, data, 86, 24, 2, 86, ref ecc, addressOffset, dataOffset, eccOffset); // P
WriteEcc(address, data, 52, 43, 86, 88, ref ecc, addressOffset, dataOffset, eccOffset + 0xAC); // Q
}
static (byte minute, byte second, byte frame) LbaToMsf(long pos) =>
((byte)((pos + 150) / 75 / 60), (byte)((pos + 150) / 75 % 60), (byte)((pos + 150) % 75));
void ReconstructPrefix(ref byte[] sector, // must point to a full 2352-byte sector
TrackType type, long lba)
{
//
// Sync
//
sector[0x000] = 0x00;
sector[0x001] = 0xFF;
sector[0x002] = 0xFF;
sector[0x003] = 0xFF;
sector[0x004] = 0xFF;
sector[0x005] = 0xFF;
sector[0x006] = 0xFF;
sector[0x007] = 0xFF;
sector[0x008] = 0xFF;
sector[0x009] = 0xFF;
sector[0x00A] = 0xFF;
sector[0x00B] = 0x00;
(byte minute, byte second, byte frame) msf = LbaToMsf(lba);
sector[0x00C] = (byte)(((msf.minute / 10) << 4) + msf.minute % 10);
sector[0x00D] = (byte)(((msf.second / 10) << 4) + msf.second % 10);
sector[0x00E] = (byte)(((msf.frame / 10) << 4) + msf.frame % 10);
switch(type)
{
case TrackType.CdMode1:
//
// Mode
//
sector[0x00F] = 0x01;
break;
case TrackType.CdMode2Form1:
case TrackType.CdMode2Form2:
case TrackType.CdMode2Formless:
//
// Mode
//
sector[0x00F] = 0x02;
//
// Flags
//
sector[0x010] = sector[0x014];
sector[0x011] = sector[0x015];
sector[0x012] = sector[0x016];
sector[0x013] = sector[0x017];
break;
default: return;
}
}
void ReconstructEcc(ref byte[] sector, // must point to a full 2352-byte sector
TrackType type)
{
byte[] computedEdc;
if(!initedEdc) EccInit();
switch(type)
{
//
// Compute EDC
//
case TrackType.CdMode1:
computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x810));
sector[0x810] = computedEdc[0];
sector[0x811] = computedEdc[1];
sector[0x812] = computedEdc[2];
sector[0x813] = computedEdc[3];
break;
case TrackType.CdMode2Form1:
computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x808, 0x10));
sector[0x818] = computedEdc[0];
sector[0x819] = computedEdc[1];
sector[0x81A] = computedEdc[2];
sector[0x81B] = computedEdc[3];
break;
case TrackType.CdMode2Form2:
computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x91C, 0x10));
sector[0x92C] = computedEdc[0];
sector[0x92D] = computedEdc[1];
sector[0x92E] = computedEdc[2];
sector[0x92F] = computedEdc[3];
break;
default: return;
}
byte[] zeroaddress = new byte[4];
switch(type)
{
//
// Compute ECC
//
case TrackType.CdMode1:
//
// Reserved
//
sector[0x814] = 0x00;
sector[0x815] = 0x00;
sector[0x816] = 0x00;
sector[0x817] = 0x00;
sector[0x818] = 0x00;
sector[0x819] = 0x00;
sector[0x81A] = 0x00;
sector[0x81B] = 0x00;
EccWriteSector(sector, sector, ref sector, 0xC, 0x10, 0x81C);
break;
case TrackType.CdMode2Form1:
EccWriteSector(zeroaddress, sector, ref sector, 0, 0x10, 0x81C);
break;
default: return;
}
//
// Done
//
}
uint ComputeEdc(uint edc, byte[] src, int size, int srcOffset = 0)
{
if(!initedEdc) EccInit();
int pos = srcOffset;
for(; size > 0; size--) edc = (edc >> 8) ^ edcTable[(edc ^ src[pos++]) & 0xFF];
return edc;
}
}
}

View File

@@ -0,0 +1,296 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : ClauniaSubchannelTransform.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains the Claunia Subchannel Transform algorithm.
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using DiscImageChef.Console;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
static byte[] ClauniaSubchannelTransform(byte[] interleaved)
{
if(interleaved == null) return null;
int[] p = new int[interleaved.Length / 8];
int[] q = new int[interleaved.Length / 8];
int[] r = new int[interleaved.Length / 8];
int[] s = new int[interleaved.Length / 8];
int[] t = new int[interleaved.Length / 8];
int[] u = new int[interleaved.Length / 8];
int[] v = new int[interleaved.Length / 8];
int[] w = new int[interleaved.Length / 8];
DateTime start = DateTime.UtcNow;
for(int i = 0; i < interleaved.Length; i += 8)
{
p[i / 8] = interleaved[i] & 0x80;
p[i / 8] += (interleaved[i + 1] & 0x80) >> 1;
p[i / 8] += (interleaved[i + 2] & 0x80) >> 2;
p[i / 8] += (interleaved[i + 3] & 0x80) >> 3;
p[i / 8] += (interleaved[i + 4] & 0x80) >> 4;
p[i / 8] += (interleaved[i + 5] & 0x80) >> 5;
p[i / 8] += (interleaved[i + 6] & 0x80) >> 6;
p[i / 8] += (interleaved[i + 7] & 0x80) >> 7;
q[i / 8] = (interleaved[i] & 0x40) << 1;
q[i / 8] += interleaved[i + 1] & 0x40;
q[i / 8] += (interleaved[i + 2] & 0x40) >> 1;
q[i / 8] += (interleaved[i + 3] & 0x40) >> 2;
q[i / 8] += (interleaved[i + 4] & 0x40) >> 3;
q[i / 8] += (interleaved[i + 5] & 0x40) >> 4;
q[i / 8] += (interleaved[i + 6] & 0x40) >> 5;
q[i / 8] += (interleaved[i + 7] & 0x40) >> 6;
r[i / 8] = (interleaved[i] & 0x20) << 2;
r[i / 8] += (interleaved[i + 1] & 0x20) << 1;
r[i / 8] += interleaved[i + 2] & 0x20;
r[i / 8] += (interleaved[i + 3] & 0x20) >> 1;
r[i / 8] += (interleaved[i + 4] & 0x20) >> 2;
r[i / 8] += (interleaved[i + 5] & 0x20) >> 3;
r[i / 8] += (interleaved[i + 6] & 0x20) >> 4;
r[i / 8] += (interleaved[i + 7] & 0x20) >> 5;
s[i / 8] = (interleaved[i] & 0x10) << 3;
s[i / 8] += (interleaved[i + 1] & 0x10) << 2;
s[i / 8] += (interleaved[i + 2] & 0x10) << 1;
s[i / 8] += interleaved[i + 3] & 0x10;
s[i / 8] += (interleaved[i + 4] & 0x10) >> 1;
s[i / 8] += (interleaved[i + 5] & 0x10) >> 2;
s[i / 8] += (interleaved[i + 6] & 0x10) >> 3;
s[i / 8] += (interleaved[i + 7] & 0x10) >> 4;
t[i / 8] = (interleaved[i] & 0x08) << 4;
t[i / 8] += (interleaved[i + 1] & 0x08) << 3;
t[i / 8] += (interleaved[i + 2] & 0x08) << 2;
t[i / 8] += (interleaved[i + 3] & 0x08) << 1;
t[i / 8] += interleaved[i + 4] & 0x08;
t[i / 8] += (interleaved[i + 5] & 0x08) >> 1;
t[i / 8] += (interleaved[i + 6] & 0x08) >> 2;
t[i / 8] += (interleaved[i + 7] & 0x08) >> 3;
u[i / 8] = (interleaved[i] & 0x04) << 5;
u[i / 8] += (interleaved[i + 1] & 0x04) << 4;
u[i / 8] += (interleaved[i + 2] & 0x04) << 3;
u[i / 8] += (interleaved[i + 3] & 0x04) << 2;
u[i / 8] += (interleaved[i + 4] & 0x04) << 1;
u[i / 8] += interleaved[i + 5] & 0x04;
u[i / 8] += (interleaved[i + 6] & 0x04) >> 1;
u[i / 8] += (interleaved[i + 7] & 0x04) >> 2;
v[i / 8] = (interleaved[i] & 0x02) << 6;
v[i / 8] += (interleaved[i + 1] & 0x02) << 5;
v[i / 8] += (interleaved[i + 2] & 0x02) << 4;
v[i / 8] += (interleaved[i + 3] & 0x02) << 3;
v[i / 8] += (interleaved[i + 4] & 0x02) << 2;
v[i / 8] += (interleaved[i + 5] & 0x02) << 1;
v[i / 8] += interleaved[i + 6] & 0x02;
v[i / 8] += (interleaved[i + 7] & 0x02) >> 1;
w[i / 8] = (interleaved[i] & 0x01) << 7;
w[i / 8] += (interleaved[i + 1] & 0x01) << 6;
w[i / 8] += (interleaved[i + 2] & 0x01) << 5;
w[i / 8] += (interleaved[i + 3] & 0x01) << 4;
w[i / 8] += (interleaved[i + 4] & 0x01) << 3;
w[i / 8] += (interleaved[i + 5] & 0x01) << 2;
w[i / 8] += (interleaved[i + 6] & 0x01) << 1;
w[i / 8] += interleaved[i + 7] & 0x01;
}
DateTime end = DateTime.UtcNow;
TimeSpan deinterleave = end - start;
byte[] sequential = new byte[interleaved.Length];
start = DateTime.UtcNow;
int qStart = p.Length * 1;
int rStart = p.Length * 2;
int sStart = p.Length * 3;
int tStart = p.Length * 4;
int uStart = p.Length * 5;
int vStart = p.Length * 6;
int wStart = p.Length * 7;
for(int i = 0; i < p.Length; i++)
{
sequential[i] = (byte)p[i];
sequential[qStart + i] = (byte)q[i];
sequential[rStart + i] = (byte)r[i];
sequential[sStart + i] = (byte)s[i];
sequential[tStart + i] = (byte)t[i];
sequential[uStart + i] = (byte)u[i];
sequential[vStart + i] = (byte)v[i];
sequential[wStart + i] = (byte)w[i];
}
end = DateTime.UtcNow;
TimeSpan sequentialize = end - start;
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Took {0}ms to deinterleave subchannel.",
deinterleave.TotalMilliseconds);
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Took {0}ms to sequentialize subchannel.",
sequentialize.TotalMilliseconds);
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Took {0}ms to transform subchannel.",
deinterleave.TotalMilliseconds + sequentialize.TotalMilliseconds);
return sequential;
}
static byte[] ClauniaSubchannelUntransform(byte[] sequential)
{
if(sequential == null) return null;
int[] p = new int[sequential.Length / 8];
int[] q = new int[sequential.Length / 8];
int[] r = new int[sequential.Length / 8];
int[] s = new int[sequential.Length / 8];
int[] t = new int[sequential.Length / 8];
int[] u = new int[sequential.Length / 8];
int[] v = new int[sequential.Length / 8];
int[] w = new int[sequential.Length / 8];
int qStart = p.Length * 1;
int rStart = p.Length * 2;
int sStart = p.Length * 3;
int tStart = p.Length * 4;
int uStart = p.Length * 5;
int vStart = p.Length * 6;
int wStart = p.Length * 7;
DateTime start = DateTime.UtcNow;
for(int i = 0; i < p.Length; i++)
{
p[i] = sequential[i];
q[i] = sequential[qStart + i];
r[i] = sequential[rStart + i];
s[i] = sequential[sStart + i];
t[i] = sequential[tStart + i];
u[i] = sequential[uStart + i];
v[i] = sequential[vStart + i];
w[i] = sequential[wStart + i];
}
DateTime end = DateTime.UtcNow;
TimeSpan desequentialize = end - start;
byte[] interleaved = new byte[sequential.Length];
start = DateTime.UtcNow;
for(int i = 0; i < interleaved.Length; i += 8)
{
interleaved[i] = (byte)((p[i / 8] & 0x80) == 0x80 ? 0x80 : 0);
interleaved[i + 1] += (byte)((p[i / 8] & 0x40) == 0x40 ? 0x80 : 0);
interleaved[i + 2] += (byte)((p[i / 8] & 0x20) == 0x20 ? 0x80 : 0);
interleaved[i + 3] += (byte)((p[i / 8] & 0x10) == 0x10 ? 0x80 : 0);
interleaved[i + 4] += (byte)((p[i / 8] & 0x08) == 0x08 ? 0x80 : 0);
interleaved[i + 5] += (byte)((p[i / 8] & 0x04) == 0x04 ? 0x80 : 0);
interleaved[i + 6] += (byte)((p[i / 8] & 0x02) == 0x02 ? 0x80 : 0);
interleaved[i + 7] += (byte)((p[i / 8] & 0x01) == 0x01 ? 0x80 : 0);
interleaved[i] += (byte)((q[i / 8] & 0x80) == 0x80 ? 0x40 : 0);
interleaved[i + 1] += (byte)((q[i / 8] & 0x40) == 0x40 ? 0x40 : 0);
interleaved[i + 2] += (byte)((q[i / 8] & 0x20) == 0x20 ? 0x40 : 0);
interleaved[i + 3] += (byte)((q[i / 8] & 0x10) == 0x10 ? 0x40 : 0);
interleaved[i + 4] += (byte)((q[i / 8] & 0x08) == 0x08 ? 0x40 : 0);
interleaved[i + 5] += (byte)((q[i / 8] & 0x04) == 0x04 ? 0x40 : 0);
interleaved[i + 6] += (byte)((q[i / 8] & 0x02) == 0x02 ? 0x40 : 0);
interleaved[i + 7] += (byte)((q[i / 8] & 0x01) == 0x01 ? 0x40 : 0);
interleaved[i] += (byte)((r[i / 8] & 0x80) == 0x80 ? 0x20 : 0);
interleaved[i + 1] += (byte)((r[i / 8] & 0x40) == 0x40 ? 0x20 : 0);
interleaved[i + 2] += (byte)((r[i / 8] & 0x20) == 0x20 ? 0x20 : 0);
interleaved[i + 3] += (byte)((r[i / 8] & 0x10) == 0x10 ? 0x20 : 0);
interleaved[i + 4] += (byte)((r[i / 8] & 0x08) == 0x08 ? 0x20 : 0);
interleaved[i + 5] += (byte)((r[i / 8] & 0x04) == 0x04 ? 0x20 : 0);
interleaved[i + 6] += (byte)((r[i / 8] & 0x02) == 0x02 ? 0x20 : 0);
interleaved[i + 7] += (byte)((r[i / 8] & 0x01) == 0x01 ? 0x20 : 0);
interleaved[i] += (byte)((s[i / 8] & 0x80) == 0x80 ? 0x10 : 0);
interleaved[i + 1] += (byte)((s[i / 8] & 0x40) == 0x40 ? 0x10 : 0);
interleaved[i + 2] += (byte)((s[i / 8] & 0x20) == 0x20 ? 0x10 : 0);
interleaved[i + 3] += (byte)((s[i / 8] & 0x10) == 0x10 ? 0x10 : 0);
interleaved[i + 4] += (byte)((s[i / 8] & 0x08) == 0x08 ? 0x10 : 0);
interleaved[i + 5] += (byte)((s[i / 8] & 0x04) == 0x04 ? 0x10 : 0);
interleaved[i + 6] += (byte)((s[i / 8] & 0x02) == 0x02 ? 0x10 : 0);
interleaved[i + 7] += (byte)((s[i / 8] & 0x01) == 0x01 ? 0x10 : 0);
interleaved[i] += (byte)((t[i / 8] & 0x80) == 0x80 ? 0x08 : 0);
interleaved[i + 1] += (byte)((t[i / 8] & 0x40) == 0x40 ? 0x08 : 0);
interleaved[i + 2] += (byte)((t[i / 8] & 0x20) == 0x20 ? 0x08 : 0);
interleaved[i + 3] += (byte)((t[i / 8] & 0x10) == 0x10 ? 0x08 : 0);
interleaved[i + 4] += (byte)((t[i / 8] & 0x08) == 0x08 ? 0x08 : 0);
interleaved[i + 5] += (byte)((t[i / 8] & 0x04) == 0x04 ? 0x08 : 0);
interleaved[i + 6] += (byte)((t[i / 8] & 0x02) == 0x02 ? 0x08 : 0);
interleaved[i + 7] += (byte)((t[i / 8] & 0x01) == 0x01 ? 0x08 : 0);
interleaved[i] += (byte)((u[i / 8] & 0x80) == 0x80 ? 0x04 : 0);
interleaved[i + 1] += (byte)((u[i / 8] & 0x40) == 0x40 ? 0x04 : 0);
interleaved[i + 2] += (byte)((u[i / 8] & 0x20) == 0x20 ? 0x04 : 0);
interleaved[i + 3] += (byte)((u[i / 8] & 0x10) == 0x10 ? 0x04 : 0);
interleaved[i + 4] += (byte)((u[i / 8] & 0x08) == 0x08 ? 0x04 : 0);
interleaved[i + 5] += (byte)((u[i / 8] & 0x04) == 0x04 ? 0x04 : 0);
interleaved[i + 6] += (byte)((u[i / 8] & 0x02) == 0x02 ? 0x04 : 0);
interleaved[i + 7] += (byte)((u[i / 8] & 0x01) == 0x01 ? 0x04 : 0);
interleaved[i] += (byte)((v[i / 8] & 0x80) == 0x80 ? 0x02 : 0);
interleaved[i + 1] += (byte)((v[i / 8] & 0x40) == 0x40 ? 0x02 : 0);
interleaved[i + 2] += (byte)((v[i / 8] & 0x20) == 0x20 ? 0x02 : 0);
interleaved[i + 3] += (byte)((v[i / 8] & 0x10) == 0x10 ? 0x02 : 0);
interleaved[i + 4] += (byte)((v[i / 8] & 0x08) == 0x08 ? 0x02 : 0);
interleaved[i + 5] += (byte)((v[i / 8] & 0x04) == 0x04 ? 0x02 : 0);
interleaved[i + 6] += (byte)((v[i / 8] & 0x02) == 0x02 ? 0x02 : 0);
interleaved[i + 7] += (byte)((v[i / 8] & 0x01) == 0x01 ? 0x02 : 0);
interleaved[i] += (byte)((w[i / 8] & 0x80) == 0x80 ? 0x01 : 0);
interleaved[i + 1] += (byte)((w[i / 8] & 0x40) == 0x40 ? 0x01 : 0);
interleaved[i + 2] += (byte)((w[i / 8] & 0x20) == 0x20 ? 0x01 : 0);
interleaved[i + 3] += (byte)((w[i / 8] & 0x10) == 0x10 ? 0x01 : 0);
interleaved[i + 4] += (byte)((w[i / 8] & 0x08) == 0x08 ? 0x01 : 0);
interleaved[i + 5] += (byte)((w[i / 8] & 0x04) == 0x04 ? 0x01 : 0);
interleaved[i + 6] += (byte)((w[i / 8] & 0x02) == 0x02 ? 0x01 : 0);
interleaved[i + 7] += (byte)((w[i / 8] & 0x01) == 0x01 ? 0x01 : 0);
}
end = DateTime.UtcNow;
TimeSpan interleave = end - start;
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Took {0}ms to de-sequentialize subchannel.",
desequentialize.TotalMilliseconds);
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Took {0}ms to interleave subchannel.",
interleave.TotalMilliseconds);
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Took {0}ms to untransform subchannel.",
interleave.TotalMilliseconds + desequentialize.TotalMilliseconds);
return interleaved;
}
}
}

View File

@@ -0,0 +1,64 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Constants.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains constants for DiscImageChef format disk 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
/// <summary>Magic identidier = "DICMFMT".</summary>
const ulong DIC_MAGIC = 0x544D52464D434944;
/// <summary>
/// Image format version. A change in this number indicates an incompatible change to the format that
/// prevents older implementations from reading it correctly, if at all.
/// </summary>
const byte DICF_VERSION = 1;
/// <summary>Maximum read cache size, 256MiB.</summary>
const uint MAX_CACHE_SIZE = 256 * 1024 * 1024;
/// <summary>Size in bytes of LZMA properties.</summary>
const int LZMA_PROPERTIES_LENGTH = 5;
/// <summary>Maximum number of entries for the DDT cache.</summary>
const int MAX_DDT_ENTRY_CACHE = 16000000;
/// <summary>How many samples are contained in a RedBook sector.</summary>
const int SAMPLES_PER_SECTOR = 588;
/// <summary>Maximum number of samples for a FLAC block. Bigger than 4608 gives no benefit.</summary>
const int MAX_FLAKE_BLOCK = 4608;
/// <summary>
/// Minimum number of samples for a FLAC block. <see cref="CUETools.Codecs.FLAKE" /> does not support it to be
/// smaller than 256.
/// </summary>
const int MIN_FLAKE_BLOCK = 256;
/// <summary>This mask is to check for flags in CompactDisc suffix/prefix DDT</summary>
const uint CD_XFIX_MASK = 0xFF000000;
/// <summary>This mask is to check for position in CompactDisc suffix/prefix deduplicated block</summary>
const uint CD_DFIX_MASK = 0x00FFFFFF;
}
}

View File

@@ -0,0 +1,194 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : DiscImageChef.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Manages DiscImageChef format disk 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
/*
The idea of the format is being able to easily store, retrieve, and access any data that can be read from media.
At the start of a file there's a header that contains a format version, application creator name, and a pointer to
the index.
The index points to one or several DeDuplication Tables, or media tag blocks.
A deduplication table is a table of offsets to blocks and sectors inside blocks. Each entry equals to an LBA and points
to a byte offset in the file shift left to the number of sectors contained in a block, plus the number of sector inside
the block.
Each block must contain sectors of equal size, but that size can be different between blocks.
The deduplication table should be stored decompressed if its size is too big to be stored on-memory. This is chosen at
creation time but it is a good idea to set the limit to 256MiB (this allows for a device of 33 million sectors,
17Gb at 512 bps, 68Gb at 2048 bps and 137Gb at 4096 bps).
Sector tags that are simply too small to be deduplicated are contained in a single block pointed by the index (e.g.
Apple GCR sector tags).
Optical disks contain a track block that describes the tracks.
TODO: Streaming tapes contain a file block that describes the files and an optional partition block that describes the tape
partitions.
There are also blocks for image metadata, contents metadata and dump hardware information.
A differencing image will have all the metadata and deduplication tables, but the entries in these ones will be set to
0 if the block is stored in the parent image. TODO: This is not yet implemented.
Also because the file becomes useless without the index and deduplication table, each can be stored twice. In case of
the index it should just be searched for. In case of deduplication tables, both copies should be indexed.
Finally, writing new data to an existing image is just Copy-On-Write. Create a new block with the modified data, change
the pointer in the corresponding deduplication table.
P.S.: Data Position Measurement is doable, as soon as I know how to do it.
P.S.2: Support for floppy image containg bitslices and/or fluxes will be added soon.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using CUETools.Codecs.FLAKE;
using DiscImageChef.Checksums;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Structs;
using SharpCompress.Compressors.LZMA;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef : IWritableOpticalImage, IVerifiableImage, IWritableTapeImage
{
bool alreadyWrittenZero;
/// <summary>Cache of uncompressed blocks.</summary>
Dictionary<ulong, byte[]> blockCache;
/// <summary>Cache of block headers.</summary>
Dictionary<ulong, BlockHeader> blockHeaderCache;
/// <summary>Stream used for writing blocks.</summary>
MemoryStream blockStream;
/// <summary>Provides checksum for deduplication of sectors.</summary>
SHA256 checksumProvider;
/// <summary>Provides CRC64.</summary>
Crc64Context crc64;
/// <summary>Header of the currently writing block.</summary>
BlockHeader currentBlockHeader;
/// <summary>Sector offset of writing position in currently writing block.</summary>
uint currentBlockOffset;
/// <summary>Current size in bytes of the block cache</summary>
uint currentCacheSize;
/// <summary>Cache of DDT entries.</summary>
Dictionary<ulong, ulong> ddtEntryCache;
MemoryStream decompressedStream;
bool deduplicate;
/// <summary>On-memory deduplication table indexed by checksum.</summary>
Dictionary<string, ulong> deduplicationTable;
/// <summary><see cref="CUETools.Codecs.FLAKE" /> writer.</summary>
FlakeWriter flakeWriter;
/// <summary><see cref="CUETools.Codecs.FLAKE" /> settings.</summary>
FlakeWriterSettings flakeWriterSettings;
/// <summary>Block with logical geometry.</summary>
GeometryBlock geometryBlock;
/// <summary>Image header.</summary>
DicHeader header;
/// <summary>Image information.</summary>
ImageInfo imageInfo;
/// <summary>Image data stream.</summary>
Stream imageStream;
/// <summary>Index.</summary>
List<IndexEntry> index;
/// <summary>If set to <c>true</c>, the DDT entries are in-memory.</summary>
bool inMemoryDdt;
ulong lastWrittenBlock;
/// <summary>LZMA stream.</summary>
LzmaStream lzmaBlockStream;
/// <summary>LZMA properties.</summary>
LzmaEncoderProperties lzmaEncoderProperties;
Md5Context md5Provider;
/// <summary>Cache of media tags.</summary>
Dictionary<MediaTagType, byte[]> mediaTags;
byte[] mode2Subheaders;
bool nocompress;
/// <summary>If DDT is on-disk, this is the image stream offset at which it starts.</summary>
long outMemoryDdtPosition;
bool rewinded;
/// <summary>Cache for data that prefixes the user data on a sector (e.g. sync).</summary>
byte[] sectorPrefix;
uint[] sectorPrefixDdt;
MemoryStream sectorPrefixMs;
/// <summary>Cache for data that goes side by side with user data (e.g. CompactDisc subchannel).</summary>
byte[] sectorSubchannel;
/// <summary>Cache for data that suffixes the user data on a sector (e.g. edc, ecc).</summary>
byte[] sectorSuffix;
uint[] sectorSuffixDdt;
MemoryStream sectorSuffixMs;
Sha1Context sha1Provider;
Sha256Context sha256Provider;
/// <summary>Shift for calculating number of sectors in a block.</summary>
byte shift;
SpamSumContext spamsumProvider;
/// <summary>Cache for bytes to write/rad on-disk.</summary>
byte[] structureBytes;
/// <summary>Cache for pointer for marshaling structures.</summary>
IntPtr structurePointer;
Dictionary<ulong, ulong> tapeDdt;
/// <summary>Cache of CompactDisc track's flags</summary>
Dictionary<byte, byte> trackFlags;
/// <summary>Cache of CompactDisc track's ISRC</summary>
Dictionary<byte, string> trackIsrcs;
/// <summary>In-memory deduplication table</summary>
ulong[] userDataDdt;
bool writingLong;
ulong writtenSectors;
public DiscImageChef()
{
imageInfo = new ImageInfo
{
ReadableSectorTags = new List<SectorTagType>(),
ReadableMediaTags = new List<MediaTagType>(),
HasPartitions = false,
HasSessions = false,
Version = null,
Application = "DiscImageChef",
ApplicationVersion = null,
Creator = null,
Comments = null,
MediaManufacturer = null,
MediaModel = null,
MediaSerialNumber = null,
MediaBarcode = null,
MediaPartNumber = null,
MediaSequence = 0,
LastMediaSequence = 0,
DriveManufacturer = null,
DriveModel = null,
DriveSerialNumber = null,
DriveFirmwareRevision = null
};
}
}
}

View File

@@ -0,0 +1,266 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Enums.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains enumerations for DiscImageChef format disk 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
/// <summary>List of known compression types</summary>
enum CompressionType : ushort
{
/// <summary>Not compressed</summary>
None = 0,
/// <summary>LZMA</summary>
Lzma = 1,
/// <summary>FLAC</summary>
Flac = 2,
/// <summary>LZMA in Claunia Subchannel Transform processed data</summary>
LzmaClauniaSubchannelTransform = 3
}
/// <summary>List of known data types</summary>
enum DataType : ushort
{
/// <summary>No data</summary>
NoData = 0,
/// <summary>User data</summary>
UserData = 1,
/// <summary>CompactDisc partial Table of Contents</summary>
CompactDiscPartialToc = 2,
/// <summary>CompactDisc session information</summary>
CompactDiscSessionInfo = 3,
/// <summary>CompactDisc Table of Contents</summary>
CompactDiscToc = 4,
/// <summary>CompactDisc Power Management Area</summary>
CompactDiscPma = 5,
/// <summary>CompactDisc Absolute Time In Pregroove</summary>
CompactDiscAtip = 6,
/// <summary>CompactDisc Lead-in's CD-Text</summary>
CompactDiscLeadInCdText = 7,
/// <summary>DVD Physical Format Information</summary>
DvdPfi = 8,
/// <summary>DVD Lead-in's Copyright Management Information</summary>
DvdLeadInCmi = 9,
/// <summary>DVD Disc Key</summary>
DvdDiscKey = 10,
/// <summary>DVD Burst Cutting Area</summary>
DvdBca = 11,
/// <summary>DVD DMI</summary>
DvdDmi = 12,
/// <summary>DVD Media Identifier</summary>
DvdMediaIdentifier = 13,
/// <summary>DVD Media Key Block</summary>
DvdMediaKeyBlock = 14,
/// <summary>DVD-RAM Disc Definition Structure</summary>
DvdRamDds = 15,
/// <summary>DVD-RAM Medium Status</summary>
DvdRamMediumStatus = 16,
/// <summary>DVD-RAM Spare Area Information</summary>
DvdRamSpareArea = 17,
/// <summary>DVD-R RMD</summary>
DvdRRmd = 18,
/// <summary>DVD-R Pre-recorded Information</summary>
DvdRPrerecordedInfo = 19,
/// <summary>DVD-R Media Identifier</summary>
DvdRMediaIdentifier = 20,
/// <summary>DVD-R Physical Format Information</summary>
DvdRPfi = 21,
/// <summary>DVD ADress In Pregroove</summary>
DvdAdip = 22,
/// <summary>HD DVD Copy Protection Information</summary>
HdDvdCpi = 23,
/// <summary>HD DVD Medium Status</summary>
HdDvdMediumStatus = 24,
/// <summary>DVD DL Layer Capacity</summary>
DvdDlLayerCapacity = 25,
/// <summary>DVD DL Middle Zone Address</summary>
DvdDlMiddleZoneAddress = 26,
/// <summary>DVD DL Jump Interval Size</summary>
DvdDlJumpIntervalSize = 27,
/// <summary>DVD DL Manual Layer Jump LBA</summary>
DvdDlManualLayerJumpLba = 28,
/// <summary>Bluray Disc Information</summary>
BlurayDi = 29,
/// <summary>Bluray Burst Cutting Area</summary>
BlurayBca = 30,
/// <summary>Bluray Disc Definition Structure</summary>
BlurayDds = 31,
/// <summary>Bluray Cartridge Status</summary>
BlurayCartridgeStatus = 32,
/// <summary>Bluray Spare Area Information</summary>
BluraySpareArea = 33,
/// <summary>AACS Volume Identifier</summary>
AacsVolumeIdentifier = 34,
/// <summary>AACS Serial Number</summary>
AacsSerialNumber = 35,
/// <summary>AACS Media Identifier</summary>
AacsMediaIdentifier = 36,
/// <summary>AACS Media Key Block</summary>
AacsMediaKeyBlock = 37,
/// <summary>AACS Data Keys</summary>
AacsDataKeys = 38,
/// <summary>AACS LBA Extents</summary>
AacsLbaExtents = 39,
/// <summary>CPRM Media Key Block</summary>
CprmMediaKeyBlock = 40,
/// <summary>Recognized Layers</summary>
HybridRecognizedLayers = 41,
/// <summary>MMC Write Protection</summary>
ScsiMmcWriteProtection = 42,
/// <summary>MMC Disc Information</summary>
ScsiMmcDiscInformation = 43,
/// <summary>MMC Track Resources Information</summary>
ScsiMmcTrackResourcesInformation = 44,
/// <summary>MMC POW Resources Information</summary>
ScsiMmcPowResourcesInformation = 45,
/// <summary>SCSI INQUIRY RESPONSE</summary>
ScsiInquiry = 46,
/// <summary>SCSI MODE PAGE 2Ah</summary>
ScsiModePage2A = 47,
/// <summary>ATA IDENTIFY response</summary>
AtaIdentify = 48,
/// <summary>ATAPI IDENTIFY response</summary>
AtapiIdentify = 49,
/// <summary>PCMCIA CIS</summary>
PcmciaCis = 50,
/// <summary>SecureDigital CID</summary>
SecureDigitalCid = 51,
/// <summary>SecureDigital CSD</summary>
SecureDigitalCsd = 52,
/// <summary>SecureDigital SCR</summary>
SecureDigitalScr = 53,
/// <summary>SecureDigital OCR</summary>
SecureDigitalOcr = 54,
/// <summary>MultiMediaCard CID</summary>
MultiMediaCardCid = 55,
/// <summary>MultiMediaCard CSD</summary>
MultiMediaCardCsd = 56,
/// <summary>MultiMediaCard OCR</summary>
MultiMediaCardOcr = 57,
/// <summary>MultiMediaCard Extended CSD</summary>
MultiMediaCardExtendedCsd = 58,
/// <summary>Xbox Security Sector</summary>
XboxSecuritySector = 59,
/// <summary>Floppy Lead-out</summary>
FloppyLeadOut = 60,
/// <summary>Dvd Disc Control Block</summary>
DvdDiscControlBlock = 61,
/// <summary>CompactDisc First track pregap</summary>
CompactDiscFirstTrackPregap = 62,
/// <summary>CompactDisc Lead-out</summary>
CompactDiscLeadOut = 63,
/// <summary>SCSI MODE SENSE (6) response</summary>
ScsiModeSense6 = 64,
/// <summary>SCSI MODE SENSE (10) response</summary>
ScsiModeSense10 = 65,
/// <summary>USB descriptors</summary>
UsbDescriptors = 66,
/// <summary>Xbox DMI</summary>
XboxDmi = 67,
/// <summary>Xbox Physical Format Information</summary>
XboxPfi = 68,
/// <summary>CompactDisc sector prefix (sync, header</summary>
CdSectorPrefix = 69,
/// <summary>CompactDisc sector suffix (edc, ecc p, ecc q)</summary>
CdSectorSuffix = 70,
/// <summary>CompactDisc subchannel</summary>
CdSectorSubchannel = 71,
/// <summary>Apple Profile (20 byte) tag</summary>
AppleProfileTag = 72,
/// <summary>Apple Sony (12 byte) tag</summary>
AppleSonyTag = 73,
/// <summary>Priam Data Tower (24 byte) tag</summary>
PriamDataTowerTag = 74,
/// <summary>CompactDisc Media Catalogue Number (as in Lead-in), 13 bytes, ASCII</summary>
CompactDiscMediaCatalogueNumber = 75,
/// <summary>CompactDisc sector prefix (sync, header), only incorrect stored</summary>
CdSectorPrefixCorrected = 76,
/// <summary>CompactDisc sector suffix (edc, ecc p, ecc q), only incorrect stored</summary>
CdSectorSuffixCorrected = 77,
/// <summary>CompactDisc MODE 2 subheader</summary>
CompactDiscMode2Subheader = 78,
/// <summary>CompactDisc Lead-in</summary>
CompactDiscLeadIn = 79
}
/// <summary>List of known blocks types</summary>
enum BlockType : uint
{
/// <summary>Block containing data</summary>
DataBlock = 0x4B4C4244,
/// <summary>Block containing a deduplication table</summary>
DeDuplicationTable = 0X2A544444,
/// <summary>Block containing the index</summary>
Index = 0X58444E49,
/// <summary>Block containing logical geometry</summary>
GeometryBlock = 0x4D4F4547,
/// <summary>Block containing metadata</summary>
MetadataBlock = 0x4154454D,
/// <summary>Block containing optical disc tracks</summary>
TracksBlock = 0x534B5254,
/// <summary>Block containing CICM XML metadata</summary>
CicmBlock = 0x4D434943,
/// <summary>Block containing contents checksums</summary>
ChecksumBlock = 0x4D534B43,
/// <summary>TODO: Block containing data position measurements</summary>
DataPositionMeasurementBlock = 0x2A4D5044,
/// <summary>TODO: Block containing a snapshot index</summary>
SnapshotBlock = 0x50414E53,
/// <summary>TODO: Block containing how to locate the parent image</summary>
ParentBlock = 0x50524E54,
/// <summary>Block containing an array of hardware used to create the image</summary>
DumpHardwareBlock = 0x2A504D44,
/// <summary>Block containing list of files for a tape image</summary>
TapeFileBlock = 0x454C4654,
/// <summary>Block containing list of partitions for a tape image</summary>
TapePartitionBlock = 0x54425054
}
enum ChecksumAlgorithm : byte
{
Invalid = 0,
Md5 = 1,
Sha1 = 2,
Sha256 = 3,
SpamSum = 4
}
enum CdFixFlags : uint
{
NotDumped = 0x10000000,
Correct = 0x20000000,
Mode2Form1Ok = 0x30000000,
Mode2Form2Ok = 0x40000000,
Mode2Form2NoCrc = 0x50000000
}
}
}

View File

@@ -0,0 +1,442 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Helpers.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains helpers for DiscImageChef format disk 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Structs.Devices.ATA;
using DiscImageChef.CommonTypes.Structs.Devices.SCSI;
using DiscImageChef.Decoders.SecureDigital;
using DiscImageChef.Helpers;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
/// <summary>Checks for media tags that may contain metadata and sets it up if not already set</summary>
void SetMetadataFromTags()
{
// Search for SecureDigital CID
if(mediaTags.TryGetValue(MediaTagType.SD_CID, out byte[] sdCid))
{
CID decoded = Decoders.SecureDigital.Decoders.DecodeCID(sdCid);
if(string.IsNullOrWhiteSpace(imageInfo.DriveManufacturer))
imageInfo.DriveManufacturer = VendorString.Prettify(decoded.Manufacturer);
if(string.IsNullOrWhiteSpace(imageInfo.DriveModel))
imageInfo.DriveModel = decoded.ProductName;
if(string.IsNullOrWhiteSpace(imageInfo.DriveFirmwareRevision))
imageInfo.DriveFirmwareRevision =
$"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}";
if(string.IsNullOrWhiteSpace(imageInfo.DriveSerialNumber))
imageInfo.DriveSerialNumber = $"{decoded.ProductSerialNumber}";
}
// Search for MultiMediaCard CID
if(mediaTags.TryGetValue(MediaTagType.MMC_CID, out byte[] mmcCid))
{
Decoders.MMC.CID decoded = Decoders.MMC.Decoders.DecodeCID(mmcCid);
if(string.IsNullOrWhiteSpace(imageInfo.DriveManufacturer))
imageInfo.DriveManufacturer = Decoders.MMC.VendorString.Prettify(decoded.Manufacturer);
if(string.IsNullOrWhiteSpace(imageInfo.DriveModel))
imageInfo.DriveModel = decoded.ProductName;
if(string.IsNullOrWhiteSpace(imageInfo.DriveFirmwareRevision))
imageInfo.DriveFirmwareRevision =
$"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}";
if(string.IsNullOrWhiteSpace(imageInfo.DriveSerialNumber))
imageInfo.DriveSerialNumber = $"{decoded.ProductSerialNumber}";
}
// Search for SCSI INQUIRY
if(mediaTags.TryGetValue(MediaTagType.SCSI_INQUIRY, out byte[] scsiInquiry))
{
Inquiry? nullableInquiry = Inquiry.Decode(scsiInquiry);
if(nullableInquiry.HasValue)
{
Inquiry inquiry = nullableInquiry.Value;
if(string.IsNullOrWhiteSpace(imageInfo.DriveManufacturer))
imageInfo.DriveManufacturer = StringHandlers.CToString(inquiry.VendorIdentification)?.Trim();
if(string.IsNullOrWhiteSpace(imageInfo.DriveModel))
imageInfo.DriveModel = StringHandlers.CToString(inquiry.ProductIdentification)?.Trim();
if(string.IsNullOrWhiteSpace(imageInfo.DriveFirmwareRevision))
imageInfo.DriveFirmwareRevision =
StringHandlers.CToString(inquiry.ProductRevisionLevel)?.Trim();
}
}
// Search for ATA or ATAPI IDENTIFY
if(!mediaTags.TryGetValue(MediaTagType.ATA_IDENTIFY, out byte[] ataIdentify) &&
!mediaTags.TryGetValue(MediaTagType.ATAPI_IDENTIFY, out ataIdentify))
return;
Identify.IdentifyDevice? nullableIdentify = CommonTypes.Structs.Devices.ATA.Identify.Decode(ataIdentify);
if(!nullableIdentify.HasValue)
return;
Identify.IdentifyDevice identify = nullableIdentify.Value;
string[] separated = identify.Model.Split(' ');
if(separated.Length == 1)
if(string.IsNullOrWhiteSpace(imageInfo.DriveModel))
imageInfo.DriveModel = separated[0];
else
{
if(string.IsNullOrWhiteSpace(imageInfo.DriveManufacturer))
imageInfo.DriveManufacturer = separated[0];
if(string.IsNullOrWhiteSpace(imageInfo.DriveModel))
imageInfo.DriveModel = separated[separated.Length - 1];
}
if(string.IsNullOrWhiteSpace(imageInfo.DriveFirmwareRevision))
imageInfo.DriveFirmwareRevision = identify.FirmwareRevision;
if(string.IsNullOrWhiteSpace(imageInfo.DriveSerialNumber))
imageInfo.DriveSerialNumber = identify.SerialNumber;
}
// Get the CICM XML media type from DIC media type
static XmlMediaType GetXmlMediaType(MediaType type)
{
switch(type)
{
case MediaType.CD:
case MediaType.CDDA:
case MediaType.CDG:
case MediaType.CDEG:
case MediaType.CDI:
case MediaType.CDIREADY:
case MediaType.CDROM:
case MediaType.CDROMXA:
case MediaType.CDPLUS:
case MediaType.CDMO:
case MediaType.CDR:
case MediaType.CDRW:
case MediaType.CDMRW:
case MediaType.VCD:
case MediaType.SVCD:
case MediaType.PCD:
case MediaType.SACD:
case MediaType.DDCD:
case MediaType.DDCDR:
case MediaType.DDCDRW:
case MediaType.DTSCD:
case MediaType.CDMIDI:
case MediaType.CDV:
case MediaType.DVDROM:
case MediaType.DVDR:
case MediaType.DVDRW:
case MediaType.DVDPR:
case MediaType.DVDPRW:
case MediaType.DVDPRWDL:
case MediaType.DVDRDL:
case MediaType.DVDPRDL:
case MediaType.DVDRAM:
case MediaType.DVDRWDL:
case MediaType.DVDDownload:
case MediaType.HDDVDROM:
case MediaType.HDDVDRAM:
case MediaType.HDDVDR:
case MediaType.HDDVDRW:
case MediaType.HDDVDRDL:
case MediaType.HDDVDRWDL:
case MediaType.BDROM:
case MediaType.BDR:
case MediaType.BDRE:
case MediaType.BDRXL:
case MediaType.BDREXL:
case MediaType.EVD:
case MediaType.FVD:
case MediaType.HVD:
case MediaType.CBHD:
case MediaType.HDVMD:
case MediaType.VCDHD:
case MediaType.SVOD:
case MediaType.FDDVD:
case MediaType.LD:
case MediaType.LDROM:
case MediaType.LDROM2:
case MediaType.LVROM:
case MediaType.MegaLD:
case MediaType.PS1CD:
case MediaType.PS2CD:
case MediaType.PS2DVD:
case MediaType.PS3DVD:
case MediaType.PS3BD:
case MediaType.PS4BD:
case MediaType.UMD:
case MediaType.XGD:
case MediaType.XGD2:
case MediaType.XGD3:
case MediaType.XGD4:
case MediaType.MEGACD:
case MediaType.SATURNCD:
case MediaType.GDROM:
case MediaType.GDR:
case MediaType.SuperCDROM2:
case MediaType.JaguarCD:
case MediaType.ThreeDO:
case MediaType.PCFX:
case MediaType.NeoGeoCD:
case MediaType.GOD:
case MediaType.WOD:
case MediaType.WUOD:
case MediaType.CDTV:
case MediaType.CD32:
case MediaType.Nuon:
case MediaType.Playdia:
case MediaType.Pippin:
case MediaType.FMTOWNS:
case MediaType.MilCD:
case MediaType.VideoNow:
case MediaType.VideoNowColor:
case MediaType.VideoNowXp: return XmlMediaType.OpticalDisc;
default: return XmlMediaType.BlockMedia;
}
}
// Gets a DDT entry
ulong GetDdtEntry(ulong sectorAddress)
{
if(inMemoryDdt)
return userDataDdt[sectorAddress];
if(ddtEntryCache.TryGetValue(sectorAddress, out ulong entry))
return entry;
long oldPosition = imageStream.Position;
imageStream.Position = outMemoryDdtPosition + Marshal.SizeOf<DdtHeader>();
imageStream.Position += (long)(sectorAddress * sizeof(ulong));
byte[] temp = new byte[sizeof(ulong)];
imageStream.Read(temp, 0, sizeof(ulong));
imageStream.Position = oldPosition;
entry = BitConverter.ToUInt64(temp, 0);
if(ddtEntryCache.Count >= MAX_DDT_ENTRY_CACHE)
ddtEntryCache.Clear();
ddtEntryCache.Add(sectorAddress, entry);
return entry;
}
// Sets a DDT entry
void SetDdtEntry(ulong sectorAddress, ulong pointer)
{
if(inMemoryDdt)
{
if(IsTape)
tapeDdt[sectorAddress] = pointer;
else
userDataDdt[sectorAddress] = pointer;
return;
}
long oldPosition = imageStream.Position;
imageStream.Position = outMemoryDdtPosition + Marshal.SizeOf<DdtHeader>();
imageStream.Position += (long)(sectorAddress * sizeof(ulong));
imageStream.Write(BitConverter.GetBytes(pointer), 0, sizeof(ulong));
imageStream.Position = oldPosition;
}
// Converts between image data type and dic media tag type
static MediaTagType GetMediaTagTypeForDataType(DataType type)
{
switch(type)
{
case DataType.CompactDiscPartialToc: return MediaTagType.CD_TOC;
case DataType.CompactDiscSessionInfo: return MediaTagType.CD_SessionInfo;
case DataType.CompactDiscToc: return MediaTagType.CD_FullTOC;
case DataType.CompactDiscPma: return MediaTagType.CD_PMA;
case DataType.CompactDiscAtip: return MediaTagType.CD_ATIP;
case DataType.CompactDiscLeadInCdText: return MediaTagType.CD_TEXT;
case DataType.DvdPfi: return MediaTagType.DVD_PFI;
case DataType.DvdLeadInCmi: return MediaTagType.DVD_CMI;
case DataType.DvdDiscKey: return MediaTagType.DVD_DiscKey;
case DataType.DvdBca: return MediaTagType.DVD_BCA;
case DataType.DvdDmi: return MediaTagType.DVD_DMI;
case DataType.DvdMediaIdentifier: return MediaTagType.DVD_MediaIdentifier;
case DataType.DvdMediaKeyBlock: return MediaTagType.DVD_MKB;
case DataType.DvdRamDds: return MediaTagType.DVDRAM_DDS;
case DataType.DvdRamMediumStatus: return MediaTagType.DVDRAM_MediumStatus;
case DataType.DvdRamSpareArea: return MediaTagType.DVDRAM_SpareArea;
case DataType.DvdRRmd: return MediaTagType.DVDR_RMD;
case DataType.DvdRPrerecordedInfo: return MediaTagType.DVDR_PreRecordedInfo;
case DataType.DvdRMediaIdentifier: return MediaTagType.DVDR_MediaIdentifier;
case DataType.DvdRPfi: return MediaTagType.DVDR_PFI;
case DataType.DvdAdip: return MediaTagType.DVD_ADIP;
case DataType.HdDvdCpi: return MediaTagType.HDDVD_CPI;
case DataType.HdDvdMediumStatus: return MediaTagType.HDDVD_MediumStatus;
case DataType.DvdDlLayerCapacity: return MediaTagType.DVDDL_LayerCapacity;
case DataType.DvdDlMiddleZoneAddress: return MediaTagType.DVDDL_MiddleZoneAddress;
case DataType.DvdDlJumpIntervalSize: return MediaTagType.DVDDL_JumpIntervalSize;
case DataType.DvdDlManualLayerJumpLba: return MediaTagType.DVDDL_ManualLayerJumpLBA;
case DataType.BlurayDi: return MediaTagType.BD_DI;
case DataType.BlurayBca: return MediaTagType.BD_BCA;
case DataType.BlurayDds: return MediaTagType.BD_DDS;
case DataType.BlurayCartridgeStatus: return MediaTagType.BD_CartridgeStatus;
case DataType.BluraySpareArea: return MediaTagType.BD_SpareArea;
case DataType.AacsVolumeIdentifier: return MediaTagType.AACS_VolumeIdentifier;
case DataType.AacsSerialNumber: return MediaTagType.AACS_SerialNumber;
case DataType.AacsMediaIdentifier: return MediaTagType.AACS_MediaIdentifier;
case DataType.AacsMediaKeyBlock: return MediaTagType.AACS_MKB;
case DataType.AacsDataKeys: return MediaTagType.AACS_DataKeys;
case DataType.AacsLbaExtents: return MediaTagType.AACS_LBAExtents;
case DataType.CprmMediaKeyBlock: return MediaTagType.AACS_CPRM_MKB;
case DataType.HybridRecognizedLayers: return MediaTagType.Hybrid_RecognizedLayers;
case DataType.ScsiMmcWriteProtection: return MediaTagType.MMC_WriteProtection;
case DataType.ScsiMmcDiscInformation: return MediaTagType.MMC_DiscInformation;
case DataType.ScsiMmcTrackResourcesInformation: return MediaTagType.MMC_TrackResourcesInformation;
case DataType.ScsiMmcPowResourcesInformation: return MediaTagType.MMC_POWResourcesInformation;
case DataType.ScsiInquiry: return MediaTagType.SCSI_INQUIRY;
case DataType.ScsiModePage2A: return MediaTagType.SCSI_MODEPAGE_2A;
case DataType.AtaIdentify: return MediaTagType.ATA_IDENTIFY;
case DataType.AtapiIdentify: return MediaTagType.ATAPI_IDENTIFY;
case DataType.PcmciaCis: return MediaTagType.PCMCIA_CIS;
case DataType.SecureDigitalCid: return MediaTagType.SD_CID;
case DataType.SecureDigitalCsd: return MediaTagType.SD_CSD;
case DataType.SecureDigitalScr: return MediaTagType.SD_SCR;
case DataType.SecureDigitalOcr: return MediaTagType.SD_OCR;
case DataType.MultiMediaCardCid: return MediaTagType.MMC_CID;
case DataType.MultiMediaCardCsd: return MediaTagType.MMC_CSD;
case DataType.MultiMediaCardOcr: return MediaTagType.MMC_OCR;
case DataType.MultiMediaCardExtendedCsd: return MediaTagType.MMC_ExtendedCSD;
case DataType.XboxSecuritySector: return MediaTagType.Xbox_SecuritySector;
case DataType.FloppyLeadOut: return MediaTagType.Floppy_LeadOut;
case DataType.DvdDiscControlBlock: return MediaTagType.DCB;
case DataType.CompactDiscFirstTrackPregap: return MediaTagType.CD_FirstTrackPregap;
case DataType.CompactDiscLeadOut: return MediaTagType.CD_LeadOut;
case DataType.ScsiModeSense6: return MediaTagType.SCSI_MODESENSE_6;
case DataType.ScsiModeSense10: return MediaTagType.SCSI_MODESENSE_10;
case DataType.UsbDescriptors: return MediaTagType.USB_Descriptors;
case DataType.XboxDmi: return MediaTagType.Xbox_DMI;
case DataType.XboxPfi: return MediaTagType.Xbox_PFI;
case DataType.CompactDiscMediaCatalogueNumber: return MediaTagType.CD_MCN;
case DataType.CompactDiscLeadIn: return MediaTagType.CD_LeadIn;
default: throw new ArgumentOutOfRangeException();
}
}
// Converts between dic media tag type and image data type
static DataType GetDataTypeForMediaTag(MediaTagType tag)
{
switch(tag)
{
case MediaTagType.CD_TOC: return DataType.CompactDiscPartialToc;
case MediaTagType.CD_SessionInfo: return DataType.CompactDiscSessionInfo;
case MediaTagType.CD_FullTOC: return DataType.CompactDiscToc;
case MediaTagType.CD_PMA: return DataType.CompactDiscPma;
case MediaTagType.CD_ATIP: return DataType.CompactDiscAtip;
case MediaTagType.CD_TEXT: return DataType.CompactDiscLeadInCdText;
case MediaTagType.DVD_PFI: return DataType.DvdPfi;
case MediaTagType.DVD_CMI: return DataType.DvdLeadInCmi;
case MediaTagType.DVD_DiscKey: return DataType.DvdDiscKey;
case MediaTagType.DVD_BCA: return DataType.DvdBca;
case MediaTagType.DVD_DMI: return DataType.DvdDmi;
case MediaTagType.DVD_MediaIdentifier: return DataType.DvdMediaIdentifier;
case MediaTagType.DVD_MKB: return DataType.DvdMediaKeyBlock;
case MediaTagType.DVDRAM_DDS: return DataType.DvdRamDds;
case MediaTagType.DVDRAM_MediumStatus: return DataType.DvdRamMediumStatus;
case MediaTagType.DVDRAM_SpareArea: return DataType.DvdRamSpareArea;
case MediaTagType.DVDR_RMD: return DataType.DvdRRmd;
case MediaTagType.DVDR_PreRecordedInfo: return DataType.DvdRPrerecordedInfo;
case MediaTagType.DVDR_MediaIdentifier: return DataType.DvdRMediaIdentifier;
case MediaTagType.DVDR_PFI: return DataType.DvdRPfi;
case MediaTagType.DVD_ADIP: return DataType.DvdAdip;
case MediaTagType.HDDVD_CPI: return DataType.HdDvdCpi;
case MediaTagType.HDDVD_MediumStatus: return DataType.HdDvdMediumStatus;
case MediaTagType.DVDDL_LayerCapacity: return DataType.DvdDlLayerCapacity;
case MediaTagType.DVDDL_MiddleZoneAddress: return DataType.DvdDlMiddleZoneAddress;
case MediaTagType.DVDDL_JumpIntervalSize: return DataType.DvdDlJumpIntervalSize;
case MediaTagType.DVDDL_ManualLayerJumpLBA: return DataType.DvdDlManualLayerJumpLba;
case MediaTagType.BD_DI: return DataType.BlurayDi;
case MediaTagType.BD_BCA: return DataType.BlurayBca;
case MediaTagType.BD_DDS: return DataType.BlurayDds;
case MediaTagType.BD_CartridgeStatus: return DataType.BlurayCartridgeStatus;
case MediaTagType.BD_SpareArea: return DataType.BluraySpareArea;
case MediaTagType.AACS_VolumeIdentifier: return DataType.AacsVolumeIdentifier;
case MediaTagType.AACS_SerialNumber: return DataType.AacsSerialNumber;
case MediaTagType.AACS_MediaIdentifier: return DataType.AacsMediaIdentifier;
case MediaTagType.AACS_MKB: return DataType.AacsMediaKeyBlock;
case MediaTagType.AACS_DataKeys: return DataType.AacsDataKeys;
case MediaTagType.AACS_LBAExtents: return DataType.AacsLbaExtents;
case MediaTagType.AACS_CPRM_MKB: return DataType.CprmMediaKeyBlock;
case MediaTagType.Hybrid_RecognizedLayers: return DataType.HybridRecognizedLayers;
case MediaTagType.MMC_WriteProtection: return DataType.ScsiMmcWriteProtection;
case MediaTagType.MMC_DiscInformation: return DataType.ScsiMmcDiscInformation;
case MediaTagType.MMC_TrackResourcesInformation: return DataType.ScsiMmcTrackResourcesInformation;
case MediaTagType.MMC_POWResourcesInformation: return DataType.ScsiMmcPowResourcesInformation;
case MediaTagType.SCSI_INQUIRY: return DataType.ScsiInquiry;
case MediaTagType.SCSI_MODEPAGE_2A: return DataType.ScsiModePage2A;
case MediaTagType.ATA_IDENTIFY: return DataType.AtaIdentify;
case MediaTagType.ATAPI_IDENTIFY: return DataType.AtapiIdentify;
case MediaTagType.PCMCIA_CIS: return DataType.PcmciaCis;
case MediaTagType.SD_CID: return DataType.SecureDigitalCid;
case MediaTagType.SD_CSD: return DataType.SecureDigitalCsd;
case MediaTagType.SD_SCR: return DataType.SecureDigitalScr;
case MediaTagType.SD_OCR: return DataType.SecureDigitalOcr;
case MediaTagType.MMC_CID: return DataType.MultiMediaCardCid;
case MediaTagType.MMC_CSD: return DataType.MultiMediaCardCsd;
case MediaTagType.MMC_OCR: return DataType.MultiMediaCardOcr;
case MediaTagType.MMC_ExtendedCSD: return DataType.MultiMediaCardExtendedCsd;
case MediaTagType.Xbox_SecuritySector: return DataType.XboxSecuritySector;
case MediaTagType.Floppy_LeadOut: return DataType.FloppyLeadOut;
case MediaTagType.DCB: return DataType.DvdDiscControlBlock;
case MediaTagType.CD_FirstTrackPregap: return DataType.CompactDiscFirstTrackPregap;
case MediaTagType.CD_LeadOut: return DataType.CompactDiscLeadOut;
case MediaTagType.SCSI_MODESENSE_6: return DataType.ScsiModeSense6;
case MediaTagType.SCSI_MODESENSE_10: return DataType.ScsiModeSense10;
case MediaTagType.USB_Descriptors: return DataType.UsbDescriptors;
case MediaTagType.Xbox_DMI: return DataType.XboxDmi;
case MediaTagType.Xbox_PFI: return DataType.XboxPfi;
case MediaTagType.CD_MCN: return DataType.CompactDiscMediaCatalogueNumber;
case MediaTagType.CD_LeadIn: return DataType.CompactDiscLeadIn;
default:
throw new ArgumentOutOfRangeException(nameof(tag), tag, null);
}
}
}
}

View File

@@ -0,0 +1,55 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Identify.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Identifies DiscImageChef format disk 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System.IO;
using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Helpers;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
public bool Identify(IFilter imageFilter)
{
imageStream = imageFilter.GetDataForkStream();
imageStream.Seek(0, SeekOrigin.Begin);
if(imageStream.Length < Marshal.SizeOf<DicHeader>()) return false;
structureBytes = new byte[Marshal.SizeOf<DicHeader>()];
imageStream.Read(structureBytes, 0, structureBytes.Length);
header = Marshal.ByteArrayToStructureLittleEndian<DicHeader>(structureBytes);
return header.identifier == DIC_MAGIC && header.imageMajorVersion <= DICF_VERSION;
}
}
}

View File

@@ -0,0 +1,83 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Properties.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains properties for DiscImageChef format disk 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Structs;
using Schemas;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
public ImageInfo Info => imageInfo;
public string Name => "DiscImageChef format";
public Guid Id => new Guid("49360069-1784-4A2F-B723-0C844D610B0A");
public string Format => "DiscImageChef";
public string Author => "Natalia Portillo";
public List<Partition> Partitions { get; private set; }
public List<Track> Tracks { get; private set; }
public List<Session> Sessions { get; private set; }
public List<DumpHardwareType> DumpHardware { get; private set; }
public CICMMetadataType CicmMetadata { get; private set; }
public IEnumerable<MediaTagType> SupportedMediaTags =>
Enum.GetValues(typeof(MediaTagType)).Cast<MediaTagType>();
public IEnumerable<SectorTagType> SupportedSectorTags =>
Enum.GetValues(typeof(SectorTagType)).Cast<SectorTagType>();
public IEnumerable<MediaType> SupportedMediaTypes => Enum.GetValues(typeof(MediaType)).Cast<MediaType>();
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
new[]
{
("sectors_per_block", typeof(uint),
"How many sectors to store per block (will be rounded to next power of two)", 4096U),
("dictionary", typeof(uint), "Size, in bytes, of the LZMA dictionary", (uint)(1 << 25)),
("max_ddt_size", typeof(uint),
"Maximum size, in mebibytes, for in-memory DDT. If image needs a bigger one, it will be on-disk",
256U),
("md5", typeof(bool), "Calculate and store MD5 of image's user data", (object)false),
("sha1", typeof(bool), "Calculate and store SHA1 of image's user data", (object)false),
("sha256", typeof(bool), "Calculate and store SHA256 of image's user data", (object)false),
("spamsum", typeof(bool), "Calculate and store SpamSum of image's user data", (object)false),
("deduplicate", typeof(bool),
"Store only unique sectors. This consumes more memory and is slower, but it's enabled by default",
(object)true),
("nocompress", typeof(bool),
"Don't compress user data blocks. Other blocks will still be compressed", (object)false)
};
public IEnumerable<string> KnownExtensions => new[] {".dicf"};
public bool IsWriting { get; private set; }
public string ErrorMessage { get; private set; }
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,394 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Structs.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains structures for DiscImageChef format disk 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System.Runtime.InteropServices;
using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
/// <summary>Header, at start of file</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
struct DicHeader
{
/// <summary>Header identifier, <see cref="DIC_MAGIC" /></summary>
public ulong identifier;
/// <summary>UTF-16LE name of the application that created the image</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string application;
/// <summary>Image format major version. A new major version means a possibly incompatible change of format</summary>
public byte imageMajorVersion;
/// <summary>Image format minor version. A new minor version indicates a compatible change of format</summary>
public byte imageMinorVersion;
/// <summary>Major version of the application that created the image</summary>
public byte applicationMajorVersion;
/// <summary>Minor version of the application that created the image</summary>
public byte applicationMinorVersion;
/// <summary>Type of media contained on image</summary>
public MediaType mediaType;
/// <summary>Offset to index</summary>
public ulong indexOffset;
/// <summary>Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image creation time</summary>
public long creationTime;
/// <summary>Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image last written time</summary>
public long lastWrittenTime;
}
/// <summary>Header for a deduplication table. Table follows it</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct DdtHeader
{
/// <summary>Identifier, <see cref="BlockType.DeDuplicationTable" /></summary>
public BlockType identifier;
/// <summary>Type of data pointed by this DDT</summary>
public DataType type;
/// <summary>Compression algorithm used to compress the DDT</summary>
public CompressionType compression;
/// <summary>Each entry is ((byte offset in file) &lt;&lt; shift) + (sector offset in block)</summary>
public byte shift;
/// <summary>How many entries are in the table</summary>
public ulong entries;
/// <summary>Compressed length for the DDT</summary>
public ulong cmpLength;
/// <summary>Uncompressed length for the DDT</summary>
public ulong length;
/// <summary>CRC64-ECMA of the compressed DDT</summary>
public ulong cmpCrc64;
/// <summary>CRC64-ECMA of the uncompressed DDT</summary>
public readonly ulong crc64;
}
/// <summary>Header for the index, followed by entries</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IndexHeader
{
/// <summary>Identifier, <see cref="BlockType.Index" /></summary>
public BlockType identifier;
/// <summary>How many entries follow this header</summary>
public ushort entries;
/// <summary>CRC64-ECMA of the index</summary>
public ulong crc64;
}
/// <summary>Index entry</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IndexEntry
{
/// <summary>Type of item pointed by this entry</summary>
public BlockType blockType;
/// <summary>Type of data contained by the block pointed by this entry</summary>
public DataType dataType;
/// <summary>Offset in file where item is stored</summary>
public ulong offset;
}
/// <summary>Block header, precedes block data</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct BlockHeader
{
/// <summary>Identifier, <see cref="BlockType.DataBlock" /></summary>
public BlockType identifier;
/// <summary>Type of data contained by this block</summary>
public DataType type;
/// <summary>Compression algorithm used to compress the block</summary>
public CompressionType compression;
/// <summary>Size in bytes of each sector contained in this block</summary>
public uint sectorSize;
/// <summary>Compressed length for the block</summary>
public uint cmpLength;
/// <summary>Uncompressed length for the block</summary>
public uint length;
/// <summary>CRC64-ECMA of the compressed block</summary>
public ulong cmpCrc64;
/// <summary>CRC64-ECMA of the uncompressed block</summary>
public ulong crc64;
}
/// <summary>Geometry block, contains physical geometry information</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct GeometryBlock
{
/// <summary>Identifier, <see cref="BlockType.GeometryBlock" /></summary>
public BlockType identifier;
public uint cylinders;
public uint heads;
public uint sectorsPerTrack;
}
/// <summary>Metadata block, contains metadata</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MetadataBlock
{
/// <summary>Identifier, <see cref="BlockType.MetadataBlock" /></summary>
public BlockType identifier;
/// <summary>Size in bytes of this whole metadata block</summary>
public uint blockSize;
/// <summary>Sequence of media set this media belongs to</summary>
public int mediaSequence;
/// <summary>Total number of media on the media set this media belongs to</summary>
public int lastMediaSequence;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint creatorOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint creatorLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint commentsOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint commentsLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint mediaTitleOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint mediaTitleLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint mediaManufacturerOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint mediaManufacturerLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint mediaModelOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint mediaModelLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint mediaSerialNumberOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint mediaSerialNumberLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint mediaBarcodeOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint mediaBarcodeLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint mediaPartNumberOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint mediaPartNumberLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint driveManufacturerOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint driveManufacturerLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint driveModelOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint driveModelLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint driveSerialNumberOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint driveSerialNumberLength;
/// <summary>Offset to start of creator string from start of this block</summary>
public uint driveFirmwareRevisionOffset;
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
public uint driveFirmwareRevisionLength;
}
/// <summary>Contains list of optical disc tracks</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct TracksHeader
{
/// <summary>Identifier, <see cref="BlockType.TracksBlock" /></summary>
public BlockType identifier;
/// <summary>How many entries follow this header</summary>
public ushort entries;
/// <summary>CRC64-ECMA of the block</summary>
public ulong crc64;
}
/// <summary>Optical disc track</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
struct TrackEntry
{
/// <summary>Track sequence</summary>
public byte sequence;
/// <summary>Track type</summary>
public TrackType type;
/// <summary>Track starting LBA</summary>
public long start;
/// <summary>Track last LBA</summary>
public long end;
/// <summary>Track pregap in sectors</summary>
public long pregap;
/// <summary>Track session</summary>
public byte session;
/// <summary>Track's ISRC in ASCII</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
public string isrc;
/// <summary>Track flags</summary>
public byte flags;
}
/// <summary>Geometry block, contains physical geometry information</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct CicmMetadataBlock
{
/// <summary>Identifier, <see cref="BlockType.CicmBlock" /></summary>
public BlockType identifier;
public uint length;
}
/// <summary>Dump hardware block, contains a list of hardware used to dump the media on this image</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct DumpHardwareHeader
{
/// <summary>Identifier, <see cref="BlockType.DumpHardwareBlock" /></summary>
public BlockType identifier;
/// <summary>How many entries follow this header</summary>
public ushort entries;
/// <summary>Size of the whole block, not including this header, in bytes</summary>
public uint length;
/// <summary>CRC64-ECMA of the block</summary>
public ulong crc64;
}
/// <summary>Dump hardware entry, contains length of strings that follow, in the same order as the length, this structure</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct DumpHardwareEntry
{
/// <summary>Length of UTF-8 manufacturer string</summary>
public uint manufacturerLength;
/// <summary>Length of UTF-8 model string</summary>
public uint modelLength;
/// <summary>Length of UTF-8 revision string</summary>
public uint revisionLength;
/// <summary>Length of UTF-8 firmware version string</summary>
public uint firmwareLength;
/// <summary>Length of UTF-8 serial string</summary>
public uint serialLength;
/// <summary>Length of UTF-8 software name string</summary>
public uint softwareNameLength;
/// <summary>Length of UTF-8 software version string</summary>
public uint softwareVersionLength;
/// <summary>Length of UTF-8 software operating system string</summary>
public uint softwareOperatingSystemLength;
/// <summary>How many extents are after the strings</summary>
public uint extents;
}
/// <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;
}
/// <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;
}
/// <summary>
/// Tape file block, contains a list of all files in a tape
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct TapeFileHeader
{
/// <summary>Identifier, <see cref="BlockType.TapeFileBlock" /></summary>
public BlockType identifier;
/// <summary>How many entries follow this header</summary>
public uint entries;
/// <summary>Size of the whole block, not including this header, in bytes</summary>
public ulong length;
/// <summary>CRC64-ECMA of the block</summary>
public ulong crc64;
}
/// <summary>
/// Tape file entry
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct TapeFileEntry
{
/// <summary>
/// File number
/// </summary>
public uint File;
/// <summary>
/// Partition number
/// </summary>
public readonly byte Partition;
/// <summary>
/// First block, inclusive, of the file
/// </summary>
public ulong FirstBlock;
/// <summary>
/// Last block, inclusive, of the file
/// </summary>
public ulong LastBlock;
}
/// <summary>
/// Tape partition block, contains a list of all partitions in a tape
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct TapePartitionHeader
{
/// <summary>Identifier, <see cref="BlockType.TapePartitionBlock" /></summary>
public BlockType identifier;
/// <summary>How many entries follow this header</summary>
public byte entries;
/// <summary>Size of the whole block, not including this header, in bytes</summary>
public ulong length;
/// <summary>CRC64-ECMA of the block</summary>
public ulong crc64;
}
/// <summary>
/// Tape partition entry
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TapePartitionEntry
{
/// <summary>
/// Partition number
/// </summary>
public byte Number;
/// <summary>
/// First block, inclusive, of the partition
/// </summary>
public ulong FirstBlock;
/// <summary>
/// Last block, inclusive, of the partition
/// </summary>
public ulong LastBlock;
}
}
}

View File

@@ -0,0 +1,76 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Tape.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Manages DiscImageChef format tape 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System.Collections.Generic;
using System.Linq;
using DiscImageChef.CommonTypes.Structs;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
public List<TapeFile> Files { get; private set; }
public List<TapePartition> TapePartitions { get; private set; }
public bool IsTape { get; private set; }
public bool AddFile(TapeFile file)
{
if(Files.Any(f => f.File == file.File))
{
TapeFile removeMe = Files.FirstOrDefault(f => f.File == file.File);
Files.Remove(removeMe);
}
Files.Add(file);
return true;
}
public bool AddPartition(TapePartition partition)
{
if(TapePartitions.Any(f => f.Number == partition.Number))
{
TapePartition removeMe = TapePartitions.FirstOrDefault(f => f.Number == partition.Number);
TapePartitions.Remove(removeMe);
}
TapePartitions.Add(partition);
return true;
}
public bool SetTape()
{
Files = new List<TapeFile>();
TapePartitions = new List<TapePartition>();
return IsTape = true;
}
}
}

View File

@@ -0,0 +1,301 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : Verify.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Verifies DiscImageChef format disk 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using System.Collections.Generic;
using DiscImageChef.Checksums;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console;
using DiscImageChef.Helpers;
namespace DiscImageChef.DiscImages
{
public partial class DiscImageChef
{
public bool? VerifyMediaImage()
{
// This will traverse all blocks and check their CRC64 without uncompressing them
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Checking index integrity at {0}",
header.indexOffset);
imageStream.Position = (long)header.indexOffset;
structureBytes = new byte[Marshal.SizeOf<IndexHeader>()];
imageStream.Read(structureBytes, 0, structureBytes.Length);
IndexHeader idxHeader = Marshal.SpanToStructureLittleEndian<IndexHeader>(structureBytes);
if(idxHeader.identifier != BlockType.Index)
{
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Incorrect index identifier");
return false;
}
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Index at {0} contains {1} entries",
header.indexOffset, idxHeader.entries);
structureBytes = new byte[Marshal.SizeOf<IndexEntry>() * idxHeader.entries];
imageStream.Read(structureBytes, 0, structureBytes.Length);
Crc64Context.Data(structureBytes, out byte[] verifyCrc);
if(BitConverter.ToUInt64(verifyCrc, 0) != idxHeader.crc64)
{
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Expected index CRC {0:X16} but got {1:X16}",
idxHeader.crc64, BitConverter.ToUInt64(verifyCrc, 0));
return false;
}
imageStream.Position -= structureBytes.Length;
List<IndexEntry> vrIndex = new List<IndexEntry>();
for(ushort i = 0; i < idxHeader.entries; i++)
{
structureBytes = new byte[Marshal.SizeOf<IndexEntry>()];
imageStream.Read(structureBytes, 0, structureBytes.Length);
IndexEntry entry = Marshal.SpanToStructureLittleEndian<IndexEntry>(structureBytes);
DicConsole.DebugWriteLine("DiscImageChef format plugin",
"Block type {0} with data type {1} is indexed to be at {2}", entry.blockType,
entry.dataType, entry.offset);
vrIndex.Add(entry);
}
// Read up to 1MiB at a time for verification
const int VERIFY_SIZE = 1024 * 1024;
foreach(IndexEntry entry in vrIndex)
{
imageStream.Position = (long)entry.offset;
Crc64Context crcVerify;
ulong readBytes;
byte[] verifyBytes;
switch(entry.blockType)
{
case BlockType.DataBlock:
structureBytes = new byte[Marshal.SizeOf<BlockHeader>()];
imageStream.Read(structureBytes, 0, structureBytes.Length);
BlockHeader blockHeader = Marshal.SpanToStructureLittleEndian<BlockHeader>(structureBytes);
crcVerify = new Crc64Context();
readBytes = 0;
DicConsole.DebugWriteLine("DiscImageChef format plugin",
"Verifying data block type {0} at position {1}", entry.dataType,
entry.offset);
while(readBytes + VERIFY_SIZE < blockHeader.cmpLength)
{
verifyBytes = new byte[VERIFY_SIZE];
imageStream.Read(verifyBytes, 0, verifyBytes.Length);
crcVerify.Update(verifyBytes);
readBytes += (ulong)verifyBytes.LongLength;
}
verifyBytes = new byte[blockHeader.cmpLength - readBytes];
imageStream.Read(verifyBytes, 0, verifyBytes.Length);
crcVerify.Update(verifyBytes);
verifyCrc = crcVerify.Final();
if(BitConverter.ToUInt64(verifyCrc, 0) != blockHeader.cmpCrc64)
{
DicConsole.DebugWriteLine("DiscImageChef format plugin",
"Expected block CRC {0:X16} but got {1:X16}",
blockHeader.cmpCrc64, BitConverter.ToUInt64(verifyCrc, 0));
return false;
}
break;
case BlockType.DeDuplicationTable:
structureBytes = new byte[Marshal.SizeOf<DdtHeader>()];
imageStream.Read(structureBytes, 0, structureBytes.Length);
DdtHeader ddtHeader = Marshal.SpanToStructureLittleEndian<DdtHeader>(structureBytes);
crcVerify = new Crc64Context();
readBytes = 0;
DicConsole.DebugWriteLine("DiscImageChef format plugin",
"Verifying deduplication table type {0} at position {1}",
entry.dataType, entry.offset);
while(readBytes + VERIFY_SIZE < ddtHeader.cmpLength)
{
verifyBytes = new byte[readBytes];
imageStream.Read(verifyBytes, 0, verifyBytes.Length);
crcVerify.Update(verifyBytes);
readBytes += (ulong)verifyBytes.LongLength;
}
verifyBytes = new byte[ddtHeader.cmpLength - readBytes];
imageStream.Read(verifyBytes, 0, verifyBytes.Length);
crcVerify.Update(verifyBytes);
verifyCrc = crcVerify.Final();
if(BitConverter.ToUInt64(verifyCrc, 0) != ddtHeader.cmpCrc64)
{
DicConsole.DebugWriteLine("DiscImageChef format plugin",
"Expected DDT CRC {0:X16} but got {1:X16}", ddtHeader.cmpCrc64,
BitConverter.ToUInt64(verifyCrc, 0));
return false;
}
break;
case BlockType.TracksBlock:
structureBytes = new byte[Marshal.SizeOf<TracksHeader>()];
imageStream.Read(structureBytes, 0, structureBytes.Length);
TracksHeader trkHeader = Marshal.SpanToStructureLittleEndian<TracksHeader>(structureBytes);
DicConsole.DebugWriteLine("DiscImageChef format plugin",
"Track block at {0} contains {1} entries", header.indexOffset,
trkHeader.entries);
structureBytes = new byte[Marshal.SizeOf<TrackEntry>() * trkHeader.entries];
imageStream.Read(structureBytes, 0, structureBytes.Length);
Crc64Context.Data(structureBytes, out verifyCrc);
if(BitConverter.ToUInt64(verifyCrc, 0) != trkHeader.crc64)
{
DicConsole.DebugWriteLine("DiscImageChef format plugin",
"Expected index CRC {0:X16} but got {1:X16}", trkHeader.crc64,
BitConverter.ToUInt64(verifyCrc, 0));
return false;
}
break;
default:
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Ignored field type {0}",
entry.blockType);
break;
}
}
return true;
}
public bool? VerifySector(ulong sectorAddress)
{
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc) return null;
byte[] buffer = ReadSectorLong(sectorAddress);
return CdChecksums.CheckCdSector(buffer);
}
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
out List<ulong> unknownLbas)
{
failingLbas = new List<ulong>();
unknownLbas = new List<ulong>();
// Right now only CompactDisc sectors are verifyable
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
{
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
return null;
}
byte[] buffer = ReadSectorsLong(sectorAddress, length);
int bps = (int)(buffer.Length / length);
byte[] sector = new byte[bps];
failingLbas = new List<ulong>();
unknownLbas = new List<ulong>();
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<ulong> failingLbas,
out List<ulong> unknownLbas)
{
// Right now only CompactDisc sectors are verifyable
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
{
failingLbas = new List<ulong>();
unknownLbas = new List<ulong>();
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
return null;
}
byte[] buffer = ReadSectorsLong(sectorAddress, length, track);
int bps = (int)(buffer.Length / length);
byte[] sector = new byte[bps];
failingLbas = new List<ulong>();
unknownLbas = new List<ulong>();
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? VerifySector(ulong sectorAddress, uint track)
{
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc) return null;
byte[] buffer = ReadSectorLong(sectorAddress, track);
return CdChecksums.CheckCdSector(buffer);
}
}
}

File diff suppressed because it is too large Load Diff