mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Add support in dicformat for skipping storing CD prefixes and suffixes that are correct.
This commit is contained in:
1
.idea/.idea.DiscImageChef/.idea/contentModel.xml
generated
1
.idea/.idea.DiscImageChef/.idea/contentModel.xml
generated
@@ -684,6 +684,7 @@
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="DiscImageChef" t="Include">
|
||||
<e p="CdEcc.cs" t="Include" />
|
||||
<e p="ClauniaSubchannelTransform.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="DiscImageChef.cs" t="Include" />
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
<Compile Include="DiscFerret\Read.cs" />
|
||||
<Compile Include="DiscFerret\Structs.cs" />
|
||||
<Compile Include="DiscFerret\Unsupported.cs" />
|
||||
<Compile Include="DiscImageChef\CdEcc.cs" />
|
||||
<Compile Include="DiscImageChef\ClauniaSubchannelTransform.cs" />
|
||||
<Compile Include="DiscImageChef\Constants.cs" />
|
||||
<Compile Include="DiscImageChef\DiscImageChef.cs" />
|
||||
|
||||
123
DiscImageChef.DiscImages/DiscImageChef/CdEcc.cs
Normal file
123
DiscImageChef.DiscImages/DiscImageChef/CdEcc.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ClauniaSubchannelTransform.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains the CD ECC algorithm.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ECC algorithm from ECM(c) 2002-2011 Neill Corlett
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class DiscImageChef
|
||||
{
|
||||
byte[] eccBTable;
|
||||
byte[] eccFTable;
|
||||
uint[] edcTable;
|
||||
|
||||
void EccInit()
|
||||
{
|
||||
eccFTable = new byte[256];
|
||||
eccBTable = new byte[256];
|
||||
edcTable = new uint[256];
|
||||
|
||||
for(uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint edc = i;
|
||||
uint j = (uint)((i << 1) ^ ((i & 0x80) == 0x80 ? 0x11D : 0));
|
||||
eccFTable[i] = (byte)j;
|
||||
eccBTable[i ^ j] = (byte)i;
|
||||
for(j = 0; j < 8; j++) edc = (edc >> 1) ^ ((edc & 1) > 0 ? 0xD8018001 : 0);
|
||||
edcTable[i] = edc;
|
||||
}
|
||||
}
|
||||
|
||||
bool SuffixIsCorrect(byte[] channel)
|
||||
{
|
||||
if(channel[0x814] != 0x00 || // reserved (8 bytes)
|
||||
channel[0x815] != 0x00 || channel[0x816] != 0x00 || channel[0x817] != 0x00 || channel[0x818] != 0x00 ||
|
||||
channel[0x819] != 0x00 || channel[0x81A] != 0x00 || channel[0x81B] != 0x00) return false;
|
||||
|
||||
byte[] address = new byte[4];
|
||||
byte[] data = new byte[2060];
|
||||
byte[] data2 = new byte[2232];
|
||||
byte[] eccP = new byte[172];
|
||||
byte[] eccQ = new byte[104];
|
||||
|
||||
Array.Copy(channel, 0x0C, address, 0, 4);
|
||||
Array.Copy(channel, 0x10, data, 0, 2060);
|
||||
Array.Copy(channel, 0x10, data2, 0, 2232);
|
||||
Array.Copy(channel, 0x81C, eccP, 0, 172);
|
||||
Array.Copy(channel, 0x8C8, eccQ, 0, 104);
|
||||
|
||||
bool correctEccP = CheckEcc(ref address, ref data, 86, 24, 2, 86, ref eccP);
|
||||
if(!correctEccP) return false;
|
||||
|
||||
bool correctEccQ = CheckEcc(ref address, ref data2, 52, 43, 86, 88, ref eccQ);
|
||||
if(!correctEccQ) return false;
|
||||
|
||||
uint storedEdc = BitConverter.ToUInt32(channel, 0x810);
|
||||
uint edc = 0;
|
||||
int size = 0x810;
|
||||
int pos = 0;
|
||||
for(; size > 0; size--) edc = (edc >> 8) ^ edcTable[(edc ^ channel[pos++]) & 0xFF];
|
||||
uint calculatedEdc = edc;
|
||||
|
||||
return calculatedEdc == storedEdc;
|
||||
}
|
||||
|
||||
bool CheckEcc(ref byte[] address, ref byte[] data, uint majorCount, uint minorCount, uint majorMult,
|
||||
uint minorInc, ref byte[] ecc)
|
||||
{
|
||||
uint size = majorCount * minorCount;
|
||||
uint major;
|
||||
for(major = 0; major < majorCount; major++)
|
||||
{
|
||||
uint idx = (major >> 1) * majorMult + (major & 1);
|
||||
byte eccA = 0;
|
||||
byte eccB = 0;
|
||||
uint minor;
|
||||
for(minor = 0; minor < minorCount; minor++)
|
||||
{
|
||||
byte temp = idx < 4 ? address[idx] : data[idx - 4];
|
||||
idx += minorInc;
|
||||
if(idx >= size) idx -= size;
|
||||
eccA ^= temp;
|
||||
eccB ^= temp;
|
||||
eccA = eccFTable[eccA];
|
||||
}
|
||||
|
||||
eccA = eccBTable[eccFTable[eccA] ^ eccB];
|
||||
if(ecc[major] != eccA || ecc[major + majorCount] != (eccA ^ eccB)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,5 +56,9 @@ namespace DiscImageChef.DiscImages
|
||||
/// smaller than 256.
|
||||
/// </summary>
|
||||
const int MIN_FLAKE_BLOCK = 256;
|
||||
/// <summary>This mask is to check for flags in CompactDisc suffix/prefix DDT</summary>
|
||||
const uint CD_XFIX_MASK = 0xFF000000;
|
||||
/// <summary>This mask is to check for position in CompactDisc suffix/prefix deduplicated block</summary>
|
||||
const uint CD_DFIX_MASK = 0x00FFFFFF;
|
||||
}
|
||||
}
|
||||
@@ -136,10 +136,14 @@ namespace DiscImageChef.DiscImages
|
||||
bool rewinded;
|
||||
/// <summary>Cache for data that prefixes the user data on a sector (e.g. sync).</summary>
|
||||
byte[] sectorPrefix;
|
||||
uint[] sectorPrefixDdt;
|
||||
MemoryStream sectorPrefixMs;
|
||||
/// <summary>Cache for data that goes side by side with user data (e.g. CompactDisc subchannel).</summary>
|
||||
byte[] sectorSubchannel;
|
||||
/// <summary>Cache for data that suffixes the user data on a sector (e.g. edc, ecc).</summary>
|
||||
byte[] sectorSuffix;
|
||||
uint[] sectorSuffixDdt;
|
||||
MemoryStream sectorSuffixMs;
|
||||
Sha1Context sha1Provider;
|
||||
Sha256Context sha256Provider;
|
||||
/// <summary>Shift for calculating number of sectors in a block.</summary>
|
||||
|
||||
@@ -201,7 +201,11 @@ namespace DiscImageChef.DiscImages
|
||||
/// <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
|
||||
CompactDiscMediaCatalogueNumber = 75,
|
||||
/// <summary>CompactDisc sector prefix (sync, header), only incorrect stored</summary>
|
||||
CdSectorPrefixCorrected = 76,
|
||||
/// <summary>CompactDisc sector suffix (edc, ecc p, ecc q), only incorrect stored</summary>
|
||||
CdSectorSuffixCorrected = 77
|
||||
}
|
||||
|
||||
/// <summary>List of known blocks types</summary>
|
||||
@@ -243,5 +247,11 @@ namespace DiscImageChef.DiscImages
|
||||
Sha256 = 3,
|
||||
SpamSum = 4
|
||||
}
|
||||
|
||||
enum CdFixFlags : uint
|
||||
{
|
||||
NotDumped = 0x10000000,
|
||||
Correct = 0x20000000
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,14 +224,28 @@ namespace DiscImageChef.DiscImages
|
||||
switch(entry.dataType)
|
||||
{
|
||||
case DataType.CdSectorPrefix:
|
||||
sectorPrefix = data;
|
||||
case DataType.CdSectorPrefixCorrected:
|
||||
if(entry.dataType == DataType.CdSectorPrefixCorrected)
|
||||
{
|
||||
sectorPrefixMs = new MemoryStream();
|
||||
sectorPrefixMs.Write(data, 0, data.Length);
|
||||
}
|
||||
else sectorPrefix = data;
|
||||
|
||||
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSync))
|
||||
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync);
|
||||
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorHeader))
|
||||
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader);
|
||||
break;
|
||||
case DataType.CdSectorSuffix:
|
||||
sectorSuffix = data;
|
||||
case DataType.CdSectorSuffixCorrected:
|
||||
if(entry.dataType == DataType.CdSectorSuffixCorrected)
|
||||
{
|
||||
sectorSuffixMs = new MemoryStream();
|
||||
sectorSuffixMs.Write(data, 0, data.Length);
|
||||
}
|
||||
else sectorSuffix = data;
|
||||
|
||||
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSubHeader))
|
||||
imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubHeader);
|
||||
if(!imageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEcc))
|
||||
@@ -274,8 +288,8 @@ namespace DiscImageChef.DiscImages
|
||||
break;
|
||||
case BlockType.DeDuplicationTable:
|
||||
// Only user data deduplication tables are used right now
|
||||
if(entry.dataType != DataType.UserData) break;
|
||||
|
||||
if(entry.dataType == DataType.UserData)
|
||||
{
|
||||
DdtHeader ddtHeader = new DdtHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(ddtHeader)];
|
||||
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||
@@ -308,7 +322,8 @@ namespace DiscImageChef.DiscImages
|
||||
compressedDdtMs.Close();
|
||||
userDataDdt = new ulong[ddtHeader.entries];
|
||||
for(ulong i = 0; i < ddtHeader.entries; i++)
|
||||
userDataDdt[i] = BitConverter.ToUInt64(decompressedDdt, (int)(i * sizeof(ulong)));
|
||||
userDataDdt[i] =
|
||||
BitConverter.ToUInt64(decompressedDdt, (int)(i * sizeof(ulong)));
|
||||
DateTime ddtEnd = DateTime.UtcNow;
|
||||
inMemoryDdt = true;
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
@@ -325,6 +340,56 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
|
||||
foundUserDataDdt = true;
|
||||
}
|
||||
else if(entry.dataType == DataType.CdSectorPrefixCorrected ||
|
||||
entry.dataType == DataType.CdSectorSuffixCorrected)
|
||||
{
|
||||
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);
|
||||
imageInfo.ImageSize += ddtHeader.cmpLength;
|
||||
|
||||
if(ddtHeader.identifier != BlockType.DeDuplicationTable) break;
|
||||
|
||||
uint[] cdDdt = new uint[ddtHeader.entries];
|
||||
byte[] decompressedDdt = new byte[ddtHeader.length];
|
||||
|
||||
// Check for DDT compression
|
||||
switch(ddtHeader.compression)
|
||||
{
|
||||
case CompressionType.Lzma:
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Decompressing DDT...");
|
||||
DateTime ddtStart = DateTime.UtcNow;
|
||||
byte[] compressedDdt = new byte[ddtHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
byte[] lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
imageStream.Read(lzmaProperties, 0, LZMA_PROPERTIES_LENGTH);
|
||||
imageStream.Read(compressedDdt, 0, compressedDdt.Length);
|
||||
MemoryStream compressedDdtMs = new MemoryStream(compressedDdt);
|
||||
LzmaStream lzmaDdt = new LzmaStream(lzmaProperties, compressedDdtMs);
|
||||
lzmaDdt.Read(decompressedDdt, 0, (int)ddtHeader.length);
|
||||
lzmaDdt.Close();
|
||||
compressedDdtMs.Close();
|
||||
DateTime ddtEnd = DateTime.UtcNow;
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Took {0} seconds to decompress DDT",
|
||||
(ddtEnd - ddtStart).TotalSeconds);
|
||||
break;
|
||||
case CompressionType.None:
|
||||
imageStream.Read(decompressedDdt, 0, decompressedDdt.Length);
|
||||
break;
|
||||
default:
|
||||
throw new
|
||||
ImageNotSupportedException($"Found unsupported compression algorithm {(ushort)ddtHeader.compression}");
|
||||
}
|
||||
|
||||
for(ulong i = 0; i < ddtHeader.entries; i++)
|
||||
cdDdt[i] = BitConverter.ToUInt32(decompressedDdt, (int)(i * sizeof(uint)));
|
||||
}
|
||||
|
||||
break;
|
||||
// Logical geometry block. It doesn't have a CRC coz, well, it's not so important
|
||||
case BlockType.GeometryBlock:
|
||||
@@ -1234,7 +1299,8 @@ namespace DiscImageChef.DiscImages
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress),
|
||||
"Can't found track containing requested sector");
|
||||
|
||||
if(sectorSuffix == null || sectorPrefix == null) return ReadSector(sectorAddress);
|
||||
if((sectorSuffix == null || sectorPrefix == null) &&
|
||||
(sectorSuffixMs == null || sectorPrefixMs == null)) return ReadSector(sectorAddress);
|
||||
|
||||
byte[] sector = new byte[2352];
|
||||
byte[] data = ReadSector(sectorAddress);
|
||||
@@ -1244,9 +1310,17 @@ namespace DiscImageChef.DiscImages
|
||||
case TrackType.Audio:
|
||||
case TrackType.Data: return data;
|
||||
case TrackType.CdMode1:
|
||||
if(sectorPrefix != null)
|
||||
Array.Copy(sectorPrefix, (int)sectorAddress * 16, sector, 0, 16);
|
||||
Array.Copy(data, 0, sector, 16, 2048);
|
||||
else if(sectorPrefixMs != null) throw new NotImplementedException();
|
||||
else throw new InvalidProgramException("Should not have arrived here");
|
||||
|
||||
if(sectorSuffix != null)
|
||||
Array.Copy(sectorSuffix, (int)sectorAddress * 288, sector, 2064, 288);
|
||||
else if(sectorSuffixMs != null) throw new NotImplementedException();
|
||||
else throw new InvalidProgramException("Should not have arrived here");
|
||||
|
||||
Array.Copy(data, 0, sector, 16, 2048);
|
||||
return sector;
|
||||
case TrackType.CdMode2Formless:
|
||||
case TrackType.CdMode2Form1:
|
||||
|
||||
@@ -312,6 +312,8 @@ namespace DiscImageChef.DiscImages
|
||||
{
|
||||
case DataType.CdSectorPrefix:
|
||||
case DataType.CdSectorSuffix:
|
||||
case DataType.CdSectorPrefixCorrected:
|
||||
case DataType.CdSectorSuffixCorrected:
|
||||
case DataType.CdSectorSubchannel:
|
||||
case DataType.AppleProfileTag:
|
||||
case DataType.AppleSonyTag:
|
||||
@@ -394,6 +396,14 @@ namespace DiscImageChef.DiscImages
|
||||
case DataType.CdSectorSuffix:
|
||||
sectorSuffix = data;
|
||||
break;
|
||||
case DataType.CdSectorPrefixCorrected:
|
||||
sectorPrefixMs = new MemoryStream();
|
||||
sectorPrefixMs.Write(data, 0, data.Length);
|
||||
break;
|
||||
case DataType.CdSectorSuffixCorrected:
|
||||
sectorSuffixMs = new MemoryStream();
|
||||
sectorSuffixMs.Write(data, 0, data.Length);
|
||||
break;
|
||||
case DataType.CdSectorSubchannel:
|
||||
case DataType.AppleProfileTag:
|
||||
case DataType.AppleSonyTag:
|
||||
@@ -405,8 +415,8 @@ namespace DiscImageChef.DiscImages
|
||||
break;
|
||||
case BlockType.DeDuplicationTable:
|
||||
// Only user data deduplication tables are used right now
|
||||
if(entry.dataType != DataType.UserData) break;
|
||||
|
||||
if(entry.dataType == DataType.UserData)
|
||||
{
|
||||
DdtHeader ddtHeader = new DdtHeader();
|
||||
structureBytes = new byte[Marshal.SizeOf(ddtHeader)];
|
||||
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||
@@ -429,9 +439,11 @@ namespace DiscImageChef.DiscImages
|
||||
switch(ddtHeader.compression)
|
||||
{
|
||||
case CompressionType.Lzma:
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Decompressing DDT...");
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Decompressing DDT...");
|
||||
DateTime ddtStart = DateTime.UtcNow;
|
||||
byte[] compressedDdt = new byte[ddtHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
byte[] compressedDdt =
|
||||
new byte[ddtHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
byte[] lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
imageStream.Read(lzmaProperties, 0, LZMA_PROPERTIES_LENGTH);
|
||||
imageStream.Read(compressedDdt, 0, compressedDdt.Length);
|
||||
@@ -461,6 +473,73 @@ namespace DiscImageChef.DiscImages
|
||||
}
|
||||
|
||||
foundUserDataDdt = true;
|
||||
}
|
||||
else if(entry.dataType == DataType.CdSectorPrefixCorrected ||
|
||||
entry.dataType == DataType.CdSectorSuffixCorrected)
|
||||
{
|
||||
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);
|
||||
|
||||
if(ddtHeader.identifier != BlockType.DeDuplicationTable) break;
|
||||
|
||||
if(ddtHeader.entries != imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage =
|
||||
$"Trying to write a media with {imageInfo.Sectors} sectors to an image with {ddtHeader.entries} sectors, not continuing...";
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] decompressedDdt = new byte[ddtHeader.length];
|
||||
uint[] cdDdt = new uint[ddtHeader.entries];
|
||||
|
||||
switch(ddtHeader.compression)
|
||||
{
|
||||
case CompressionType.Lzma:
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Decompressing DDT...");
|
||||
DateTime ddtStart = DateTime.UtcNow;
|
||||
byte[] compressedDdt =
|
||||
new byte[ddtHeader.cmpLength - LZMA_PROPERTIES_LENGTH];
|
||||
byte[] lzmaProperties = new byte[LZMA_PROPERTIES_LENGTH];
|
||||
imageStream.Read(lzmaProperties, 0, LZMA_PROPERTIES_LENGTH);
|
||||
imageStream.Read(compressedDdt, 0, compressedDdt.Length);
|
||||
MemoryStream compressedDdtMs = new MemoryStream(compressedDdt);
|
||||
LzmaStream lzmaDdt = new LzmaStream(lzmaProperties, compressedDdtMs);
|
||||
lzmaDdt.Read(decompressedDdt, 0, (int)ddtHeader.length);
|
||||
lzmaDdt.Close();
|
||||
compressedDdtMs.Close();
|
||||
DateTime ddtEnd = DateTime.UtcNow;
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Took {0} seconds to decompress DDT",
|
||||
(ddtEnd - ddtStart).TotalSeconds);
|
||||
break;
|
||||
case CompressionType.None:
|
||||
imageStream.Read(decompressedDdt, 0, decompressedDdt.Length);
|
||||
break;
|
||||
default:
|
||||
throw new
|
||||
ImageNotSupportedException($"Found unsupported compression algorithm {(ushort)ddtHeader.compression}");
|
||||
}
|
||||
|
||||
for(ulong i = 0; i < ddtHeader.entries; i++)
|
||||
cdDdt[i] = BitConverter.ToUInt32(decompressedDdt, (int)(i * sizeof(uint)));
|
||||
|
||||
switch(entry.dataType)
|
||||
{
|
||||
case DataType.CdSectorPrefixCorrected:
|
||||
sectorPrefixDdt = cdDdt;
|
||||
break;
|
||||
case DataType.CdSectorSuffixCorrected:
|
||||
sectorSuffixDdt = cdDdt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
// CICM XML metadata block
|
||||
case BlockType.CicmBlock:
|
||||
@@ -634,6 +713,15 @@ namespace DiscImageChef.DiscImages
|
||||
ErrorMessage = "Could not find user data deduplication table.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorSuffixMs == null || sectorSuffixDdt == null || sectorPrefixMs == null ||
|
||||
sectorPrefixDdt == null)
|
||||
{
|
||||
sectorSuffixMs = null;
|
||||
sectorSuffixDdt = null;
|
||||
sectorPrefixMs = null;
|
||||
sectorPrefixDdt = null;
|
||||
}
|
||||
}
|
||||
// Creating new
|
||||
else
|
||||
@@ -1018,30 +1106,153 @@ namespace DiscImageChef.DiscImages
|
||||
lastWrittenBlock = sectorAddress;
|
||||
}
|
||||
|
||||
bool prefixCorrect;
|
||||
int minute;
|
||||
int second;
|
||||
int frame;
|
||||
int storedLba;
|
||||
|
||||
// Split raw cd sector data in prefix (sync, header), user data and suffix (edc, ecc p, ecc q)
|
||||
switch(track.TrackType)
|
||||
{
|
||||
case TrackType.Audio:
|
||||
case TrackType.Data: return WriteSector(data, sectorAddress);
|
||||
case TrackType.CdMode1:
|
||||
if(sectorPrefix == null) sectorPrefix = new byte[imageInfo.Sectors * 16];
|
||||
if(sectorSuffix == null) sectorSuffix = new byte[imageInfo.Sectors * 288];
|
||||
if(sectorPrefix != null && sectorSuffix != null)
|
||||
{
|
||||
sector = new byte[2048];
|
||||
Array.Copy(data, 0, sectorPrefix, (int)sectorAddress * 16, 16);
|
||||
Array.Copy(data, 16, sector, 0, 2048);
|
||||
Array.Copy(data, 2064, sectorSuffix, (int)sectorAddress * 288, 288);
|
||||
return WriteSector(sector, sectorAddress);
|
||||
}
|
||||
|
||||
if(sectorSuffixMs == null) sectorSuffixMs = new MemoryStream();
|
||||
if(sectorPrefixMs == null) sectorPrefixMs = new MemoryStream();
|
||||
if(sectorSuffixDdt == null)
|
||||
{
|
||||
sectorSuffixDdt = new uint[imageInfo.Sectors];
|
||||
EccInit();
|
||||
}
|
||||
|
||||
if(sectorPrefixDdt == null) sectorPrefixDdt = new uint[imageInfo.Sectors];
|
||||
|
||||
sector = new byte[2048];
|
||||
if(ArrayHelpers.ArrayIsNullOrEmpty(data))
|
||||
{
|
||||
sectorPrefixDdt[sectorAddress] = (uint)CdFixFlags.NotDumped;
|
||||
sectorSuffixDdt[sectorAddress] = (uint)CdFixFlags.NotDumped;
|
||||
return WriteSector(sector, sectorAddress);
|
||||
}
|
||||
|
||||
prefixCorrect = true;
|
||||
|
||||
if(data[0x00] != 0x00 || data[0x01] != 0xFF || data[0x02] != 0xFF || data[0x03] != 0xFF ||
|
||||
data[0x04] != 0xFF || data[0x05] != 0xFF || data[0x06] != 0xFF || data[0x07] != 0xFF ||
|
||||
data[0x08] != 0xFF || data[0x09] != 0xFF || data[0x0A] != 0xFF || data[0x0B] != 0x00 ||
|
||||
data[0x0F] != 0x01) prefixCorrect = false;
|
||||
|
||||
if(prefixCorrect)
|
||||
{
|
||||
minute = (data[0x0C] >> 4) * 10 + (data[0x0C] & 0x0F);
|
||||
second = (data[0x0D] >> 4) * 10 + (data[0x0D] & 0x0F);
|
||||
frame = (data[0x0E] >> 4) * 10 + (data[0x0E] & 0x0F);
|
||||
storedLba = minute * 60 * 75 + second * 75 + frame - 150;
|
||||
prefixCorrect = storedLba == (int)sectorAddress;
|
||||
}
|
||||
|
||||
if(prefixCorrect) sectorPrefixDdt[sectorAddress] = (uint)CdFixFlags.Correct;
|
||||
else
|
||||
{
|
||||
if((sectorPrefixDdt[sectorAddress] & CD_DFIX_MASK) > 0)
|
||||
sectorPrefixMs.Position =
|
||||
((sectorPrefixDdt[sectorAddress] & CD_DFIX_MASK) - 1) * 16;
|
||||
else sectorPrefixMs.Seek(0, SeekOrigin.End);
|
||||
|
||||
sectorPrefixDdt[sectorAddress] = (uint)(sectorPrefixMs.Position / 16 + 1);
|
||||
sectorPrefixMs.Write(data, 0, 16);
|
||||
}
|
||||
|
||||
bool correct = SuffixIsCorrect(data);
|
||||
|
||||
if(correct) sectorSuffixDdt[sectorAddress] = (uint)CdFixFlags.Correct;
|
||||
else
|
||||
{
|
||||
if((sectorSuffixDdt[sectorAddress] & CD_DFIX_MASK) > 0)
|
||||
sectorSuffixMs.Position =
|
||||
((sectorSuffixDdt[sectorAddress] & CD_DFIX_MASK) - 1) * 288;
|
||||
else sectorSuffixMs.Seek(0, SeekOrigin.End);
|
||||
|
||||
sectorSuffixDdt[sectorAddress] = (uint)(sectorSuffixMs.Position / 288 + 1);
|
||||
|
||||
sectorSuffixMs.Write(data, 2064, 288);
|
||||
}
|
||||
|
||||
Array.Copy(data, 16, sector, 0, 2048);
|
||||
return WriteSector(sector, sectorAddress);
|
||||
case TrackType.CdMode2Formless:
|
||||
case TrackType.CdMode2Form1:
|
||||
case TrackType.CdMode2Form2:
|
||||
if(sectorPrefix == null) sectorPrefix = new byte[imageInfo.Sectors * 16];
|
||||
if(sectorSuffix == null) sectorSuffix = new byte[imageInfo.Sectors * 288];
|
||||
if(sectorPrefix != null && sectorSuffix != null)
|
||||
{
|
||||
sector = new byte[2336];
|
||||
Array.Copy(data, 0, sectorPrefix, (int)sectorAddress * 16, 16);
|
||||
Array.Copy(data, 16, sector, 0, 2336);
|
||||
return WriteSector(sector, sectorAddress);
|
||||
}
|
||||
|
||||
if(sectorSuffixMs == null) sectorSuffixMs = new MemoryStream();
|
||||
if(sectorPrefixMs == null) sectorPrefixMs = new MemoryStream();
|
||||
if(sectorSuffixDdt == null)
|
||||
{
|
||||
sectorSuffixDdt = new uint[imageInfo.Sectors];
|
||||
EccInit();
|
||||
}
|
||||
|
||||
if(sectorPrefixDdt == null) sectorPrefixDdt = new uint[imageInfo.Sectors];
|
||||
|
||||
sector = new byte[2336];
|
||||
if(ArrayHelpers.ArrayIsNullOrEmpty(sector))
|
||||
{
|
||||
sectorPrefixDdt[sectorAddress] = (uint)CdFixFlags.NotDumped;
|
||||
return WriteSector(sector, sectorAddress);
|
||||
}
|
||||
|
||||
prefixCorrect = true;
|
||||
|
||||
if(data[0x00] != 0x00 || data[0x01] != 0xFF || data[0x02] != 0xFF || data[0x03] != 0xFF ||
|
||||
data[0x04] != 0xFF || data[0x05] != 0xFF || data[0x06] != 0xFF || data[0x07] != 0xFF ||
|
||||
data[0x08] != 0xFF || data[0x09] != 0xFF || data[0x0A] != 0xFF || data[0x0B] != 0x00 ||
|
||||
data[0x0F] != 0x02 || data[0x10] != 0xFF || data[0x11] != 0xFF || data[0x12] != 0x00 ||
|
||||
data[0x13] != 0xFF || data[0x14] != 0xFF || data[0x15] != 0xFF || data[0x16] != 0x00 ||
|
||||
data[0x17] != 0x00) return false;
|
||||
|
||||
if(prefixCorrect)
|
||||
{
|
||||
minute = (data[0x0C] >> 4) * 10 + (data[0x0C] & 0x0F);
|
||||
second = (data[0x0D] >> 4) * 10 + (data[0x0D] & 0x0F);
|
||||
frame = (data[0x0E] >> 4) * 10 + (data[0x0E] & 0x0F);
|
||||
storedLba = minute * 60 * 75 + second * 75 + frame - 150;
|
||||
prefixCorrect = storedLba == (int)sectorAddress;
|
||||
}
|
||||
|
||||
if(prefixCorrect) sectorPrefixDdt[sectorAddress] = (uint)CdFixFlags.Correct;
|
||||
else
|
||||
{
|
||||
if((sectorPrefixDdt[sectorAddress] & CD_DFIX_MASK) > 0)
|
||||
sectorPrefixMs.Position =
|
||||
((sectorPrefixDdt[sectorAddress] & CD_DFIX_MASK) - 1) * 16;
|
||||
else sectorPrefixMs.Seek(0, SeekOrigin.End);
|
||||
|
||||
sectorPrefixDdt[sectorAddress] = (uint)(sectorPrefixMs.Position / 16 + 1);
|
||||
|
||||
sectorPrefixMs.Write(data, 0, 16);
|
||||
}
|
||||
|
||||
Array.Copy(data, 16, sector, 0, 2336);
|
||||
return WriteSector(sector, sectorAddress);
|
||||
}
|
||||
|
||||
break;
|
||||
case XmlMediaType.BlockMedia:
|
||||
switch(imageInfo.MediaType)
|
||||
@@ -1744,6 +1955,7 @@ namespace DiscImageChef.DiscImages
|
||||
case XmlMediaType.OpticalDisc when Tracks != null && Tracks.Count > 0:
|
||||
DateTime startCompress;
|
||||
DateTime endCompress;
|
||||
// Old format
|
||||
if(sectorPrefix != null && sectorSuffix != null)
|
||||
{
|
||||
idxEntry = new IndexEntry
|
||||
@@ -1883,6 +2095,290 @@ namespace DiscImageChef.DiscImages
|
||||
index.Add(idxEntry);
|
||||
blockStream = null;
|
||||
}
|
||||
else if(sectorSuffixMs != null && sectorSuffixDdt != null && sectorPrefixMs != null &&
|
||||
sectorPrefixDdt != null)
|
||||
{
|
||||
uint notDumpedPrefixes = 0;
|
||||
uint correctPrefixes = 0;
|
||||
uint writtenPrefixes = 0;
|
||||
uint notDumpedSuffixes = 0;
|
||||
uint correctSuffixes = 0;
|
||||
uint writtenSuffixes = 0;
|
||||
|
||||
for(long i = 0; i < sectorPrefixDdt.LongLength; i++)
|
||||
if((sectorPrefixDdt[i] & CD_XFIX_MASK) == (uint)CdFixFlags.NotDumped)
|
||||
notDumpedPrefixes++;
|
||||
else if((sectorPrefixDdt[i] & CD_XFIX_MASK) == (uint)CdFixFlags.Correct) correctPrefixes++;
|
||||
else if((sectorPrefixDdt[i] & CD_DFIX_MASK) > 0) writtenPrefixes++;
|
||||
|
||||
for(long i = 0; i < sectorPrefixDdt.LongLength; i++)
|
||||
if((sectorSuffixDdt[i] & CD_XFIX_MASK) == (uint)CdFixFlags.NotDumped)
|
||||
notDumpedSuffixes++;
|
||||
else if((sectorSuffixDdt[i] & CD_XFIX_MASK) == (uint)CdFixFlags.Correct) correctSuffixes++;
|
||||
else if((sectorSuffixDdt[i] & CD_DFIX_MASK) > 0) writtenSuffixes++;
|
||||
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"{0} ({1:P}% prefixes are correct, {2} ({3:P}%) prefixes have not been dumped, {4} ({5:P}%) prefixes have been written to image",
|
||||
correctPrefixes, correctPrefixes / imageInfo.Sectors,
|
||||
notDumpedPrefixes, notDumpedPrefixes / imageInfo.Sectors,
|
||||
writtenPrefixes, writtenPrefixes / imageInfo.Sectors);
|
||||
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"{0} ({1:P}% suffixes are correct, {2} ({3:P}%) suffixes have not been dumped, {4} ({5:P}%) suffixes have been written to image",
|
||||
correctSuffixes, correctSuffixes / imageInfo.Sectors,
|
||||
notDumpedSuffixes, notDumpedSuffixes / imageInfo.Sectors,
|
||||
writtenSuffixes, writtenSuffixes / imageInfo.Sectors);
|
||||
|
||||
idxEntry = new IndexEntry
|
||||
{
|
||||
blockType = BlockType.DeDuplicationTable,
|
||||
dataType = DataType.CdSectorPrefixCorrected,
|
||||
offset = (ulong)imageStream.Position
|
||||
};
|
||||
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Writing CompactDisc sector prefix DDT to position {0}",
|
||||
idxEntry.offset);
|
||||
|
||||
DdtHeader ddtHeader = new DdtHeader
|
||||
{
|
||||
identifier = BlockType.DeDuplicationTable,
|
||||
type = DataType.CdSectorPrefixCorrected,
|
||||
compression = CompressionType.Lzma,
|
||||
entries = (ulong)sectorPrefixDdt.LongLength,
|
||||
length = (ulong)(sectorPrefixDdt.LongLength * sizeof(uint))
|
||||
};
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
crc64 = new Crc64Context();
|
||||
for(ulong i = 0; i < (ulong)sectorPrefixDdt.LongLength; i++)
|
||||
{
|
||||
byte[] ddtEntry = BitConverter.GetBytes(sectorPrefixDdt[i]);
|
||||
crc64.Update(ddtEntry);
|
||||
lzmaBlockStream.Write(ddtEntry, 0, ddtEntry.Length);
|
||||
}
|
||||
|
||||
byte[] lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
ddtHeader.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
Crc64Context cmpCrc64Context = new Crc64Context();
|
||||
cmpCrc64Context.Update(lzmaProperties);
|
||||
cmpCrc64Context.Update(blockStream.ToArray());
|
||||
ddtHeader.cmpCrc64 = BitConverter.ToUInt64(cmpCrc64Context.Final(), 0);
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(ddtHeader));
|
||||
structureBytes = new byte[Marshal.SizeOf(ddtHeader)];
|
||||
Marshal.StructureToPtr(ddtHeader, structurePointer, true);
|
||||
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
imageStream.Write(structureBytes, 0, structureBytes.Length);
|
||||
structureBytes = null;
|
||||
imageStream.Write(lzmaProperties, 0, lzmaProperties.Length);
|
||||
imageStream.Write(blockStream.ToArray(), 0, (int)blockStream.Length);
|
||||
blockStream = null;
|
||||
lzmaBlockStream = null;
|
||||
|
||||
index.RemoveAll(t => t.blockType == BlockType.DeDuplicationTable &&
|
||||
t.dataType == DataType.CdSectorPrefixCorrected);
|
||||
|
||||
index.Add(idxEntry);
|
||||
|
||||
idxEntry = new IndexEntry
|
||||
{
|
||||
blockType = BlockType.DeDuplicationTable,
|
||||
dataType = DataType.CdSectorSuffixCorrected,
|
||||
offset = (ulong)imageStream.Position
|
||||
};
|
||||
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Writing CompactDisc sector suffix DDT to position {0}",
|
||||
idxEntry.offset);
|
||||
|
||||
ddtHeader = new DdtHeader
|
||||
{
|
||||
identifier = BlockType.DeDuplicationTable,
|
||||
type = DataType.CdSectorSuffixCorrected,
|
||||
compression = CompressionType.Lzma,
|
||||
entries = (ulong)sectorSuffixDdt.LongLength,
|
||||
length = (ulong)(sectorSuffixDdt.LongLength * sizeof(uint))
|
||||
};
|
||||
|
||||
blockStream = new MemoryStream();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
crc64 = new Crc64Context();
|
||||
for(ulong i = 0; i < (ulong)sectorSuffixDdt.LongLength; i++)
|
||||
{
|
||||
byte[] ddtEntry = BitConverter.GetBytes(sectorSuffixDdt[i]);
|
||||
crc64.Update(ddtEntry);
|
||||
lzmaBlockStream.Write(ddtEntry, 0, ddtEntry.Length);
|
||||
}
|
||||
|
||||
lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
ddtHeader.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
cmpCrc64Context = new Crc64Context();
|
||||
cmpCrc64Context.Update(lzmaProperties);
|
||||
cmpCrc64Context.Update(blockStream.ToArray());
|
||||
ddtHeader.cmpCrc64 = BitConverter.ToUInt64(cmpCrc64Context.Final(), 0);
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(ddtHeader));
|
||||
structureBytes = new byte[Marshal.SizeOf(ddtHeader)];
|
||||
Marshal.StructureToPtr(ddtHeader, structurePointer, true);
|
||||
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
imageStream.Write(structureBytes, 0, structureBytes.Length);
|
||||
structureBytes = null;
|
||||
imageStream.Write(lzmaProperties, 0, lzmaProperties.Length);
|
||||
imageStream.Write(blockStream.ToArray(), 0, (int)blockStream.Length);
|
||||
blockStream = null;
|
||||
lzmaBlockStream = null;
|
||||
|
||||
index.RemoveAll(t => t.blockType == BlockType.DeDuplicationTable &&
|
||||
t.dataType == DataType.CdSectorSuffixCorrected);
|
||||
|
||||
index.Add(idxEntry);
|
||||
|
||||
idxEntry = new IndexEntry
|
||||
{
|
||||
blockType = BlockType.DataBlock,
|
||||
dataType = DataType.CdSectorPrefixCorrected,
|
||||
offset = (ulong)imageStream.Position
|
||||
};
|
||||
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Writing CD sector corrected prefix block to position {0}",
|
||||
idxEntry.offset);
|
||||
|
||||
Crc64Context.Data(sectorPrefixMs.GetBuffer(), (uint)sectorPrefixMs.Length, out byte[] blockCrc);
|
||||
|
||||
BlockHeader prefixBlock = new BlockHeader
|
||||
{
|
||||
identifier = BlockType.DataBlock,
|
||||
type = DataType.CdSectorPrefixCorrected,
|
||||
length = (uint)sectorPrefixMs.Length,
|
||||
crc64 = BitConverter.ToUInt64(blockCrc, 0),
|
||||
sectorSize = 16
|
||||
};
|
||||
|
||||
lzmaProperties = null;
|
||||
|
||||
if(nocompress)
|
||||
{
|
||||
prefixBlock.compression = CompressionType.None;
|
||||
prefixBlock.cmpCrc64 = prefixBlock.crc64;
|
||||
prefixBlock.cmpLength = prefixBlock.length;
|
||||
blockStream = sectorPrefixMs;
|
||||
}
|
||||
else
|
||||
{
|
||||
startCompress = DateTime.Now;
|
||||
blockStream = new MemoryStream();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
sectorPrefixMs.WriteTo(lzmaBlockStream);
|
||||
lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
|
||||
Crc64Context cmpCrc = new Crc64Context();
|
||||
cmpCrc.Update(lzmaProperties);
|
||||
cmpCrc.Update(blockStream.ToArray());
|
||||
blockCrc = cmpCrc.Final();
|
||||
prefixBlock.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
prefixBlock.cmpCrc64 = BitConverter.ToUInt64(blockCrc, 0);
|
||||
prefixBlock.compression = CompressionType.Lzma;
|
||||
|
||||
lzmaBlockStream = null;
|
||||
endCompress = DateTime.Now;
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Took {0} seconds to compress prefix",
|
||||
(endCompress - startCompress).TotalSeconds);
|
||||
}
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(prefixBlock));
|
||||
structureBytes = new byte[Marshal.SizeOf(prefixBlock)];
|
||||
Marshal.StructureToPtr(prefixBlock, structurePointer, true);
|
||||
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
imageStream.Write(structureBytes, 0, structureBytes.Length);
|
||||
if(prefixBlock.compression == CompressionType.Lzma)
|
||||
imageStream.Write(lzmaProperties, 0, lzmaProperties.Length);
|
||||
imageStream.Write(blockStream.ToArray(), 0, (int)blockStream.Length);
|
||||
|
||||
index.RemoveAll(t => t.blockType == BlockType.DataBlock &&
|
||||
t.dataType == DataType.CdSectorPrefixCorrected);
|
||||
|
||||
index.Add(idxEntry);
|
||||
|
||||
idxEntry = new IndexEntry
|
||||
{
|
||||
blockType = BlockType.DataBlock,
|
||||
dataType = DataType.CdSectorSuffixCorrected,
|
||||
offset = (ulong)imageStream.Position
|
||||
};
|
||||
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Writing CD sector corrected suffix block to position {0}",
|
||||
idxEntry.offset);
|
||||
|
||||
Crc64Context.Data(sectorSuffixMs.GetBuffer(), (uint)sectorSuffixMs.Length, out blockCrc);
|
||||
|
||||
BlockHeader suffixBlock = new BlockHeader
|
||||
{
|
||||
identifier = BlockType.DataBlock,
|
||||
type = DataType.CdSectorSuffixCorrected,
|
||||
length = (uint)sectorSuffixMs.Length,
|
||||
crc64 = BitConverter.ToUInt64(blockCrc, 0),
|
||||
sectorSize = 288
|
||||
};
|
||||
|
||||
lzmaProperties = null;
|
||||
|
||||
if(nocompress)
|
||||
{
|
||||
suffixBlock.compression = CompressionType.None;
|
||||
suffixBlock.cmpCrc64 = suffixBlock.crc64;
|
||||
suffixBlock.cmpLength = suffixBlock.length;
|
||||
blockStream = sectorSuffixMs;
|
||||
}
|
||||
else
|
||||
{
|
||||
startCompress = DateTime.Now;
|
||||
blockStream = new MemoryStream();
|
||||
lzmaBlockStream = new LzmaStream(lzmaEncoderProperties, false, blockStream);
|
||||
sectorSuffixMs.WriteTo(lzmaBlockStream);
|
||||
lzmaProperties = lzmaBlockStream.Properties;
|
||||
lzmaBlockStream.Close();
|
||||
|
||||
Crc64Context cmpCrc = new Crc64Context();
|
||||
cmpCrc.Update(lzmaProperties);
|
||||
cmpCrc.Update(blockStream.ToArray());
|
||||
blockCrc = cmpCrc.Final();
|
||||
suffixBlock.cmpLength = (uint)blockStream.Length + LZMA_PROPERTIES_LENGTH;
|
||||
suffixBlock.cmpCrc64 = BitConverter.ToUInt64(blockCrc, 0);
|
||||
suffixBlock.compression = CompressionType.Lzma;
|
||||
|
||||
lzmaBlockStream = null;
|
||||
endCompress = DateTime.Now;
|
||||
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||
"Took {0} seconds to compress suffix",
|
||||
(endCompress - startCompress).TotalSeconds);
|
||||
}
|
||||
|
||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(suffixBlock));
|
||||
structureBytes = new byte[Marshal.SizeOf(suffixBlock)];
|
||||
Marshal.StructureToPtr(suffixBlock, structurePointer, true);
|
||||
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||
Marshal.FreeHGlobal(structurePointer);
|
||||
imageStream.Write(structureBytes, 0, structureBytes.Length);
|
||||
if(suffixBlock.compression == CompressionType.Lzma)
|
||||
imageStream.Write(lzmaProperties, 0, lzmaProperties.Length);
|
||||
imageStream.Write(blockStream.ToArray(), 0, (int)blockStream.Length);
|
||||
|
||||
index.RemoveAll(t => t.blockType == BlockType.DataBlock &&
|
||||
t.dataType == DataType.CdSectorSuffixCorrected);
|
||||
|
||||
index.Add(idxEntry);
|
||||
}
|
||||
|
||||
if(sectorSubchannel != null)
|
||||
{
|
||||
|
||||
@@ -622,7 +622,9 @@ enum <ushort> DataType
|
||||
AppleProfileTag = 72,
|
||||
AppleSonyTag = 73,
|
||||
PriamDataTowerTag = 74,
|
||||
CompactDiscMediaCatalogueNumber = 75
|
||||
CompactDiscMediaCatalogueNumber = 75,
|
||||
CdSectorPrefixCorrected = 76,
|
||||
CdSectorSuffixCorrected = 77
|
||||
};
|
||||
|
||||
enum <uint> BlockType
|
||||
|
||||
Reference in New Issue
Block a user