mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Refactor image classes and split them to smaller files.
This commit is contained in:
@@ -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-2018 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
DiscImageChef.DiscImages/DiscImageChef/Constants.cs
Normal file
60
DiscImageChef.DiscImages/DiscImageChef/Constants.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
// /***************************************************************************
|
||||
// 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-2018 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;
|
||||
}
|
||||
}
|
||||
188
DiscImageChef.DiscImages/DiscImageChef/DiscImageChef.cs
Normal file
188
DiscImageChef.DiscImages/DiscImageChef/DiscImageChef.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
// /***************************************************************************
|
||||
// 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-2018 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 : IWritableImage
|
||||
{
|
||||
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;
|
||||
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;
|
||||
/// <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;
|
||||
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;
|
||||
/// <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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
247
DiscImageChef.DiscImages/DiscImageChef/Enums.cs
Normal file
247
DiscImageChef.DiscImages/DiscImageChef/Enums.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
// /***************************************************************************
|
||||
// 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-2018 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 Lead-in</summary>
|
||||
CompactDiscLeadIn = 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>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>TODO: Block containing list of files for a tape image</summary>
|
||||
TapeFileBlock = 0x454C4654
|
||||
}
|
||||
|
||||
enum ChecksumAlgorithm : byte
|
||||
{
|
||||
Invalid = 0,
|
||||
Md5 = 1,
|
||||
Sha1 = 2,
|
||||
Sha256 = 3,
|
||||
SpamSum = 4
|
||||
}
|
||||
}
|
||||
}
|
||||
407
DiscImageChef.DiscImages/DiscImageChef/Helpers.cs
Normal file
407
DiscImageChef.DiscImages/DiscImageChef/Helpers.cs
Normal file
@@ -0,0 +1,407 @@
|
||||
// /***************************************************************************
|
||||
// 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-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.Decoders.ATA;
|
||||
using DiscImageChef.Decoders.SCSI;
|
||||
using DiscImageChef.Decoders.SecureDigital;
|
||||
using VendorString = DiscImageChef.Decoders.SecureDigital.VendorString;
|
||||
|
||||
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.SCSIInquiry? nullableInquiry = Inquiry.Decode(scsiInquiry);
|
||||
|
||||
if(nullableInquiry.HasValue)
|
||||
{
|
||||
Inquiry.SCSIInquiry 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 = Decoders.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.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: 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(typeof(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)
|
||||
{
|
||||
userDataDdt[sectorAddress] = pointer;
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPosition = imageStream.Position;
|
||||
imageStream.Position = outMemoryDdtPosition + Marshal.SizeOf(typeof(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.CompactDiscLeadIn: return MediaTagType.CD_LeadIn;
|
||||
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;
|
||||
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_LeadIn: return DataType.CompactDiscLeadIn;
|
||||
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;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(tag), tag, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
DiscImageChef.DiscImages/DiscImageChef/Identify.cs
Normal file
59
DiscImageChef.DiscImages/DiscImageChef/Identify.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
// /***************************************************************************
|
||||
// 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-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
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(header)) return false;
|
||||
|
||||
header = new DicHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(header)];
|
||||
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(header));
|
||||
Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(header));
|
||||
header = (DicHeader)Marshal.PtrToStructure(structurePointer, typeof(DicHeader));
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
|
||||
return header.identifier == DIC_MAGIC && header.imageMajorVersion <= DICF_VERSION;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
DiscImageChef.DiscImages/DiscImageChef/Properties.cs
Normal file
79
DiscImageChef.DiscImages/DiscImageChef/Properties.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
// /***************************************************************************
|
||||
// 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-2018 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 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)> SupportedOptions =>
|
||||
new[]
|
||||
{
|
||||
("sectors_per_block", typeof(uint),
|
||||
"How many sectors to store per block (will be rounded to next power of two)"),
|
||||
("dictionary", typeof(uint), "Size, in bytes, of the LZMA dictionary"),
|
||||
("max_ddt_size", typeof(uint),
|
||||
"Maximum size, in mebibytes, for in-memory DDT. If image needs a bigger one, it will be on-disk"),
|
||||
("md5", typeof(bool), "Calculate and store MD5 of image's user data"),
|
||||
("sha1", typeof(bool), "Calculate and store SHA1 of image's user data"),
|
||||
("sha256", typeof(bool), "Calculate and store SHA256 of image's user data"),
|
||||
("spamsum", typeof(bool), "Calculate and store SpamSum of image's user data"),
|
||||
("deduplicate", typeof(bool),
|
||||
"Store only unique sectors. This consumes more memory and is slower, but it's enabled by default"),
|
||||
("nocompress", typeof(bool), "Don't compress user data blocks. Other blocks will still be compressed")
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] {".dicf"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
1423
DiscImageChef.DiscImages/DiscImageChef/Read.cs
Normal file
1423
DiscImageChef.DiscImages/DiscImageChef/Read.cs
Normal file
File diff suppressed because it is too large
Load Diff
326
DiscImageChef.DiscImages/DiscImageChef/Structs.cs
Normal file
326
DiscImageChef.DiscImages/DiscImageChef/Structs.cs
Normal file
@@ -0,0 +1,326 @@
|
||||
// /***************************************************************************
|
||||
// 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-2018 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) << 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 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>Dump hardware extent, first and last sector dumped, both inclusive</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DumpHardwareExtent
|
||||
{
|
||||
public ulong start;
|
||||
public ulong end;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checksum block, contains a checksum of all user data sectors (except for optical discs that is 2352 bytes raw
|
||||
/// sector if available
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ChecksumHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.ChecksumBlock" /></summary>
|
||||
public BlockType identifier;
|
||||
/// <summary>Length in bytes of the block</summary>
|
||||
public uint length;
|
||||
/// <summary>How many checksums follow</summary>
|
||||
public byte entries;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
321
DiscImageChef.DiscImages/DiscImageChef/Verify.cs
Normal file
321
DiscImageChef.DiscImages/DiscImageChef/Verify.cs
Normal file
@@ -0,0 +1,321 @@
|
||||
// /***************************************************************************
|
||||
// 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-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.Checksums;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class DiscImageChef
|
||||
{
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc) return null;
|
||||
|
||||
byte[] buffer = ReadSectorLong(sectorAddress);
|
||||
return CdChecksums.CheckCdSector(buffer);
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc) return null;
|
||||
|
||||
byte[] buffer = ReadSectorLong(sectorAddress, track);
|
||||
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? 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;
|
||||
|
||||
IndexHeader idxHeader = new IndexHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(idxHeader)];
|
||||
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(idxHeader));
|
||||
Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(idxHeader));
|
||||
idxHeader = (IndexHeader)Marshal.PtrToStructure(structurePointer, typeof(IndexHeader));
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
|
||||
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(typeof(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++)
|
||||
{
|
||||
IndexEntry entry = new IndexEntry();
|
||||
structureBytes = new byte[Marshal.SizeOf(entry)];
|
||||
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(entry));
|
||||
Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(entry));
|
||||
entry = (IndexEntry)Marshal.PtrToStructure(structurePointer, typeof(IndexEntry));
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
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:
|
||||
BlockHeader blockHeader = new BlockHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(blockHeader)];
|
||||
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(blockHeader));
|
||||
Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(blockHeader));
|
||||
blockHeader = (BlockHeader)Marshal.PtrToStructure(structurePointer, typeof(BlockHeader));
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
|
||||
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:
|
||||
DdtHeader ddtHeader = new DdtHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(ddtHeader)];
|
||||
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(ddtHeader));
|
||||
Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(ddtHeader));
|
||||
ddtHeader = (DdtHeader)Marshal.PtrToStructure(structurePointer, typeof(DdtHeader));
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
|
||||
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:
|
||||
TracksHeader trkHeader = new TracksHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(trkHeader)];
|
||||
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(trkHeader));
|
||||
Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(trkHeader));
|
||||
trkHeader = (TracksHeader)Marshal.PtrToStructure(structurePointer, typeof(TracksHeader));
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Track block at {0} contains {1} entries", header.indexOffset,
|
||||
trkHeader.entries);
|
||||
|
||||
structureBytes = new byte[Marshal.SizeOf(typeof(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
2528
DiscImageChef.DiscImages/DiscImageChef/Write.cs
Normal file
2528
DiscImageChef.DiscImages/DiscImageChef/Write.cs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user