Refactor image classes and split them to smaller files.

This commit is contained in:
2018-07-23 23:25:43 +01:00
parent 55ca2d23b6
commit ed88989642
445 changed files with 50086 additions and 34342 deletions

View File

@@ -0,0 +1,296 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : ClauniaSubchannelTransform.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains the Claunia Subchannel Transform algorithm.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-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;
}
}
}

View 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;
}
}

View 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
};
}
}
}

View 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
}
}
}

View 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);
}
}
}
}

View 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;
}
}
}

View 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; }
}
}

File diff suppressed because it is too large Load Diff

View 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) &lt;&lt; shift) + (sector offset in block)</summary>
public byte shift;
/// <summary>How many entries are in the table</summary>
public ulong entries;
/// <summary>Compressed length for the DDT</summary>
public ulong cmpLength;
/// <summary>Uncompressed length for the DDT</summary>
public ulong length;
/// <summary>CRC64-ECMA of the compressed DDT</summary>
public ulong cmpCrc64;
/// <summary>CRC64-ECMA of the uncompressed DDT</summary>
public 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;
}
}
}

View 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;
}
}
}

File diff suppressed because it is too large Load Diff