mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Add DiscImageChef format version 1.
This commit is contained in:
@@ -50,13 +50,13 @@
|
||||
Apple GCR sector tags).
|
||||
|
||||
Optical disks contain a track block that describes the tracks.
|
||||
Streaming tapes contain a file block that describes the files and an optional partition block that describes the tape
|
||||
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.
|
||||
TODO: 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. This is not yet implemented.
|
||||
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.
|
||||
@@ -90,50 +90,92 @@ using VendorString = DiscImageChef.Decoders.SecureDigital.VendorString;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Work in progress
|
||||
public class DiscImageChef : IWritableImage
|
||||
{
|
||||
const ulong DIC_MAGIC = 0x544D464444434944;
|
||||
const byte DICF_VERSION = 0;
|
||||
/// <summary>Magic identidier = "DICMFMT".</summary>
|
||||
const ulong DIC_MAGIC = 0x544D52464D434944;
|
||||
/// <summary>
|
||||
/// Image format version. A change in this number indicates an incompatible change to the format that
|
||||
/// prevents older implementations from reading it correctly, if at all.
|
||||
/// </summary>
|
||||
const byte DICF_VERSION = 1;
|
||||
/// <summary>Maximum read cache size, 256MiB.</summary>
|
||||
const uint MAX_CACHE_SIZE = 256 * 1024 * 1024;
|
||||
/// <summary>Size in bytes of LZMA properties.</summary>
|
||||
const int LZMA_PROPERTIES_LENGTH = 5;
|
||||
/// <summary>Maximum number of entries for the DDT cache.</summary>
|
||||
const int MAX_DDT_ENTRY_CACHE = 16000000;
|
||||
|
||||
/// <summary>How many samples are contained in a RedBook sector.</summary>
|
||||
const int SAMPLES_PER_SECTOR = 588;
|
||||
/// <summary>Maximum number of samples for a FLAC block. Bigger than 4608 gives no benefit.</summary>
|
||||
const int MAX_FLAKE_BLOCK = 4608;
|
||||
/// <summary>
|
||||
/// Minimum number of samples for a FLAC block. <see cref="CUETools.Codecs.FLAKE" /> does not support it to be
|
||||
/// smaller than 256.
|
||||
/// </summary>
|
||||
const int MIN_FLAKE_BLOCK = 256;
|
||||
|
||||
/// <summary>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;
|
||||
LzmaStream compressedBlockStream;
|
||||
/// <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;
|
||||
/// <summary>On-memory deduplication table indexed by checksum.</summary>
|
||||
Dictionary<byte[], 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;
|
||||
/// <summary>LZMA stream.</summary>
|
||||
LzmaStream lzmaBlockStream;
|
||||
/// <summary>LZMA properties.</summary>
|
||||
LzmaEncoderProperties lzmaEncoderProperties;
|
||||
/// <summary>Cache of media tags.</summary>
|
||||
Dictionary<MediaTagType, byte[]> mediaTags;
|
||||
/// <summary>If DDT is on-disk, this is the image stream offset at which it starts.</summary>
|
||||
long outMemoryDdtPosition;
|
||||
/// <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;
|
||||
/// <summary>Shift for calculating number of sectors in a block.</summary>
|
||||
byte shift;
|
||||
/// <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;
|
||||
|
||||
public DiscImageChef()
|
||||
@@ -212,6 +254,7 @@ namespace DiscImageChef.DiscImages
|
||||
imageInfo.Version = $"{header.imageMajorVersion}.{header.imageMinorVersion}";
|
||||
imageInfo.MediaType = header.mediaType;
|
||||
|
||||
// Read the index header
|
||||
imageStream.Position = (long)header.indexOffset;
|
||||
IndexHeader idxHeader = new IndexHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(idxHeader)];
|
||||
@@ -226,6 +269,7 @@ namespace DiscImageChef.DiscImages
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Index at {0} contains {1} entries",
|
||||
header.indexOffset, idxHeader.entries);
|
||||
|
||||
// Fill in-memory index
|
||||
index = new List<IndexEntry>();
|
||||
for(ushort i = 0; i < idxHeader.entries; i++)
|
||||
{
|
||||
@@ -296,6 +340,7 @@ namespace DiscImageChef.DiscImages
|
||||
"Found data block type {0} at position {1}", entry.dataType,
|
||||
entry.offset);
|
||||
|
||||
// Decompress media tag
|
||||
if(blockHeader.compression == CompressionType.Lzma)
|
||||
{
|
||||
byte[] compressedTag = new byte[blockHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
@@ -322,6 +367,7 @@ namespace DiscImageChef.DiscImages
|
||||
break;
|
||||
}
|
||||
|
||||
// Check CRC, if not correct, skip it
|
||||
Crc64Context.Data(data, out byte[] blockCrc);
|
||||
blockCrc = blockCrc.Reverse().ToArray();
|
||||
if(BitConverter.ToUInt64(blockCrc, 0) != blockHeader.crc64)
|
||||
@@ -332,6 +378,7 @@ namespace DiscImageChef.DiscImages
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if it's not a media tag, but a sector tag, and fill the appropriate table then
|
||||
switch(entry.dataType)
|
||||
{
|
||||
case DataType.CdSectorPrefix:
|
||||
@@ -401,6 +448,7 @@ namespace DiscImageChef.DiscImages
|
||||
imageInfo.Sectors = ddtHeader.entries;
|
||||
shift = ddtHeader.shift;
|
||||
|
||||
// Check for DDT compression
|
||||
switch(ddtHeader.compression)
|
||||
{
|
||||
case CompressionType.Lzma:
|
||||
@@ -436,6 +484,7 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
foundUserDataDdt = true;
|
||||
break;
|
||||
// Logical geometry block. It doesn't have a CRC coz, well, it's not so important
|
||||
case BlockType.GeometryBlock:
|
||||
geometryBlock = new GeometryBlock();
|
||||
structureBytes = new byte[Marshal.SizeOf(geometryBlock)];
|
||||
@@ -456,6 +505,7 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
|
||||
break;
|
||||
// Metadata block
|
||||
case BlockType.MetadataBlock:
|
||||
MetadataBlock metadataBlock = new MetadataBlock();
|
||||
structureBytes = new byte[Marshal.SizeOf(metadataBlock)];
|
||||
@@ -626,6 +676,7 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
|
||||
break;
|
||||
// Optical disc tracks block
|
||||
case BlockType.TracksBlock:
|
||||
TracksHeader tracksHeader = new TracksHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(tracksHeader)];
|
||||
@@ -719,6 +770,7 @@ namespace DiscImageChef.DiscImages
|
||||
currentCacheSize = 0;
|
||||
if(!inMemoryDdt) ddtEntryCache = new Dictionary<ulong, ulong>();
|
||||
|
||||
// Initialize tracks, sessions and partitions
|
||||
if(imageInfo.XmlMediaType == XmlMediaType.OpticalDisc)
|
||||
{
|
||||
if(Tracks == null || Tracks.Count == 0)
|
||||
@@ -827,6 +879,7 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
byte[] sector;
|
||||
|
||||
// Check if block is cached
|
||||
if(blockCache.TryGetValue(blockOffset, out byte[] block) &&
|
||||
blockHeaderCache.TryGetValue(blockOffset, out BlockHeader blockHeader))
|
||||
{
|
||||
@@ -835,6 +888,7 @@ namespace DiscImageChef.DiscImages
|
||||
return sector;
|
||||
}
|
||||
|
||||
// Read block header
|
||||
imageStream.Position = (long)blockOffset;
|
||||
blockHeader = new BlockHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(blockHeader)];
|
||||
@@ -844,6 +898,7 @@ namespace DiscImageChef.DiscImages
|
||||
blockHeader = (BlockHeader)Marshal.PtrToStructure(structurePointer, typeof(BlockHeader));
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
|
||||
// Decompress block
|
||||
switch(blockHeader.compression)
|
||||
{
|
||||
case CompressionType.None:
|
||||
@@ -879,6 +934,7 @@ namespace DiscImageChef.DiscImages
|
||||
ImageNotSupportedException($"Found unsupported compression algorithm {(ushort)blockHeader.compression}");
|
||||
}
|
||||
|
||||
// Check if cache needs to be emptied
|
||||
if(currentCacheSize + blockHeader.length >= MAX_CACHE_SIZE)
|
||||
{
|
||||
currentCacheSize = 0;
|
||||
@@ -886,6 +942,7 @@ namespace DiscImageChef.DiscImages
|
||||
blockCache = new Dictionary<ulong, byte[]>();
|
||||
}
|
||||
|
||||
// Add block to cache
|
||||
currentCacheSize += blockHeader.length;
|
||||
blockHeaderCache.Add(blockOffset, blockHeader);
|
||||
blockCache.Add(blockOffset, block);
|
||||
@@ -1070,6 +1127,7 @@ namespace DiscImageChef.DiscImages
|
||||
dataSource = sectorPrefix;
|
||||
break;
|
||||
}
|
||||
// These could be implemented
|
||||
case SectorTagType.CdSectorEcc:
|
||||
case SectorTagType.CdSectorEccP:
|
||||
case SectorTagType.CdSectorEccQ:
|
||||
@@ -1243,8 +1301,10 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
switch(trk.TrackType)
|
||||
{
|
||||
// These types only contain user data
|
||||
case TrackType.Audio:
|
||||
case TrackType.Data: return ReadSectors(sectorAddress, length);
|
||||
// Join prefix (sync, header) with user data with suffix (edc, ecc p, ecc q)
|
||||
case TrackType.CdMode1:
|
||||
if(sectorPrefix == null || sectorSuffix == null) return ReadSectors(sectorAddress, length);
|
||||
|
||||
@@ -1261,6 +1321,7 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
|
||||
return sectors;
|
||||
// Join prefix (sync, header) with user data
|
||||
case TrackType.CdMode2Formless:
|
||||
case TrackType.CdMode2Form1:
|
||||
case TrackType.CdMode2Form2:
|
||||
@@ -1283,6 +1344,7 @@ namespace DiscImageChef.DiscImages
|
||||
case XmlMediaType.BlockMedia:
|
||||
switch(imageInfo.MediaType)
|
||||
{
|
||||
// Join user data with tags
|
||||
case MediaType.AppleFileWare:
|
||||
case MediaType.AppleProfile:
|
||||
case MediaType.AppleSonySS:
|
||||
@@ -1376,6 +1438,7 @@ namespace DiscImageChef.DiscImages
|
||||
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);
|
||||
@@ -1413,6 +1476,7 @@ namespace DiscImageChef.DiscImages
|
||||
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>();
|
||||
@@ -1452,6 +1516,7 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
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;
|
||||
@@ -1502,6 +1567,7 @@ namespace DiscImageChef.DiscImages
|
||||
vrIndex.Add(entry);
|
||||
}
|
||||
|
||||
// Read up to 1MiB at a time for verification
|
||||
const int VERIFY_SIZE = 1024 * 1024;
|
||||
|
||||
foreach(IndexEntry entry in vrIndex)
|
||||
@@ -1691,12 +1757,14 @@ namespace DiscImageChef.DiscImages
|
||||
maxDdtSize = 256;
|
||||
}
|
||||
|
||||
// This really, cannot happen
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate shift
|
||||
shift = 0;
|
||||
uint oldSectorsPerBlock = sectorsPerBlock;
|
||||
while(sectorsPerBlock > 1)
|
||||
@@ -1723,6 +1791,7 @@ namespace DiscImageChef.DiscImages
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if appending to an existing image
|
||||
if(imageStream.Length > Marshal.SizeOf(typeof(DicHeader)))
|
||||
{
|
||||
header = new DicHeader();
|
||||
@@ -1772,6 +1841,7 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
index = new List<IndexEntry>();
|
||||
|
||||
// If there exists an index, we are appending, so read index
|
||||
if(header.indexOffset > 0)
|
||||
{
|
||||
imageStream.Position = (long)header.indexOffset;
|
||||
@@ -1977,11 +2047,15 @@ namespace DiscImageChef.DiscImages
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Creating new
|
||||
else
|
||||
{
|
||||
// Checking that DDT is smaller than requested size
|
||||
inMemoryDdt = sectors <= maxDdtSize * 1024 * 1024 / sizeof(ulong);
|
||||
|
||||
// If in memory, easy
|
||||
if(inMemoryDdt) userDataDdt = new ulong[sectors];
|
||||
// If not, create the block, add to index, and enlarge the file to allow the DDT to exist on-disk
|
||||
else
|
||||
{
|
||||
outMemoryDdtPosition = imageStream.Position;
|
||||
@@ -2019,6 +2093,7 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin", "In memory DDT?: {0}", inMemoryDdt);
|
||||
|
||||
// Initialize tables
|
||||
imageStream.Seek(0, SeekOrigin.End);
|
||||
mediaTags = new Dictionary<MediaTagType, byte[]>();
|
||||
checksumProvider = SHA256.Create();
|
||||
@@ -2026,6 +2101,7 @@ namespace DiscImageChef.DiscImages
|
||||
trackIsrcs = new Dictionary<byte, string>();
|
||||
trackFlags = new Dictionary<byte, byte>();
|
||||
|
||||
// Initialize compressors properties (all maxed)
|
||||
lzmaEncoderProperties = new LzmaEncoderProperties(true, (int)dictionary, 273);
|
||||
flakeWriterSettings = new FlakeWriterSettings
|
||||
{
|
||||
@@ -2049,6 +2125,7 @@ namespace DiscImageChef.DiscImages
|
||||
AllowNonSubset = true
|
||||
};
|
||||
|
||||
// Check if FLAKE's block size is bigger than what we want
|
||||
if(flakeWriterSettings.BlockSize > MAX_FLAKE_BLOCK) flakeWriterSettings.BlockSize = MAX_FLAKE_BLOCK;
|
||||
if(flakeWriterSettings.BlockSize < MIN_FLAKE_BLOCK) flakeWriterSettings.BlockSize = MIN_FLAKE_BLOCK;
|
||||
FlakeWriter.Vendor = "DiscImageChef";
|
||||
@@ -2099,6 +2176,7 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
Track trk = new Track();
|
||||
|
||||
// If optical disc check track
|
||||
if(imageInfo.XmlMediaType == XmlMediaType.OpticalDisc)
|
||||
{
|
||||
trk = Tracks.FirstOrDefault(t => sectorAddress >= t.TrackStartSector &&
|
||||
@@ -2110,10 +2188,12 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
// Close current block first
|
||||
if(blockStream != null &&
|
||||
// When sector siz changes
|
||||
(currentBlockHeader.sectorSize != data.Length ||
|
||||
// When block if filled
|
||||
currentBlockOffset == 1 << shift ||
|
||||
currentBlockHeader.compression == CompressionType.Flac &&
|
||||
trk.TrackType != TrackType.Audio))
|
||||
// When we change to/from CompactDisc audio
|
||||
currentBlockHeader.compression == CompressionType.Flac && trk.TrackType != TrackType.Audio))
|
||||
{
|
||||
currentBlockHeader.length = currentBlockOffset * currentBlockHeader.sectorSize;
|
||||
currentBlockHeader.crc64 = BitConverter.ToUInt64(crc64.Final(), 0);
|
||||
@@ -2143,8 +2223,8 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
else
|
||||
{
|
||||
lzmaProperties = compressedBlockStream.Properties;
|
||||
compressedBlockStream.Close();
|
||||
lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
cmpCrc64Context.Update(lzmaProperties);
|
||||
}
|
||||
|
||||
@@ -2191,9 +2271,8 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
if(currentBlockHeader.compression == CompressionType.Flac)
|
||||
flakeWriter =
|
||||
new FlakeWriter("", blockStream, flakeWriterSettings) {DoSeekTable = false};
|
||||
else compressedBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
flakeWriter = new FlakeWriter("", blockStream, flakeWriterSettings) {DoSeekTable = false};
|
||||
else lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
crc64 = new Crc64Context();
|
||||
crc64.Init();
|
||||
}
|
||||
@@ -2205,7 +2284,7 @@ namespace DiscImageChef.DiscImages
|
||||
AudioBuffer audioBuffer = new AudioBuffer(AudioPCMConfig.RedBook, data, SAMPLES_PER_SECTOR);
|
||||
flakeWriter.Write(audioBuffer);
|
||||
}
|
||||
else compressedBlockStream.Write(data, 0, data.Length);
|
||||
else lzmaBlockStream.Write(data, 0, data.Length);
|
||||
|
||||
SetDdtEntry(sectorAddress, ddtEntry);
|
||||
crc64.Update(data);
|
||||
@@ -2271,6 +2350,7 @@ namespace DiscImageChef.DiscImages
|
||||
return false;
|
||||
}
|
||||
|
||||
// Split raw cd sector data in prefix (sync, header), user data and suffix (edc, ecc p, ecc q)
|
||||
switch(track.TrackType)
|
||||
{
|
||||
case TrackType.Audio:
|
||||
@@ -2298,6 +2378,7 @@ namespace DiscImageChef.DiscImages
|
||||
case XmlMediaType.BlockMedia:
|
||||
switch(imageInfo.MediaType)
|
||||
{
|
||||
// Split user data from Apple tags
|
||||
case MediaType.AppleFileWare:
|
||||
case MediaType.AppleProfile:
|
||||
case MediaType.AppleSonyDS:
|
||||
@@ -2528,8 +2609,8 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
else
|
||||
{
|
||||
lzmaProperties = compressedBlockStream.Properties;
|
||||
compressedBlockStream.Close();
|
||||
lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
cmpCrc64Context.Update(lzmaProperties);
|
||||
}
|
||||
|
||||
@@ -2560,6 +2641,7 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
IndexEntry idxEntry;
|
||||
|
||||
// Write media tag blocks
|
||||
foreach(KeyValuePair<MediaTagType, byte[]> mediaTag in mediaTags)
|
||||
{
|
||||
DataType dataType = GetDataTypeForMediaTag(mediaTag.Key);
|
||||
@@ -2584,10 +2666,10 @@ namespace DiscImageChef.DiscImages
|
||||
};
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
compressedBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
compressedBlockStream.Write(mediaTag.Value, 0, mediaTag.Value.Length);
|
||||
byte[] lzmaProperties = compressedBlockStream.Properties;
|
||||
compressedBlockStream.Close();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
lzmaBlockStream.Write(mediaTag.Value, 0, mediaTag.Value.Length);
|
||||
byte[] lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
byte[] tagData;
|
||||
|
||||
// Not compressible
|
||||
@@ -2607,7 +2689,7 @@ namespace DiscImageChef.DiscImages
|
||||
tagBlock.compression = CompressionType.Lzma;
|
||||
}
|
||||
|
||||
compressedBlockStream = null;
|
||||
lzmaBlockStream = null;
|
||||
blockStream = null;
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(tagBlock));
|
||||
@@ -2625,6 +2707,7 @@ namespace DiscImageChef.DiscImages
|
||||
index.Add(idxEntry);
|
||||
}
|
||||
|
||||
// If we have set the geometry block, write it
|
||||
if(geometryBlock.identifier == BlockType.GeometryBlock)
|
||||
{
|
||||
idxEntry = new IndexEntry
|
||||
@@ -2649,6 +2732,7 @@ namespace DiscImageChef.DiscImages
|
||||
index.Add(idxEntry);
|
||||
}
|
||||
|
||||
// If the DDT is in-memory, write it to disk
|
||||
if(inMemoryDdt)
|
||||
{
|
||||
idxEntry = new IndexEntry
|
||||
@@ -2672,18 +2756,18 @@ namespace DiscImageChef.DiscImages
|
||||
};
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
compressedBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
crc64 = new Crc64Context();
|
||||
crc64.Init();
|
||||
for(ulong i = 0; i < (ulong)userDataDdt.LongLength; i++)
|
||||
{
|
||||
byte[] ddtEntry = BitConverter.GetBytes(userDataDdt[i]);
|
||||
crc64.Update(ddtEntry);
|
||||
compressedBlockStream.Write(ddtEntry, 0, ddtEntry.Length);
|
||||
lzmaBlockStream.Write(ddtEntry, 0, ddtEntry.Length);
|
||||
}
|
||||
|
||||
byte[] lzmaProperties = compressedBlockStream.Properties;
|
||||
compressedBlockStream.Close();
|
||||
byte[] lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
ddtHeader.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
Crc64Context cmpCrc64Context = new Crc64Context();
|
||||
cmpCrc64Context.Init();
|
||||
@@ -2701,13 +2785,14 @@ namespace DiscImageChef.DiscImages
|
||||
imageStream.Write(lzmaProperties, 0, lzmaProperties.Length);
|
||||
imageStream.Write(blockStream.ToArray(), 0, (int)blockStream.Length);
|
||||
blockStream = null;
|
||||
compressedBlockStream = null;
|
||||
lzmaBlockStream = null;
|
||||
|
||||
index.RemoveAll(t => t.blockType == BlockType.DeDuplicationTable && t.dataType == DataType.UserData);
|
||||
|
||||
index.Add(idxEntry);
|
||||
}
|
||||
|
||||
// Write the sector prefix, suffix and subchannels if present
|
||||
switch(imageInfo.XmlMediaType)
|
||||
{
|
||||
case XmlMediaType.OpticalDisc when Tracks != null && Tracks.Count > 0:
|
||||
@@ -2734,17 +2819,17 @@ namespace DiscImageChef.DiscImages
|
||||
};
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
compressedBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
compressedBlockStream.Write(sectorPrefix, 0, sectorPrefix.Length);
|
||||
byte[] lzmaProperties = compressedBlockStream.Properties;
|
||||
compressedBlockStream.Close();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
lzmaBlockStream.Write(sectorPrefix, 0, sectorPrefix.Length);
|
||||
byte[] lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
|
||||
Crc64Context.Data(blockStream.ToArray(), out blockCrc);
|
||||
prefixBlock.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
prefixBlock.cmpCrc64 = BitConverter.ToUInt64(blockCrc, 0);
|
||||
prefixBlock.compression = CompressionType.Lzma;
|
||||
|
||||
compressedBlockStream = null;
|
||||
lzmaBlockStream = null;
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(prefixBlock));
|
||||
structureBytes = new byte[Marshal.SizeOf(prefixBlock)];
|
||||
@@ -2782,17 +2867,17 @@ namespace DiscImageChef.DiscImages
|
||||
};
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
compressedBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
compressedBlockStream.Write(sectorSuffix, 0, sectorSuffix.Length);
|
||||
lzmaProperties = compressedBlockStream.Properties;
|
||||
compressedBlockStream.Close();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
lzmaBlockStream.Write(sectorSuffix, 0, sectorSuffix.Length);
|
||||
lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
|
||||
Crc64Context.Data(blockStream.ToArray(), out blockCrc);
|
||||
prefixBlock.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
prefixBlock.cmpCrc64 = BitConverter.ToUInt64(blockCrc, 0);
|
||||
prefixBlock.compression = CompressionType.Lzma;
|
||||
|
||||
compressedBlockStream = null;
|
||||
lzmaBlockStream = null;
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(prefixBlock));
|
||||
structureBytes = new byte[Marshal.SizeOf(prefixBlock)];
|
||||
@@ -2834,17 +2919,17 @@ namespace DiscImageChef.DiscImages
|
||||
};
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
compressedBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
compressedBlockStream.Write(sectorSubchannel, 0, sectorSubchannel.Length);
|
||||
byte[] lzmaProperties = compressedBlockStream.Properties;
|
||||
compressedBlockStream.Close();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
lzmaBlockStream.Write(sectorSubchannel, 0, sectorSubchannel.Length);
|
||||
byte[] lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
|
||||
Crc64Context.Data(blockStream.ToArray(), out blockCrc);
|
||||
subchannelBlock.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
subchannelBlock.cmpCrc64 = BitConverter.ToUInt64(blockCrc, 0);
|
||||
subchannelBlock.compression = CompressionType.Lzma;
|
||||
|
||||
compressedBlockStream = null;
|
||||
lzmaBlockStream = null;
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(subchannelBlock));
|
||||
structureBytes = new byte[Marshal.SizeOf(subchannelBlock)];
|
||||
@@ -2885,6 +2970,7 @@ namespace DiscImageChef.DiscImages
|
||||
});
|
||||
}
|
||||
|
||||
// If there are tracks build the tracks block
|
||||
if(trackEntries.Count > 0)
|
||||
{
|
||||
blockStream = new MemoryStream();
|
||||
@@ -2977,17 +3063,17 @@ namespace DiscImageChef.DiscImages
|
||||
};
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
compressedBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
compressedBlockStream.Write(sectorSubchannel, 0, sectorSubchannel.Length);
|
||||
byte[] lzmaProperties = compressedBlockStream.Properties;
|
||||
compressedBlockStream.Close();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
lzmaBlockStream.Write(sectorSubchannel, 0, sectorSubchannel.Length);
|
||||
byte[] lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
|
||||
Crc64Context.Data(blockStream.ToArray(), out blockCrc);
|
||||
subchannelBlock.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
subchannelBlock.cmpCrc64 = BitConverter.ToUInt64(blockCrc, 0);
|
||||
subchannelBlock.compression = CompressionType.Lzma;
|
||||
|
||||
compressedBlockStream = null;
|
||||
lzmaBlockStream = null;
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(subchannelBlock));
|
||||
structureBytes = new byte[Marshal.SizeOf(subchannelBlock)];
|
||||
@@ -3008,6 +3094,7 @@ namespace DiscImageChef.DiscImages
|
||||
break;
|
||||
}
|
||||
|
||||
// Write metadata if present
|
||||
SetMetadataFromTags();
|
||||
MetadataBlock metadataBlock = new MetadataBlock();
|
||||
blockStream = new MemoryStream();
|
||||
@@ -3141,6 +3228,7 @@ namespace DiscImageChef.DiscImages
|
||||
blockStream.Write(new byte[] {0, 0}, 0, 2);
|
||||
}
|
||||
|
||||
// Check if we set up any metadata earlier, then write its block
|
||||
if(metadataBlock.identifier == BlockType.MetadataBlock)
|
||||
{
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Writing metadata to position {0}",
|
||||
@@ -3170,6 +3258,7 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
|
||||
// Write index to memory
|
||||
foreach(IndexEntry entry in index)
|
||||
{
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(entry));
|
||||
@@ -3189,6 +3278,7 @@ namespace DiscImageChef.DiscImages
|
||||
crc64 = BitConverter.ToUInt64(idxCrc, 0)
|
||||
};
|
||||
|
||||
// Write index to disk
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(idxHeader));
|
||||
structureBytes = new byte[Marshal.SizeOf(idxHeader)];
|
||||
Marshal.StructureToPtr(idxHeader, structurePointer, true);
|
||||
@@ -3381,8 +3471,12 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
}
|
||||
|
||||
/// <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);
|
||||
@@ -3397,6 +3491,7 @@ namespace DiscImageChef.DiscImages
|
||||
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);
|
||||
@@ -3411,6 +3506,7 @@ namespace DiscImageChef.DiscImages
|
||||
imageInfo.DriveSerialNumber = $"{decoded.ProductSerialNumber}";
|
||||
}
|
||||
|
||||
// Search for SCSI INQUIRY
|
||||
if(mediaTags.TryGetValue(MediaTagType.SCSI_INQUIRY, out byte[] scsiInquiry))
|
||||
{
|
||||
Inquiry.SCSIInquiry? nullableInquiry = Inquiry.Decode(scsiInquiry);
|
||||
@@ -3428,6 +3524,7 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
}
|
||||
|
||||
// Search for ATA or ATAPI IDENTIFY
|
||||
if(!mediaTags.TryGetValue(MediaTagType.ATA_IDENTIFY, out byte[] ataIdentify) &&
|
||||
!mediaTags.TryGetValue(MediaTagType.ATAPI_IDENTIFY, out ataIdentify)) return;
|
||||
|
||||
@@ -3456,6 +3553,7 @@ namespace DiscImageChef.DiscImages
|
||||
imageInfo.DriveSerialNumber = identify.SerialNumber;
|
||||
}
|
||||
|
||||
// Get the CICM XML media type from DIC media type
|
||||
static XmlMediaType GetXmlMediaType(MediaType type)
|
||||
{
|
||||
switch(type)
|
||||
@@ -3542,6 +3640,7 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
}
|
||||
|
||||
// Gets a DDT entry
|
||||
ulong GetDdtEntry(ulong sectorAddress)
|
||||
{
|
||||
if(inMemoryDdt) return userDataDdt[sectorAddress];
|
||||
@@ -3562,6 +3661,7 @@ namespace DiscImageChef.DiscImages
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Sets a DDT entry
|
||||
void SetDdtEntry(ulong sectorAddress, ulong pointer)
|
||||
{
|
||||
if(inMemoryDdt)
|
||||
@@ -3577,6 +3677,7 @@ namespace DiscImageChef.DiscImages
|
||||
imageStream.Position = oldPosition;
|
||||
}
|
||||
|
||||
// Converts between image data type and dic media tag type
|
||||
static MediaTagType GetMediaTagTypeForDataType(DataType type)
|
||||
{
|
||||
switch(type)
|
||||
@@ -3652,6 +3753,7 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
}
|
||||
|
||||
// Converts between dic media tag type and image data type
|
||||
static DataType GetDataTypeForMediaTag(MediaTagType tag)
|
||||
{
|
||||
switch(tag)
|
||||
@@ -3728,100 +3830,201 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>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>List of known blocks types</summary>
|
||||
enum BlockType : uint
|
||||
{
|
||||
DataBlock = 0x484B4C42,
|
||||
DeDuplicationTable = 0x48544444,
|
||||
Index = 0x48584449,
|
||||
/// <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,
|
||||
MetadataBlock = 0x5444545D,
|
||||
TracksBlock = 0x534B5254
|
||||
/// <summary>Block containing metadata</summary>
|
||||
MetadataBlock = 0x4154454D,
|
||||
/// <summary>Block containing optical disc tracks</summary>
|
||||
TracksBlock = 0x534B5254,
|
||||
/// <summary>TODO: Block containing CICM XML metadata</summary>
|
||||
CicmBlock = 0x4D434943,
|
||||
/// <summary>TODO: 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>TODO: 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
|
||||
}
|
||||
|
||||
/// <summary>Header, at start of file</summary>
|
||||
@@ -3845,13 +4048,9 @@ namespace DiscImageChef.DiscImages
|
||||
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>
|
||||
/// <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>
|
||||
/// <summary>Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image last written time</summary>
|
||||
public long lastWrittenTime;
|
||||
}
|
||||
|
||||
@@ -3998,6 +4197,7 @@ namespace DiscImageChef.DiscImages
|
||||
public uint driveFirmwareRevisionLength;
|
||||
}
|
||||
|
||||
/// <summary>Contains list of optical disc tracks</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TracksHeader
|
||||
{
|
||||
@@ -4009,17 +4209,26 @@ namespace DiscImageChef.DiscImages
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
//
|
||||
// File: dicformat.bt
|
||||
// Authors: Natalia Portillo
|
||||
// Version: 0.0
|
||||
// Version: 1.0
|
||||
// Purpose: DiscImageChef format
|
||||
// Category: Misc
|
||||
// File Mask: *.dicf
|
||||
// ID Bytes: 44 49 43 44 44 46 4D 54 // DICDDFMT
|
||||
// ID Bytes: 44 49 43 4D 46 52 4D 54 // DICMFRMT
|
||||
// History:
|
||||
// 0.0 2018-01-25 Natalia Portillo: Initial release
|
||||
// 1.0 2018-01-26 Natalia Portillo: Initial release
|
||||
//------------------------------------------------
|
||||
|
||||
#define DIC_MAGIC 0x544D464444434944
|
||||
#define DIC_MAGIC 0x544D52464D434944
|
||||
|
||||
enum <uint> MediaType
|
||||
{
|
||||
@@ -620,12 +620,19 @@ enum <ushort> DataType
|
||||
|
||||
enum <uint> BlockType
|
||||
{
|
||||
DataBlock = 0x484B4C42,
|
||||
DeDuplicationTable = 0x48544444,
|
||||
Index = 0x48584449,
|
||||
DataBlock = 0x4B4C4244,
|
||||
DeDuplicationTable = 0X2A544444,
|
||||
Index = 0X58444E49,
|
||||
GeometryBlock = 0x4D4F4547,
|
||||
MetadataBlock = 0x5444545D,
|
||||
TracksBlock = 0x534B5254
|
||||
MetadataBlock = 0x4154454D,
|
||||
TracksBlock = 0x534B5254,
|
||||
CicmBlock = 0x4D434943,
|
||||
ChecksumBlock = 0x4D534B43,
|
||||
DataPositionMeasurementBlock = 0x2A4D5044,
|
||||
SnapshotBlock = 0x50414E53,
|
||||
ParentBlock = 0x50524E54,
|
||||
DumpHardwareBlock = 0x2A504D44,
|
||||
TapeFileBlock = 0x454C4654
|
||||
};
|
||||
|
||||
enum <byte> TrackType
|
||||
@@ -767,16 +774,16 @@ for(i = 0; i < index.entries; i++)
|
||||
FSeek(index.items[i].offset);
|
||||
switch(index.items[i].blockType)
|
||||
{
|
||||
case 0x484B4C42:
|
||||
case 0x4B4C4244:
|
||||
BlockHeader dataBlock;
|
||||
break;
|
||||
case 0x48544444:
|
||||
case 0x2A544444:
|
||||
DdtHeader deduplicationTable;
|
||||
break;
|
||||
case 0x4D4F4547:
|
||||
GeometryBlock geometry;
|
||||
break;
|
||||
case 0x5444545D:
|
||||
case 0x4154454D:
|
||||
MetadataBlock metadata;
|
||||
if(metadata.creatorOffset > 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user