Use tuples to convert MediaType to type and subtype.

This commit is contained in:
2019-11-18 20:59:16 +00:00
parent dbcbdb3c88
commit 586536fdbf
11 changed files with 2532 additions and 1602 deletions

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ContentModelStore">
<e p="$APPLICATION_PLUGINS_DIR$/puppet/lib/stubs" t="IncludeRecursive" />
<e p="$USER_HOME$/.Rider2019.3/system/extResources" t="IncludeRecursive" />
<e p="$USER_HOME$/.Rider2019.3/system/resharper-host/local/Transient/ReSharperHost/v193/SolutionCaches/_DiscImageChef.-1491758497.00" t="ExcludeRecursive" />
<e p="$USER_HOME$/.nuget/packages/sqlitepclraw.lib.e_sqlite3.linux/1.1.12/runtimes/linux-x64/native/libe_sqlite3.so" t="Include" />

View File

@@ -47,22 +47,20 @@ using Tuple = DiscImageChef.Decoders.PCMCIA.Tuple;
namespace DiscImageChef.Core.Devices.Dumping
{
/// <summary>
/// Implements dumping ATA devices
/// </summary>
/// <summary>Implements dumping ATA devices</summary>
public partial class Dump
{
/// <summary>
/// Dumps an ATA device
/// </summary>
/// <summary>Dumps an ATA device</summary>
public void Ata()
{
if(dumpRaw)
{
if(force) ErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, continuing...");
if(force)
ErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, continuing...");
else
{
StoppingErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, aborting...");
return;
}
}
@@ -74,9 +72,12 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke("Requesting ATA IDENTIFY DEVICE.");
dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE.");
bool sense = dev.AtaIdentify(out byte[] cmdBuf, out _);
if(!sense && Identify.Decode(cmdBuf).HasValue)
if(!sense &&
Identify.Decode(cmdBuf).HasValue)
{
Identify.IdentifyDevice? ataIdNullable = Identify.Decode(cmdBuf);
if(ataIdNullable != null)
{
Identify.IdentifyDevice ataId = ataIdNullable.Value;
@@ -93,23 +94,28 @@ namespace DiscImageChef.Core.Devices.Dumping
// Initializate reader
UpdateStatus?.Invoke("Initializing reader.");
dumpLog.WriteLine("Initializing reader.");
Reader ataReader = new Reader(dev, TIMEOUT, ataIdentify);
var ataReader = new Reader(dev, TIMEOUT, ataIdentify);
// Fill reader blocks
ulong blocks = ataReader.GetDeviceBlocks();
// Check block sizes
if(ataReader.GetBlockSize())
{
dumpLog.WriteLine("ERROR: Cannot get block size: {0}.", ataReader.ErrorMessage);
ErrorMessage(ataReader.ErrorMessage);
return;
}
uint blockSize = ataReader.LogicalBlockSize;
uint physicalsectorsize = ataReader.PhysicalBlockSize;
if(ataReader.FindReadCommand())
{
dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", ataReader.ErrorMessage);
ErrorMessage(ataReader.ErrorMessage);
return;
}
@@ -118,6 +124,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{
dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", ataReader.ErrorMessage);
ErrorMessage(ataReader.ErrorMessage);
return;
}
@@ -127,27 +134,36 @@ namespace DiscImageChef.Core.Devices.Dumping
byte sectors = ataReader.Sectors;
UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes).");
UpdateStatus
?.Invoke($"Device reports {cylinders} cylinders {heads} heads {sectors} sectors per track.");
UpdateStatus?.
Invoke($"Device reports {cylinders} cylinders {heads} heads {sectors} sectors per track.");
UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block.");
UpdateStatus?.Invoke($"Device reports {physicalsectorsize} bytes per physical block.");
dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize);
dumpLog.WriteLine("Device reports {0} cylinders {1} heads {2} sectors per track.", cylinders, heads,
sectors);
dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize);
dumpLog.WriteLine("Device reports {0} bytes per physical block.", physicalsectorsize);
bool removable = !dev.IsCompactFlash &&
ataId.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.Removable);
DumpHardwareType currentTry = null;
ExtentsULong extents = null;
ResumeSupport.Process(ataReader.IsLba, removable, blocks, dev.Manufacturer, dev.Model, dev.Serial,
dev.PlatformId, ref resume, ref currentTry, ref extents);
if(currentTry == null || extents == null)
if(currentTry == null ||
extents == null)
{
StoppingErrorMessage?.Invoke("Could not process resume file, not continuing...");
return;
}
@@ -157,7 +173,8 @@ namespace DiscImageChef.Core.Devices.Dumping
bool ret = true;
if(dev.IsUsb && dev.UsbDescriptors != null &&
if(dev.IsUsb &&
dev.UsbDescriptors != null &&
!outputPlugin.SupportedMediaTags.Contains(MediaTagType.USB_Descriptors))
{
ret = false;
@@ -165,7 +182,8 @@ namespace DiscImageChef.Core.Devices.Dumping
ErrorMessage("Output format does not support USB descriptors.");
}
if(dev.IsPcmcia && dev.Cis != null &&
if(dev.IsPcmcia &&
dev.Cis != null &&
!outputPlugin.SupportedMediaTags.Contains(MediaTagType.PCMCIA_CIS))
{
ret = false;
@@ -183,10 +201,13 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!ret)
{
dumpLog.WriteLine("Several media tags not supported, {0}continuing...", force ? "" : "not ");
if(force) ErrorMessage("Several media tags not supported, continuing...");
if(force)
ErrorMessage("Several media tags not supported, continuing...");
else
{
StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing...");
return;
}
}
@@ -200,9 +221,11 @@ namespace DiscImageChef.Core.Devices.Dumping
{
dumpLog.WriteLine("Error creating output image, not continuing.");
dumpLog.WriteLine(outputPlugin.ErrorMessage);
StoppingErrorMessage?.Invoke("Error creating output image, not continuing." +
Environment.NewLine +
outputPlugin.ErrorMessage);
return;
}
@@ -212,7 +235,9 @@ namespace DiscImageChef.Core.Devices.Dumping
if(ataReader.IsLba)
{
UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");
if(skip < blocksToRead) skip = blocksToRead;
if(skip < blocksToRead)
skip = blocksToRead;
mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
ibgLog = new IbgLog(outputPrefix + ".ibg", ATA_PROFILE);
@@ -229,6 +254,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime timeSpeedStart = DateTime.UtcNow;
ulong sectorSpeedStart = 0;
InitProgress?.Invoke();
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
{
if(aborted)
@@ -236,14 +262,21 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
dumpLog.WriteLine("Aborted!");
break;
}
if(blocks - i < blocksToRead) blocksToRead = (byte)(blocks - i);
if(blocks - i < blocksToRead)
blocksToRead = (byte)(blocks - i);
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
if(currentSpeed > maxSpeed && currentSpeed != 0) maxSpeed = currentSpeed;
if(currentSpeed < minSpeed && currentSpeed != 0) minSpeed = currentSpeed;
if(currentSpeed > maxSpeed &&
currentSpeed != 0)
maxSpeed = currentSpeed;
if(currentSpeed < minSpeed &&
currentSpeed != 0)
minSpeed = currentSpeed;
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)",
@@ -262,9 +295,11 @@ namespace DiscImageChef.Core.Devices.Dumping
}
else
{
if(i + skip > blocks) skip = (uint)(blocks - i);
if(i + skip > blocks)
skip = (uint)(blocks - i);
for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b);
for(ulong b = i; b < i + skip; b++)
resume.BadBlocks.Add(b);
mhddLog.Write(i, duration < 500 ? 65535 : duration);
@@ -281,7 +316,9 @@ namespace DiscImageChef.Core.Devices.Dumping
resume.NextBlock = i + blocksToRead;
double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
if(elapsed < 1) continue;
if(elapsed < 1)
continue;
currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
sectorSpeedStart = 0;
@@ -291,23 +328,32 @@ namespace DiscImageChef.Core.Devices.Dumping
end = DateTime.Now;
EndProgress?.Invoke();
mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * (double)(blocks + 1) / 1024 /
(totalDuration / 1000), devicePath);
UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds.");
UpdateStatus
?.Invoke($"Average dump speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
UpdateStatus
?.Invoke($"Average write speed {(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec.");
UpdateStatus?.
Invoke($"Average dump speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
UpdateStatus?.
Invoke($"Average write speed {(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec.");
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Trimming
if(resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim)
if(resume.BadBlocks.Count > 0 &&
!aborted &&
!notrim &&
newTrim)
{
start = DateTime.UtcNow;
UpdateStatus?.Invoke("Trimming bad sectors");
@@ -315,6 +361,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ulong[] tmpArray = resume.BadBlocks.ToArray();
InitProgress?.Invoke();
foreach(ulong badSector in tmpArray)
{
if(aborted)
@@ -322,6 +369,7 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
dumpLog.WriteLine("Aborted!");
break;
}
@@ -331,7 +379,8 @@ namespace DiscImageChef.Core.Devices.Dumping
totalDuration += duration;
if(error) continue;
if(error)
continue;
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
@@ -346,7 +395,9 @@ namespace DiscImageChef.Core.Devices.Dumping
#endregion Trimming
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
if(resume.BadBlocks.Count > 0 &&
!aborted &&
retryPasses > 0)
{
int pass = 1;
bool forward = true;
@@ -354,6 +405,7 @@ namespace DiscImageChef.Core.Devices.Dumping
InitProgress?.Invoke();
repeatRetryLba:
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(aborted)
@@ -361,6 +413,7 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
dumpLog.WriteLine("Aborted!");
break;
}
@@ -380,15 +433,19 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
}
else if(persistent) outputPlugin.WriteSector(cmdBuf, badSector);
else if(persistent)
outputPlugin.WriteSector(cmdBuf, badSector);
}
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
if(pass < retryPasses &&
!aborted &&
resume.BadBlocks.Count > 0)
{
pass++;
forward = !forward;
resume.BadBlocks.Sort();
resume.BadBlocks.Reverse();
goto repeatRetryLba;
}
@@ -409,6 +466,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime timeSpeedStart = DateTime.UtcNow;
ulong sectorSpeedStart = 0;
InitProgress?.Invoke();
for(ushort cy = 0; cy < cylinders; cy++)
{
for(byte hd = 0; hd < heads; hd++)
@@ -420,16 +478,22 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
dumpLog.WriteLine("Aborted!");
break;
}
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
if(currentSpeed > maxSpeed && currentSpeed != 0) maxSpeed = currentSpeed;
if(currentSpeed < minSpeed && currentSpeed != 0) minSpeed = currentSpeed;
if(currentSpeed > maxSpeed &&
currentSpeed != 0)
maxSpeed = currentSpeed;
if(currentSpeed < minSpeed &&
currentSpeed != 0)
minSpeed = currentSpeed;
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
PulseProgress
?.Invoke($"Reading cylinder {cy} head {hd} sector {sc} ({currentSpeed:F3} MiB/sec.)");
PulseProgress?.
Invoke($"Reading cylinder {cy} head {hd} sector {sc} ({currentSpeed:F3} MiB/sec.)");
bool error = ataReader.ReadChs(out cmdBuf, cy, hd, sc, out duration);
@@ -440,10 +504,13 @@ namespace DiscImageChef.Core.Devices.Dumping
mhddLog.Write(currentBlock, duration);
ibgLog.Write(currentBlock, currentSpeed * 1024);
DateTime writeStart = DateTime.Now;
outputPlugin.WriteSector(cmdBuf,
(ulong)((cy * heads + hd) * sectors + (sc - 1)));
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
extents.Add(currentBlock);
dumpLog.WriteLine("Error reading cylinder {0} head {1} sector {2}.", cy, hd,
sc);
}
@@ -454,8 +521,10 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog.Write(currentBlock, 0);
DateTime writeStart = DateTime.Now;
outputPlugin.WriteSector(new byte[blockSize],
(ulong)((cy * heads + hd) * sectors + (sc - 1)));
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
}
@@ -463,7 +532,9 @@ namespace DiscImageChef.Core.Devices.Dumping
currentBlock++;
double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
if(elapsed < 1) continue;
if(elapsed < 1)
continue;
currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
sectorSpeedStart = 0;
@@ -475,25 +546,37 @@ namespace DiscImageChef.Core.Devices.Dumping
end = DateTime.Now;
EndProgress?.Invoke();
mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * (double)(blocks + 1) / 1024 /
(totalDuration / 1000), devicePath);
UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds.");
UpdateStatus
?.Invoke($"Average dump speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
UpdateStatus
?.Invoke($"Average write speed {(double)blockSize * (double)(blocks + 1) / 1024 / (imageWriteDuration / 1000):F3} KiB/sec.");
UpdateStatus?.
Invoke($"Average dump speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
UpdateStatus?.
Invoke($"Average write speed {(double)blockSize * (double)(blocks + 1) / 1024 / (imageWriteDuration / 1000):F3} KiB/sec.");
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 /
(imageWriteDuration / 1000));
}
foreach(ulong bad in resume.BadBlocks) dumpLog.WriteLine("Sector {0} could not be read.", bad);
foreach(ulong bad in resume.BadBlocks)
dumpLog.WriteLine("Sector {0} could not be read.", bad);
outputPlugin.SetDumpHardware(resume.Tries);
if(preSidecar != null) outputPlugin.SetCicmMetadata(preSidecar);
if(preSidecar != null)
outputPlugin.SetCicmMetadata(preSidecar);
dumpLog.WriteLine("Closing output file.");
UpdateStatus?.Invoke("Closing output file.");
DateTime closeStart = DateTime.Now;
@@ -506,20 +589,24 @@ namespace DiscImageChef.Core.Devices.Dumping
{
dumpLog.WriteLine("Aborted!");
UpdateStatus?.Invoke("Aborted!");
return;
}
double totalChkDuration = 0;
if(!nometadata)
{
dumpLog.WriteLine("Creating sidecar.");
UpdateStatus?.Invoke("Creating sidecar.");
FiltersList filters = new FiltersList();
var filters = new FiltersList();
IFilter filter = filters.GetFilter(outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
if(!inputPlugin.Open(filter))
{
StoppingErrorMessage?.Invoke("Could not open created image.");
return;
}
@@ -533,13 +620,15 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecarClass.EndProgressEvent2 += EndProgress2;
sidecarClass.UpdateStatusEvent += UpdateStatus;
CICMMetadataType sidecar = sidecarClass.Create();
if(preSidecar != null)
{
preSidecar.BlockMedia = sidecar.BlockMedia;
sidecar = preSidecar;
}
if(dev.IsUsb && dev.UsbDescriptors != null)
if(dev.IsUsb &&
dev.UsbDescriptors != null)
{
dumpLog.WriteLine("Reading USB descriptors.");
UpdateStatus?.Invoke("Reading USB descriptors.");
@@ -548,18 +637,16 @@ namespace DiscImageChef.Core.Devices.Dumping
if(ret)
sidecar.BlockMedia[0].USB = new USBType
{
ProductID = dev.UsbProductId,
VendorID = dev.UsbVendorId,
Descriptors = new DumpType
ProductID = dev.UsbProductId, VendorID = dev.UsbVendorId, Descriptors = new DumpType
{
Image = outputPath,
Size = (ulong)dev.UsbDescriptors.Length,
Image = outputPath, Size = (ulong)dev.UsbDescriptors.Length,
Checksums = Checksum.GetChecksums(dev.UsbDescriptors).ToArray()
}
};
}
if(dev.IsPcmcia && dev.Cis != null)
if(dev.IsPcmcia &&
dev.Cis != null)
{
dumpLog.WriteLine("Reading PCMCIA CIS.");
UpdateStatus?.Invoke("Reading PCMCIA CIS.");
@@ -570,8 +657,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{
CIS = new DumpType
{
Image = outputPath,
Size = (ulong)dev.Cis.Length,
Image = outputPath, Size = (ulong)dev.Cis.Length,
Checksums = Checksum.GetChecksums(dev.Cis).ToArray()
}
};
@@ -579,6 +665,7 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Decoding PCMCIA CIS.");
UpdateStatus?.Invoke("Decoding PCMCIA CIS.");
Tuple[] tuples = CIS.GetTuples(dev.Cis);
if(tuples != null)
foreach(Tuple tuple in tuples)
switch(tuple.Code)
@@ -591,6 +678,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{
sidecar.BlockMedia[0].PCMCIA.ManufacturerCode =
manfid.ManufacturerID;
sidecar.BlockMedia[0].PCMCIA.CardCode = manfid.CardID;
sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true;
sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true;
@@ -604,8 +692,10 @@ namespace DiscImageChef.Core.Devices.Dumping
{
sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer;
sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product;
sidecar.BlockMedia[0].PCMCIA.Compliance =
$"{vers.MajorVersion}.{vers.MinorVersion}";
sidecar.BlockMedia[0].PCMCIA.AdditionalInformation =
vers.AdditionalInformation;
}
@@ -621,8 +711,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{
Identify = new DumpType
{
Image = outputPath,
Size = (ulong)cmdBuf.Length,
Image = outputPath, Size = (ulong)cmdBuf.Length,
Checksums = Checksum.GetChecksums(cmdBuf).ToArray()
}
};
@@ -631,13 +720,17 @@ namespace DiscImageChef.Core.Devices.Dumping
totalChkDuration = (chkEnd - chkStart).TotalMilliseconds;
UpdateStatus?.Invoke($"Sidecar created in {(chkEnd - chkStart).TotalSeconds} seconds.");
UpdateStatus
?.Invoke($"Average checksum speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec.");
UpdateStatus?.
Invoke($"Average checksum speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec.");
dumpLog.WriteLine("Sidecar created in {0} seconds.", (chkEnd - chkStart).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000));
List<(ulong start, string type)> filesystems = new List<(ulong start, string type)>();
if(sidecar.BlockMedia[0].FileSystemInformation != null)
filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation
where partition.FileSystems != null
@@ -645,26 +738,29 @@ namespace DiscImageChef.Core.Devices.Dumping
select (partition.StartSector, fileSystem.Type));
if(filesystems.Count > 0)
foreach(var filesystem in filesystems.Select(o => new {o.start, o.type}).Distinct())
foreach(var filesystem in filesystems.Select(o => new
{
UpdateStatus
?.Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}");
o.start, o.type
}).Distinct())
{
UpdateStatus?.
Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}");
dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type,
filesystem.start);
}
string xmlDskTyp, xmlDskSubTyp;
(string type, string subType) xmlType;
if(dev.IsCompactFlash)
CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.CompactFlash, out xmlDskTyp,
out xmlDskSubTyp);
xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.CompactFlash);
else if(dev.IsPcmcia)
CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.PCCardTypeI, out xmlDskTyp,
out xmlDskSubTyp);
xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.PCCardTypeI);
else
CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.GENERIC_HDD, out xmlDskTyp,
out xmlDskSubTyp);
sidecar.BlockMedia[0].DiskType = xmlDskTyp;
sidecar.BlockMedia[0].DiskSubType = xmlDskSubTyp;
xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.GENERIC_HDD);
sidecar.BlockMedia[0].DiskType = xmlType.type;
sidecar.BlockMedia[0].DiskSubType = xmlType.subType;
sidecar.BlockMedia[0].Interface = "ATA";
sidecar.BlockMedia[0].LogicalBlocks = blocks;
sidecar.BlockMedia[0].PhysicalBlockSize = physicalsectorsize;
@@ -673,7 +769,10 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecar.BlockMedia[0].Model = dev.Model;
sidecar.BlockMedia[0].Serial = dev.Serial;
sidecar.BlockMedia[0].Size = blocks * blockSize;
if(cylinders > 0 && heads > 0 && sectors > 0)
if(cylinders > 0 &&
heads > 0 &&
sectors > 0)
{
sidecar.BlockMedia[0].Cylinders = cylinders;
sidecar.BlockMedia[0].CylindersSpecified = true;
@@ -685,30 +784,40 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke("Writing metadata sidecar");
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
var xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType));
var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
xmlSer.Serialize(xmlFs, sidecar);
xmlFs.Close();
}
UpdateStatus?.Invoke("");
UpdateStatus
?.Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing).");
UpdateStatus
?.Invoke($"Average speed: {(double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");
UpdateStatus?.
Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing).");
UpdateStatus?.
Invoke($"Average speed: {(double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");
UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec.");
UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec.");
UpdateStatus?.Invoke($"{resume.BadBlocks.Count} sectors could not be read.");
if(resume.BadBlocks.Count > 0) resume.BadBlocks.Sort();
if(resume.BadBlocks.Count > 0)
resume.BadBlocks.Sort();
UpdateStatus?.Invoke("");
}
if(dev.IsCompactFlash) Statistics.AddMedia(MediaType.CompactFlash, true);
else if(dev.IsPcmcia) Statistics.AddMedia(MediaType.PCCardTypeI, true);
else Statistics.AddMedia(MediaType.GENERIC_HDD, true);
if(dev.IsCompactFlash)
Statistics.AddMedia(MediaType.CompactFlash, true);
else if(dev.IsPcmcia)
Statistics.AddMedia(MediaType.PCCardTypeI, true);
else
Statistics.AddMedia(MediaType.GENERIC_HDD, true);
}
else StoppingErrorMessage?.Invoke("Unable to communicate with ATA device.");
else
StoppingErrorMessage?.Invoke("Unable to communicate with ATA device.");
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -400,8 +400,7 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke($"Blocksize changed to {blockSize} bytes at block {currentBlock}");
dumpLog.WriteLine("Blocksize changed to {0} bytes at block {1}", blockSize, currentBlock);
sense = dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, dev.Timeout,
out duration);
sense = dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, dev.Timeout, out duration);
totalDuration += duration;
@@ -891,8 +890,7 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke($"Blocksize changed to {blockSize} bytes at block {currentBlock}");
dumpLog.WriteLine("Blocksize changed to {0} bytes at block {1}", blockSize, currentBlock);
sense = dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, dev.Timeout,
out duration);
sense = dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, dev.Timeout, out duration);
totalDuration += duration;
@@ -1314,11 +1312,10 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(dskType);
CommonTypes.Metadata.MediaType.MediaTypeToString(dskType, out string xmlDskTyp,
out string xmlDskSubTyp);
(string type, string subType) xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType);
sidecar.BlockMedia[0].DiskType = xmlDskTyp;
sidecar.BlockMedia[0].DiskSubType = xmlDskSubTyp;
sidecar.BlockMedia[0].DiskType = xmlType.type;
sidecar.BlockMedia[0].DiskSubType = xmlType.subType;
// TODO: Implement device firmware revision
if(!dev.IsRemovable ||

View File

@@ -47,25 +47,22 @@ using MediaType = DiscImageChef.CommonTypes.MediaType;
namespace DiscImageChef.Core.Devices.Dumping
{
/// <summary>
/// Implements dumping a MultiMediaCard or SecureDigital flash card
/// </summary>
/// <summary>Implements dumping a MultiMediaCard or SecureDigital flash card</summary>
public partial class Dump
{
/// <summary>
/// Dumps a MultiMediaCard or SecureDigital flash card
/// </summary>
/// <summary>Dumps a MultiMediaCard or SecureDigital flash card</summary>
public void SecureDigital()
{
if(dumpRaw)
{
if(force)
ErrorMessage
?.Invoke("Raw dumping is not supported in MultiMediaCard or SecureDigital devices. Continuing...");
ErrorMessage?.
Invoke("Raw dumping is not supported in MultiMediaCard or SecureDigital devices. Continuing...");
else
{
StoppingErrorMessage
?.Invoke("Raw dumping is not supported in MultiMediaCard or SecureDigital devices. Aborting...");
StoppingErrorMessage?.
Invoke("Raw dumping is not supported in MultiMediaCard or SecureDigital devices. Aborting...");
return;
}
}
@@ -94,23 +91,30 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke("Reading Extended CSD");
dumpLog.WriteLine("Reading Extended CSD");
sense = dev.ReadExtendedCsd(out ecsd, out _, TIMEOUT, out duration);
if(!sense)
{
ExtendedCSD ecsdDecoded = Decoders.MMC.Decoders.DecodeExtendedCSD(ecsd);
blocksToRead = ecsdDecoded.OptimalReadSize;
blocks = ecsdDecoded.SectorCount;
blockSize = (uint)(ecsdDecoded.SectorSize == 1 ? 4096 : 512);
if(ecsdDecoded.NativeSectorSize == 0) physicalBlockSize = 512;
else if(ecsdDecoded.NativeSectorSize == 1) physicalBlockSize = 4096;
if(ecsdDecoded.NativeSectorSize == 0)
physicalBlockSize = 512;
else if(ecsdDecoded.NativeSectorSize == 1)
physicalBlockSize = 4096;
// Supposing it's high-capacity MMC if it has Extended CSD...
byteAddressed = false;
mediaTags.Add(MediaTagType.MMC_ExtendedCSD, null);
}
else ecsd = null;
else
ecsd = null;
UpdateStatus?.Invoke("Reading CSD");
dumpLog.WriteLine("Reading CSD");
sense = dev.ReadCsd(out csd, out _, TIMEOUT, out duration);
if(!sense)
{
if(blocks == 0)
@@ -122,13 +126,17 @@ namespace DiscImageChef.Core.Devices.Dumping
mediaTags.Add(MediaTagType.MMC_CSD, null);
}
else csd = null;
else
csd = null;
UpdateStatus?.Invoke("Reading OCR");
dumpLog.WriteLine("Reading OCR");
sense = dev.ReadOcr(out ocr, out _, TIMEOUT, out duration);
if(sense) ocr = null;
else mediaTags.Add(MediaTagType.MMC_OCR, null);
if(sense)
ocr = null;
else
mediaTags.Add(MediaTagType.MMC_OCR, null);
break;
}
@@ -138,30 +146,41 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke("Reading CSD");
dumpLog.WriteLine("Reading CSD");
sense = dev.ReadCsd(out csd, out _, TIMEOUT, out duration);
if(!sense)
{
Decoders.SecureDigital.CSD csdDecoded = Decoders.SecureDigital.Decoders.DecodeCSD(csd);
blocks = (ulong)(csdDecoded.Structure == 0
? (csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2)
: (csdDecoded.Size + 1) * 1024);
blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength);
// Structure >=1 for SDHC/SDXC, so that's block addressed
byteAddressed = csdDecoded.Structure == 0;
mediaTags.Add(MediaTagType.SD_CSD, null);
}
else csd = null;
else
csd = null;
UpdateStatus?.Invoke("Reading OCR");
dumpLog.WriteLine("Reading OCR");
sense = dev.ReadSdocr(out ocr, out _, TIMEOUT, out duration);
if(sense) ocr = null;
else mediaTags.Add(MediaTagType.SD_OCR, null);
if(sense)
ocr = null;
else
mediaTags.Add(MediaTagType.SD_OCR, null);
UpdateStatus?.Invoke("Reading SCR");
dumpLog.WriteLine("Reading SCR");
sense = dev.ReadScr(out scr, out _, TIMEOUT, out duration);
if(sense) scr = null;
else mediaTags.Add(MediaTagType.SD_SCR, null);
if(sense)
scr = null;
else
mediaTags.Add(MediaTagType.SD_SCR, null);
break;
}
@@ -170,8 +189,11 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke("Reading CID");
dumpLog.WriteLine("Reading CID");
sense = dev.ReadCid(out byte[] cid, out _, TIMEOUT, out duration);
if(sense) cid = null;
else mediaTags.Add(dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID, null);
if(sense)
cid = null;
else
mediaTags.Add(dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID, null);
DateTime start;
DateTime end;
@@ -184,6 +206,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{
dumpLog.WriteLine("Unable to get device size.");
StoppingErrorMessage?.Invoke("Unable to get device size.");
return;
}
@@ -197,30 +220,39 @@ namespace DiscImageChef.Core.Devices.Dumping
{
error = dev.Read(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, TIMEOUT, out duration);
if(error) blocksToRead /= 2;
if(error)
blocksToRead /= 2;
if(!error || blocksToRead == 1) break;
if(!error ||
blocksToRead == 1)
break;
}
if(error)
{
dumpLog.WriteLine("ERROR: Cannot get blocks to read, device error {0}.", dev.LastError);
StoppingErrorMessage?.Invoke($"Device error {dev.LastError} trying to guess ideal transfer length.");
return;
}
UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
if(skip < blocksToRead) skip = blocksToRead;
if(skip < blocksToRead)
skip = blocksToRead;
DumpHardwareType currentTry = null;
ExtentsULong extents = null;
ResumeSupport.Process(true, false, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformId,
ref resume, ref currentTry, ref extents);
if(currentTry == null || extents == null)
if(currentTry == null ||
extents == null)
{
StoppingErrorMessage?.Invoke("Could not process resume file, not continuing...");
return;
}
@@ -228,7 +260,8 @@ namespace DiscImageChef.Core.Devices.Dumping
foreach(MediaTagType tag in mediaTags.Keys)
{
if(outputPlugin.SupportedMediaTags.Contains(tag)) continue;
if(outputPlugin.SupportedMediaTags.Contains(tag))
continue;
ret = false;
dumpLog.WriteLine($"Output format does not support {tag}.");
@@ -246,12 +279,14 @@ namespace DiscImageChef.Core.Devices.Dumping
{
dumpLog.WriteLine("Several media tags not supported, not continuing...");
StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing...");
return;
}
}
MhddLog mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
IbgLog ibgLog = new IbgLog(outputPrefix + ".ibg", SD_PROFILE);
var mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
var ibgLog = new IbgLog(outputPrefix + ".ibg", SD_PROFILE);
ret = outputPlugin.Create(outputPath,
dev.Type == DeviceType.SecureDigital ? MediaType.SecureDigital : MediaType.MMC,
formatOptions, blocks, blockSize);
@@ -261,8 +296,10 @@ namespace DiscImageChef.Core.Devices.Dumping
{
dumpLog.WriteLine("Error creating output image, not continuing.");
dumpLog.WriteLine(outputPlugin.ErrorMessage);
StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine +
outputPlugin.ErrorMessage);
return;
}
@@ -279,6 +316,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ulong sectorSpeedStart = 0;
InitProgress?.Invoke();
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
{
if(aborted)
@@ -286,14 +324,21 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
dumpLog.WriteLine("Aborted!");
break;
}
if(blocks - i < blocksToRead) blocksToRead = (byte)(blocks - i);
if(blocks - i < blocksToRead)
blocksToRead = (byte)(blocks - i);
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
if(currentSpeed > maxSpeed && currentSpeed != 0) maxSpeed = currentSpeed;
if(currentSpeed < minSpeed && currentSpeed != 0) minSpeed = currentSpeed;
if(currentSpeed > maxSpeed &&
currentSpeed != 0)
maxSpeed = currentSpeed;
if(currentSpeed < minSpeed &&
currentSpeed != 0)
minSpeed = currentSpeed;
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
@@ -313,9 +358,11 @@ namespace DiscImageChef.Core.Devices.Dumping
}
else
{
if(i + skip > blocks) skip = (uint)(blocks - i);
if(i + skip > blocks)
skip = (uint)(blocks - i);
for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b);
for(ulong b = i; b < i + skip; b++)
resume.BadBlocks.Add(b);
mhddLog.Write(i, duration < 500 ? 65535 : duration);
@@ -332,7 +379,9 @@ namespace DiscImageChef.Core.Devices.Dumping
resume.NextBlock = i + blocksToRead;
double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
if(elapsed < 1) continue;
if(elapsed < 1)
continue;
currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
sectorSpeedStart = 0;
@@ -342,22 +391,32 @@ namespace DiscImageChef.Core.Devices.Dumping
end = DateTime.Now;
EndProgress?.Invoke();
mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
devicePath);
UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds.");
UpdateStatus
?.Invoke($"Average dump speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
UpdateStatus
?.Invoke($"Average write speed {(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec.");
UpdateStatus?.
Invoke($"Average dump speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
UpdateStatus?.
Invoke($"Average write speed {(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec.");
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Trimming
if(resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim)
if(resume.BadBlocks.Count > 0 &&
!aborted &&
!notrim &&
newTrim)
{
start = DateTime.UtcNow;
UpdateStatus?.Invoke("Trimming bad sectors");
@@ -365,6 +424,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ulong[] tmpArray = resume.BadBlocks.ToArray();
InitProgress?.Invoke();
foreach(ulong badSector in tmpArray)
{
if(aborted)
@@ -372,6 +432,7 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
dumpLog.WriteLine("Aborted!");
break;
}
@@ -382,7 +443,8 @@ namespace DiscImageChef.Core.Devices.Dumping
totalDuration += duration;
if(error) continue;
if(error)
continue;
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
@@ -397,7 +459,9 @@ namespace DiscImageChef.Core.Devices.Dumping
#endregion Trimming
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
if(resume.BadBlocks.Count > 0 &&
!aborted &&
retryPasses > 0)
{
int pass = 1;
bool forward = true;
@@ -406,6 +470,7 @@ namespace DiscImageChef.Core.Devices.Dumping
InitProgress?.Invoke();
repeatRetryLba:
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(aborted)
@@ -413,6 +478,7 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
dumpLog.WriteLine("Aborted!");
break;
}
@@ -433,15 +499,19 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
}
else if(runningPersistent) outputPlugin.WriteSector(cmdBuf, badSector);
else if(runningPersistent)
outputPlugin.WriteSector(cmdBuf, badSector);
}
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
if(pass < retryPasses &&
!aborted &&
resume.BadBlocks.Count > 0)
{
pass++;
forward = !forward;
resume.BadBlocks.Sort();
resume.BadBlocks.Reverse();
goto repeatRetryLba;
}
@@ -452,7 +522,10 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
outputPlugin.SetDumpHardware(resume.Tries);
if(preSidecar != null) outputPlugin.SetCicmMetadata(preSidecar);
if(preSidecar != null)
outputPlugin.SetCicmMetadata(preSidecar);
dumpLog.WriteLine("Closing output file.");
UpdateStatus?.Invoke("Closing output file.");
DateTime closeStart = DateTime.Now;
@@ -465,18 +538,22 @@ namespace DiscImageChef.Core.Devices.Dumping
{
UpdateStatus?.Invoke("Aborted!");
dumpLog.WriteLine("Aborted!");
return;
}
double totalChkDuration = 0;
if(!nometadata)
{
UpdateStatus?.Invoke("Creating sidecar.");
dumpLog.WriteLine("Creating sidecar.");
FiltersList filters = new FiltersList();
var filters = new FiltersList();
IFilter filter = filters.GetFilter(outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
if(!inputPlugin.Open(filter)) StoppingErrorMessage?.Invoke("Could not open created image.");
if(!inputPlugin.Open(filter))
StoppingErrorMessage?.Invoke("Could not open created image.");
DateTime chkStart = DateTime.UtcNow;
sidecarClass = new Sidecar(inputPlugin, outputPath, filter.Id, encoding);
@@ -499,9 +576,11 @@ namespace DiscImageChef.Core.Devices.Dumping
{
case DeviceType.MMC:
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
break;
case DeviceType.SecureDigital:
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
break;
}
@@ -513,23 +592,23 @@ namespace DiscImageChef.Core.Devices.Dumping
{
cidDump = new DumpType
{
Image = outputPath,
Size = (ulong)cid.Length,
Checksums = Checksum.GetChecksums(cid).ToArray()
Image = outputPath, Size = (ulong)cid.Length, Checksums = Checksum.GetChecksums(cid).ToArray()
};
ret =
outputPlugin.WriteMediaTag(cid,
dev.Type == DeviceType.SecureDigital
? MediaTagType.SD_CID
dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID
: MediaTagType.MMC_CID);
// Cannot write CID to image
if(!ret && !force)
if(!ret &&
!force)
{
dumpLog.WriteLine("Cannot write CID to output image.");
StoppingErrorMessage?.Invoke("Cannot write CID to output image." + Environment.NewLine +
outputPlugin.ErrorMessage);
return;
}
}
@@ -538,23 +617,23 @@ namespace DiscImageChef.Core.Devices.Dumping
{
csdDump = new DumpType
{
Image = outputPath,
Size = (ulong)csd.Length,
Checksums = Checksum.GetChecksums(csd).ToArray()
Image = outputPath, Size = (ulong)csd.Length, Checksums = Checksum.GetChecksums(csd).ToArray()
};
ret =
outputPlugin.WriteMediaTag(csd,
dev.Type == DeviceType.SecureDigital
? MediaTagType.SD_CSD
dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CSD
: MediaTagType.MMC_CSD);
// Cannot write CSD to image
if(!ret && !force)
if(!ret &&
!force)
{
dumpLog.WriteLine("Cannot write CSD to output image.");
StoppingErrorMessage?.Invoke("Cannot write CSD to output image." + Environment.NewLine +
outputPlugin.ErrorMessage);
return;
}
}
@@ -563,20 +642,21 @@ namespace DiscImageChef.Core.Devices.Dumping
{
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType
{
Image = outputPath,
Size = (ulong)ecsd.Length,
Checksums = Checksum.GetChecksums(ecsd).ToArray()
Image = outputPath, Size = (ulong)ecsd.Length, Checksums = Checksum.GetChecksums(ecsd).ToArray()
};
ret = outputPlugin.WriteMediaTag(ecsd, MediaTagType.MMC_ExtendedCSD);
// Cannot write Extended CSD to image
if(!ret && !force)
if(!ret &&
!force)
{
dumpLog.WriteLine("Cannot write Extended CSD to output image.");
StoppingErrorMessage?.Invoke("Cannot write Extended CSD to output image." +
Environment.NewLine +
outputPlugin.ErrorMessage);
return;
}
}
@@ -585,23 +665,23 @@ namespace DiscImageChef.Core.Devices.Dumping
{
ocrDump = new DumpType
{
Image = outputPath,
Size = (ulong)ocr.Length,
Checksums = Checksum.GetChecksums(ocr).ToArray()
Image = outputPath, Size = (ulong)ocr.Length, Checksums = Checksum.GetChecksums(ocr).ToArray()
};
ret =
outputPlugin.WriteMediaTag(ocr,
dev.Type == DeviceType.SecureDigital
? MediaTagType.SD_OCR
dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_OCR
: MediaTagType.MMC_OCR);
// Cannot write OCR to image
if(!ret && !force)
if(!ret &&
!force)
{
dumpLog.WriteLine("Cannot write OCR to output image.");
StoppingErrorMessage?.Invoke("Cannot write OCR to output image." + Environment.NewLine +
outputPlugin.ErrorMessage);
return;
}
}
@@ -610,19 +690,20 @@ namespace DiscImageChef.Core.Devices.Dumping
{
sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType
{
Image = outputPath,
Size = (ulong)scr.Length,
Checksums = Checksum.GetChecksums(scr).ToArray()
Image = outputPath, Size = (ulong)scr.Length, Checksums = Checksum.GetChecksums(scr).ToArray()
};
ret = outputPlugin.WriteMediaTag(scr, MediaTagType.SD_SCR);
// Cannot write SCR to image
if(!ret && !force)
if(!ret &&
!force)
{
dumpLog.WriteLine("Cannot write SCR to output image.");
StoppingErrorMessage?.Invoke("Cannot write SCR to output image." + Environment.NewLine +
outputPlugin.ErrorMessage);
return;
}
}
@@ -633,11 +714,13 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecar.BlockMedia[0].MultiMediaCard.CID = cidDump;
sidecar.BlockMedia[0].MultiMediaCard.CSD = csdDump;
sidecar.BlockMedia[0].MultiMediaCard.OCR = ocrDump;
break;
case DeviceType.SecureDigital:
sidecar.BlockMedia[0].SecureDigital.CID = cidDump;
sidecar.BlockMedia[0].SecureDigital.CSD = csdDump;
sidecar.BlockMedia[0].SecureDigital.OCR = ocrDump;
break;
}
@@ -645,29 +728,36 @@ namespace DiscImageChef.Core.Devices.Dumping
totalChkDuration = (end - chkStart).TotalMilliseconds;
UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds.");
UpdateStatus
?.Invoke($"Average checksum speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec.");
UpdateStatus?.
Invoke($"Average checksum speed {(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec.");
dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000));
string xmlDskTyp = null, xmlDskSubTyp = null;
(string type, string subType) xmlType = (null, null);
switch(dev.Type)
{
case DeviceType.MMC:
CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.MMC, out xmlDskTyp,
out xmlDskSubTyp);
xmlType =
CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.MMC);
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(MediaType.MMC);
break;
case DeviceType.SecureDigital:
CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.SecureDigital, out xmlDskTyp,
out xmlDskSubTyp);
CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.SecureDigital);
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(MediaType.SecureDigital);
break;
}
sidecar.BlockMedia[0].DiskType = xmlDskTyp;
sidecar.BlockMedia[0].DiskSubType = xmlDskSubTyp;
sidecar.BlockMedia[0].DiskType = xmlType.type;
sidecar.BlockMedia[0].DiskSubType = xmlType.subType;
// TODO: Implement device firmware revision
sidecar.BlockMedia[0].LogicalBlocks = blocks;
sidecar.BlockMedia[0].PhysicalBlockSize = physicalBlockSize > 0 ? physicalBlockSize : blockSize;
@@ -679,31 +769,38 @@ namespace DiscImageChef.Core.Devices.Dumping
UpdateStatus?.Invoke("Writing metadata sidecar");
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
var xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType));
var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
xmlSer.Serialize(xmlFs, sidecar);
xmlFs.Close();
}
UpdateStatus?.Invoke("");
UpdateStatus
?.Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing).");
UpdateStatus
?.Invoke($"Average speed: {(double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");
UpdateStatus?.
Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing).");
UpdateStatus?.
Invoke($"Average speed: {(double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");
UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec.");
UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec.");
UpdateStatus?.Invoke($"{resume.BadBlocks.Count} sectors could not be read.");
UpdateStatus?.Invoke("");
if(resume.BadBlocks.Count > 0) resume.BadBlocks.Sort();
if(resume.BadBlocks.Count > 0)
resume.BadBlocks.Sort();
switch(dev.Type)
{
case DeviceType.MMC:
Statistics.AddMedia(MediaType.MMC, true);
break;
case DeviceType.SecureDigital:
Statistics.AddMedia(MediaType.SecureDigital, true);
break;
}
}

View File

@@ -81,11 +81,13 @@ namespace DiscImageChef.Core.Devices.Dumping
{
DicConsole.
ErrorWriteLine("Because of the commands sent to a device, dumping XGD must be done with administrative privileges. Cannot continue.");
dumpLog.WriteLine("Cannot dump XGD without administrative privileges.");
return;
}
}
if(mediaTags.ContainsKey(MediaTagType.DVD_PFI))
mediaTags.Remove(MediaTagType.DVD_PFI);
@@ -1232,10 +1234,10 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecar.OpticalDisc[0].Sessions = 1;
sidecar.OpticalDisc[0].Dimensions = Dimensions.DimensionsFromMediaType(dskType);
var xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType);
(string type, string subType) xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType);
sidecar.OpticalDisc[0].DiscType = xmlDskTyp;
sidecar.OpticalDisc[0].DiscSubType = xmlDskSubTyp;
sidecar.OpticalDisc[0].DiscType = xmlType.type;
sidecar.OpticalDisc[0].DiscSubType = xmlType.subType;
foreach(KeyValuePair<MediaTagType, byte[]> tag in mediaTags)
if(outputPlugin.SupportedMediaTags.Contains(tag.Key))

View File

@@ -53,9 +53,7 @@ namespace DiscImageChef.Core
{
public partial class Sidecar
{
/// <summary>
/// Creates a metadata sidecar for a block media (e.g. floppy, hard disk, flash card, usb stick)
/// </summary>
/// <summary>Creates a metadata sidecar for a block media (e.g. floppy, hard disk, flash card, usb stick)</summary>
/// <param name="image">Image</param>
/// <param name="filterId">Filter uuid</param>
/// <param name="imagePath">Image path</param>
@@ -63,30 +61,29 @@ namespace DiscImageChef.Core
/// <param name="plugins">Image plugins</param>
/// <param name="imgChecksums">List of image checksums</param>
/// <param name="sidecar">Metadata sidecar</param>
void BlockMedia(IMediaImage image, Guid filterId, string imagePath, FileInfo fi,
PluginBase plugins,
void BlockMedia(IMediaImage image, Guid filterId, string imagePath, FileInfo fi, PluginBase plugins,
List<ChecksumType> imgChecksums, ref CICMMetadataType sidecar, Encoding encoding)
{
if(aborted) return;
if(aborted)
return;
sidecar.BlockMedia = new[]
{
new BlockMediaType
{
Checksums = imgChecksums.ToArray(),
Image = new ImageType
Checksums = imgChecksums.ToArray(), Image = new ImageType
{
format = image.Format,
offset = 0,
offsetSpecified = true,
Value = Path.GetFileName(imagePath)
format = image.Format, offset = 0, offsetSpecified = true, Value = Path.GetFileName(imagePath)
},
Size = (ulong)fi.Length,
Sequence = new SequenceType {MediaTitle = image.Info.MediaTitle}
Size = (ulong)fi.Length, Sequence = new SequenceType
{
MediaTitle = image.Info.MediaTitle
}
}
};
if(image.Info.MediaSequence != 0 && image.Info.LastMediaSequence != 0)
if(image.Info.MediaSequence != 0 &&
image.Info.LastMediaSequence != 0)
{
sidecar.BlockMedia[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence;
sidecar.BlockMedia[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence;
@@ -98,9 +95,11 @@ namespace DiscImageChef.Core
}
UpdateStatus("Hashing media tags...");
foreach(MediaTagType tagType in image.Info.ReadableMediaTags)
{
if(aborted) return;
if(aborted)
return;
switch(tagType)
{
@@ -109,27 +108,28 @@ namespace DiscImageChef.Core
{
Identify = new DumpType
{
Checksums =
Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY))
.ToArray(),
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY)).
ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY).Length
}
};
break;
case MediaTagType.ATA_IDENTIFY:
sidecar.BlockMedia[0].ATA = new ATAType
{
Identify = new DumpType
{
Checksums = Checksum
.GetChecksums(image.ReadDiskTag(MediaTagType.ATA_IDENTIFY))
.ToArray(),
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.ATA_IDENTIFY)).
ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.ATA_IDENTIFY).Length
}
};
break;
case MediaTagType.PCMCIA_CIS:
byte[] cis = image.ReadDiskTag(MediaTagType.PCMCIA_CIS);
sidecar.BlockMedia[0].PCMCIA = new PCMCIAType
{
CIS = new DumpType
@@ -137,7 +137,9 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(cis).ToArray(), Size = (ulong)cis.Length
}
};
Tuple[] tuples = CIS.GetTuples(cis);
if(tuples != null)
foreach(Tuple tuple in tuples)
switch(tuple.Code)
@@ -150,6 +152,7 @@ namespace DiscImageChef.Core
{
sidecar.BlockMedia[0].PCMCIA.ManufacturerCode =
manfid.ManufacturerID;
sidecar.BlockMedia[0].PCMCIA.CardCode = manfid.CardID;
sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true;
sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true;
@@ -163,8 +166,10 @@ namespace DiscImageChef.Core
{
sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer;
sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product;
sidecar.BlockMedia[0].PCMCIA.Compliance =
$"{vers.MajorVersion}.{vers.MinorVersion}";
sidecar.BlockMedia[0].PCMCIA.AdditionalInformation =
vers.AdditionalInformation;
}
@@ -178,112 +183,137 @@ namespace DiscImageChef.Core
{
Inquiry = new DumpType
{
Checksums = Checksum
.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_INQUIRY))
.ToArray(),
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_INQUIRY)).
ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SCSI_INQUIRY).Length
}
};
break;
case MediaTagType.SD_CID:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
sidecar.BlockMedia[0].SecureDigital.CID = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_CID)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SD_CID).Length
};
break;
case MediaTagType.SD_CSD:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
sidecar.BlockMedia[0].SecureDigital.CSD = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_CSD)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SD_CSD).Length
};
break;
case MediaTagType.SD_SCR:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_SCR)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SD_SCR).Length
};
break;
case MediaTagType.SD_OCR:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
sidecar.BlockMedia[0].SecureDigital.OCR = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_OCR)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SD_OCR).Length
};
break;
case MediaTagType.MMC_CID:
if(sidecar.BlockMedia[0].MultiMediaCard == null)
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
sidecar.BlockMedia[0].MultiMediaCard.CID = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_CID)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SD_CID).Length
};
break;
case MediaTagType.MMC_CSD:
if(sidecar.BlockMedia[0].MultiMediaCard == null)
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
sidecar.BlockMedia[0].MultiMediaCard.CSD = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_CSD)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SD_CSD).Length
};
break;
case MediaTagType.MMC_OCR:
if(sidecar.BlockMedia[0].MultiMediaCard == null)
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
sidecar.BlockMedia[0].MultiMediaCard.OCR = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_OCR)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SD_OCR).Length
};
break;
case MediaTagType.MMC_ExtendedCSD:
if(sidecar.BlockMedia[0].MultiMediaCard == null)
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.MMC_ExtendedCSD))
.ToArray(),
Checksums =
Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.MMC_ExtendedCSD)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.MMC_ExtendedCSD).Length
};
break;
case MediaTagType.USB_Descriptors:
if(sidecar.BlockMedia[0].USB == null) sidecar.BlockMedia[0].USB = new USBType();
if(sidecar.BlockMedia[0].USB == null)
sidecar.BlockMedia[0].USB = new USBType();
sidecar.BlockMedia[0].USB.Descriptors = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.USB_Descriptors))
.ToArray(),
Checksums =
Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.USB_Descriptors)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.USB_Descriptors).Length
};
break;
case MediaTagType.SCSI_MODESENSE_6:
if(sidecar.BlockMedia[0].SCSI == null) sidecar.BlockMedia[0].SCSI = new SCSIType();
if(sidecar.BlockMedia[0].SCSI == null)
sidecar.BlockMedia[0].SCSI = new SCSIType();
sidecar.BlockMedia[0].SCSI.ModeSense = new DumpType
{
Checksums =
Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_6)).ToArray(),
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_6)).
ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_6).Length
};
break;
case MediaTagType.SCSI_MODESENSE_10:
if(sidecar.BlockMedia[0].SCSI == null) sidecar.BlockMedia[0].SCSI = new SCSIType();
if(sidecar.BlockMedia[0].SCSI == null)
sidecar.BlockMedia[0].SCSI = new SCSIType();
sidecar.BlockMedia[0].SCSI.ModeSense10 = new DumpType
{
Checksums =
Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_10)).ToArray(),
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_10)).
ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_10).Length
};
break;
}
}
@@ -296,7 +326,7 @@ namespace DiscImageChef.Core
{
UpdateStatus("Hashing sectors...");
Checksum contentChkWorker = new Checksum();
var contentChkWorker = new Checksum();
// For fast debugging, skip checksum
//goto skipImageChecksum;
@@ -306,11 +336,13 @@ namespace DiscImageChef.Core
ulong doneSectors = 0;
InitProgress2();
while(doneSectors < sectors)
{
if(aborted)
{
EndProgress2();
return;
}
@@ -342,29 +374,30 @@ namespace DiscImageChef.Core
EndProgress2();
}
MediaType.MediaTypeToString(image.Info.MediaType, out string dskType, out string dskSubType);
sidecar.BlockMedia[0].DiskType = dskType;
sidecar.BlockMedia[0].DiskSubType = dskSubType;
(string type, string subType) diskType = MediaType.MediaTypeToString(image.Info.MediaType);
sidecar.BlockMedia[0].DiskType = diskType.type;
sidecar.BlockMedia[0].DiskSubType = diskType.subType;
Statistics.AddMedia(image.Info.MediaType, false);
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(image.Info.MediaType);
sidecar.BlockMedia[0].LogicalBlocks = image.Info.Sectors;
sidecar.BlockMedia[0].LogicalBlockSize = image.Info.SectorSize;
// TODO: Detect it
sidecar.BlockMedia[0].PhysicalBlockSize = image.Info.SectorSize;
if(image is ITapeImage tapeImage && tapeImage.IsTape)
if(image is ITapeImage tapeImage &&
tapeImage.IsTape)
{
List<TapePartitionType> tapePartitions = new List<TapePartitionType>();
foreach(TapePartition tapePartition in tapeImage.TapePartitions)
{
TapePartitionType thisPartition = new TapePartitionType
var thisPartition = new TapePartitionType
{
Image = sidecar.BlockMedia[0].Image,
Sequence = tapePartition.Number,
StartBlock = tapePartition.FirstBlock,
EndBlock = tapePartition.LastBlock
Image = sidecar.BlockMedia[0].Image, Sequence = tapePartition.Number,
StartBlock = tapePartition.FirstBlock, EndBlock = tapePartition.LastBlock
};
if(tapeImage.TapePartitions.Count == 1)
@@ -373,9 +406,10 @@ namespace DiscImageChef.Core
{
UpdateStatus($"Hashing partition {tapePartition.Number}...");
if(aborted) return;
if(aborted)
return;
Checksum tapePartitionChk = new Checksum();
var tapePartitionChk = new Checksum();
// For fast debugging, skip checksum
//goto skipImageChecksum;
@@ -385,11 +419,13 @@ namespace DiscImageChef.Core
ulong doneSectors = 0;
InitProgress2();
while(doneSectors < sectors)
{
if(aborted)
{
EndProgress2();
return;
}
@@ -405,6 +441,7 @@ namespace DiscImageChef.Core
{
sector = image.ReadSectors(tapePartition.FirstBlock + doneSectors,
(uint)(sectors - doneSectors));
UpdateProgress2("Hashing blocks {0} of {1}", (long)doneSectors, (long)sectors);
doneSectors += sectors - doneSectors;
}
@@ -428,14 +465,11 @@ namespace DiscImageChef.Core
foreach(TapeFile tapeFile in tapeImage.Files.Where(f => f.Partition == tapePartition.Number))
{
TapeFileType thisFile = new TapeFileType
var thisFile = new TapeFileType
{
Sequence = tapeFile.File,
StartBlock = tapeFile.FirstBlock,
Sequence = tapeFile.File, StartBlock = tapeFile.FirstBlock,
EndBlock = tapeFile.LastBlock,
Image = sidecar.BlockMedia[0].Image,
Size = 0,
BlockSize = 0
Image = sidecar.BlockMedia[0].Image, Size = 0, BlockSize = 0
};
if(tapeImage.Files.Count(f => f.Partition == tapePartition.Number) == 1)
@@ -447,9 +481,10 @@ namespace DiscImageChef.Core
{
UpdateStatus($"Hashing file {tapeFile.File}...");
if(aborted) return;
if(aborted)
return;
Checksum tapeFileChk = new Checksum();
var tapeFileChk = new Checksum();
// For fast debugging, skip checksum
//goto skipImageChecksum;
@@ -459,11 +494,13 @@ namespace DiscImageChef.Core
ulong doneSectors = 0;
InitProgress2();
while(doneSectors < sectors)
{
if(aborted)
{
EndProgress2();
return;
}
@@ -479,6 +516,7 @@ namespace DiscImageChef.Core
{
sector = image.ReadSectors(tapeFile.FirstBlock + doneSectors,
(uint)(sectors - doneSectors));
UpdateProgress2("Hashing blocks {0} of {1}", (long)doneSectors, (long)sectors);
doneSectors += sectors - doneSectors;
}
@@ -513,36 +551,40 @@ namespace DiscImageChef.Core
UpdateStatus("Checking filesystems...");
if(aborted) return;
if(aborted)
return;
List<Partition> partitions = Partitions.GetAll(image);
Partitions.AddSchemesToStats(partitions);
sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[1];
if(partitions.Count > 0)
{
sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[partitions.Count];
for(int i = 0; i < partitions.Count; i++)
{
if(aborted) return;
if(aborted)
return;
sidecar.BlockMedia[0].FileSystemInformation[i] = new PartitionType
{
Description = partitions[i].Description,
EndSector = partitions[i].End,
Name = partitions[i].Name,
Sequence = (uint)partitions[i].Sequence,
StartSector = partitions[i].Start,
Type = partitions[i].Type
Description = partitions[i].Description, EndSector = partitions[i].End,
Name = partitions[i].Name, Sequence = (uint)partitions[i].Sequence,
StartSector = partitions[i].Start, Type = partitions[i].Type
};
List<FileSystemType> lstFs = new List<FileSystemType>();
foreach(IFilesystem plugin in plugins.PluginsList.Values)
try
{
if(aborted) return;
if(aborted)
return;
if(!plugin.Identify(image, partitions[i])) continue;
if(!plugin.Identify(image, partitions[i]))
continue;
if(plugin is IReadOnlyFilesystem fsPlugin &&
fsPlugin.Mount(image, partitions[i], encoding, null, null) == Errno.NoError)
@@ -553,7 +595,8 @@ namespace DiscImageChef.Core
fsPlugin.Unmount();
}
else plugin.GetInformation(image, partitions[i], out _, encoding);
else
plugin.GetInformation(image, partitions[i], out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
@@ -565,20 +608,23 @@ namespace DiscImageChef.Core
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
if(lstFs.Count > 0) sidecar.BlockMedia[0].FileSystemInformation[i].FileSystems = lstFs.ToArray();
if(lstFs.Count > 0)
sidecar.BlockMedia[0].FileSystemInformation[i].FileSystems = lstFs.ToArray();
}
}
else
{
if(aborted) return;
if(aborted)
return;
sidecar.BlockMedia[0].FileSystemInformation[0] =
new PartitionType {StartSector = 0, EndSector = image.Info.Sectors - 1};
Partition wholePart = new Partition
sidecar.BlockMedia[0].FileSystemInformation[0] = new PartitionType
{
Name = "Whole device",
Length = image.Info.Sectors,
StartSector = 0, EndSector = image.Info.Sectors - 1
};
var wholePart = new Partition
{
Name = "Whole device", Length = image.Info.Sectors,
Size = image.Info.Sectors * image.Info.SectorSize
};
@@ -587,9 +633,11 @@ namespace DiscImageChef.Core
foreach(IFilesystem plugin in plugins.PluginsList.Values)
try
{
if(aborted) return;
if(aborted)
return;
if(!plugin.Identify(image, wholePart)) continue;
if(!plugin.Identify(image, wholePart))
continue;
if(plugin is IReadOnlyFilesystem fsPlugin &&
fsPlugin.Mount(image, wholePart, encoding, null, null) == Errno.NoError)
@@ -600,7 +648,8 @@ namespace DiscImageChef.Core
fsPlugin.Unmount();
}
else plugin.GetInformation(image, wholePart, out _, encoding);
else
plugin.GetInformation(image, wholePart, out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
@@ -612,12 +661,15 @@ namespace DiscImageChef.Core
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
if(lstFs.Count > 0) sidecar.BlockMedia[0].FileSystemInformation[0].FileSystems = lstFs.ToArray();
if(lstFs.Count > 0)
sidecar.BlockMedia[0].FileSystemInformation[0].FileSystems = lstFs.ToArray();
}
UpdateStatus("Saving metadata...");
if(image.Info.Cylinders > 0 && image.Info.Heads > 0 && image.Info.SectorsPerTrack > 0)
if(image.Info.Cylinders > 0 &&
image.Info.Heads > 0 &&
image.Info.SectorsPerTrack > 0)
{
sidecar.BlockMedia[0].CylindersSpecified = true;
sidecar.BlockMedia[0].HeadsSpecified = true;
@@ -630,8 +682,10 @@ namespace DiscImageChef.Core
if(image.Info.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY))
{
Identify.IdentifyDevice? ataId = Identify.Decode(image.ReadDiskTag(MediaTagType.ATA_IDENTIFY));
if(ataId.HasValue)
if(ataId.Value.CurrentCylinders > 0 && ataId.Value.CurrentHeads > 0 &&
if(ataId.Value.CurrentCylinders > 0 &&
ataId.Value.CurrentHeads > 0 &&
ataId.Value.CurrentSectorsPerTrack > 0)
{
sidecar.BlockMedia[0].CylindersSpecified = true;
@@ -641,7 +695,9 @@ namespace DiscImageChef.Core
sidecar.BlockMedia[0].Heads = ataId.Value.CurrentHeads;
sidecar.BlockMedia[0].SectorsPerTrack = ataId.Value.CurrentSectorsPerTrack;
}
else if(ataId.Value.Cylinders > 0 && ataId.Value.Heads > 0 && ataId.Value.SectorsPerTrack > 0)
else if(ataId.Value.Cylinders > 0 &&
ataId.Value.Heads > 0 &&
ataId.Value.SectorsPerTrack > 0)
{
sidecar.BlockMedia[0].CylindersSpecified = true;
sidecar.BlockMedia[0].HeadsSpecified = true;
@@ -652,7 +708,8 @@ namespace DiscImageChef.Core
}
}
if(image.DumpHardware != null) sidecar.BlockMedia[0].DumpHardwareArray = image.DumpHardware.ToArray();
if(image.DumpHardware != null)
sidecar.BlockMedia[0].DumpHardwareArray = image.DumpHardware.ToArray();
// TODO: This is more of a hack, redo it planned for >4.0
string trkFormat = null;
@@ -662,17 +719,21 @@ namespace DiscImageChef.Core
case CommonTypes.MediaType.Apple32SS:
case CommonTypes.MediaType.Apple32DS:
trkFormat = "Apple GCR (DOS 3.2)";
break;
case CommonTypes.MediaType.Apple33SS:
case CommonTypes.MediaType.Apple33DS:
trkFormat = "Apple GCR (DOS 3.3)";
break;
case CommonTypes.MediaType.AppleSonySS:
case CommonTypes.MediaType.AppleSonyDS:
trkFormat = "Apple GCR (Sony)";
break;
case CommonTypes.MediaType.AppleFileWare:
trkFormat = "Apple GCR (Twiggy)";
break;
case CommonTypes.MediaType.DOS_525_SS_DD_9:
case CommonTypes.MediaType.DOS_525_DS_DD_8:
@@ -720,6 +781,7 @@ namespace DiscImageChef.Core
case CommonTypes.MediaType.Apricot_35:
case CommonTypes.MediaType.CompactFloppy:
trkFormat = "IBM MFM";
break;
case CommonTypes.MediaType.ATARI_525_SD:
case CommonTypes.MediaType.NEC_8_SD:
@@ -733,18 +795,22 @@ namespace DiscImageChef.Core
case CommonTypes.MediaType.IBM43FD_128:
case CommonTypes.MediaType.IBM43FD_256:
trkFormat = "IBM FM";
break;
case CommonTypes.MediaType.CBM_35_DD:
trkFormat = "Commodore MFM";
break;
case CommonTypes.MediaType.CBM_AMIGA_35_HD:
case CommonTypes.MediaType.CBM_AMIGA_35_DD:
trkFormat = "Amiga MFM";
break;
case CommonTypes.MediaType.CBM_1540:
case CommonTypes.MediaType.CBM_1540_Ext:
case CommonTypes.MediaType.CBM_1571:
trkFormat = "Commodore GCR";
break;
case CommonTypes.MediaType.SHARP_525_9:
case CommonTypes.MediaType.SHARP_35_9: break;
@@ -752,6 +818,7 @@ namespace DiscImageChef.Core
case CommonTypes.MediaType.ECMA_99_26:
case CommonTypes.MediaType.ECMA_99_8:
trkFormat = "ISO MFM";
break;
case CommonTypes.MediaType.ECMA_54:
case CommonTypes.MediaType.ECMA_59:
@@ -763,9 +830,11 @@ namespace DiscImageChef.Core
case CommonTypes.MediaType.ECMA_78:
case CommonTypes.MediaType.ECMA_78_2:
trkFormat = "ISO FM";
break;
default:
trkFormat = "Unknown";
break;
}
@@ -773,22 +842,27 @@ namespace DiscImageChef.Core
string scpFilePath = Path.Combine(Path.GetDirectoryName(imagePath),
Path.GetFileNameWithoutExtension(imagePath) + ".scp");
if(aborted) return;
if(aborted)
return;
if(File.Exists(scpFilePath))
{
UpdateStatus("Hashing SuperCardPro image...");
SuperCardPro scpImage = new SuperCardPro();
ZZZNoFilter scpFilter = new ZZZNoFilter();
var scpImage = new SuperCardPro();
var scpFilter = new ZZZNoFilter();
scpFilter.Open(scpFilePath);
if(image.Info.Heads <= 2 && scpImage.Identify(scpFilter))
if(image.Info.Heads <= 2 &&
scpImage.Identify(scpFilter))
{
try { scpImage.Open(scpFilter); }
try
{
scpImage.Open(scpFilter);
}
catch(NotImplementedException) { }
if(image.Info.Heads == 2 && scpImage.Header.heads == 0 || image.Info.Heads == 1 &&
(scpImage.Header.heads == 1 || scpImage.Header.heads == 2))
if(image.Info.Heads == 2 && scpImage.Header.heads == 0 ||
image.Info.Heads == 1 && (scpImage.Header.heads == 1 || scpImage.Header.heads == 2))
if(scpImage.Header.end + 1 >= image.Info.Cylinders)
{
List<BlockTrackType> scpBlockTrackTypes = new List<BlockTrackType>();
@@ -797,16 +871,15 @@ namespace DiscImageChef.Core
for(byte t = scpImage.Header.start; t <= scpImage.Header.end; t++)
{
if(aborted) return;
if(aborted)
return;
BlockTrackType scpBlockTrackType = new BlockTrackType
var scpBlockTrackType = new BlockTrackType
{
Cylinder = t / image.Info.Heads,
Head = (ushort)(t % image.Info.Heads),
Image = new ImageType
Cylinder = t / image.Info.Heads, Head = (ushort)(t % image.Info.Heads), Image =
new ImageType
{
format = scpImage.Format,
Value = Path.GetFileName(scpFilePath),
format = scpImage.Format, Value = Path.GetFileName(scpFilePath),
offset = scpImage.Header.offsets[t]
}
};
@@ -826,6 +899,7 @@ namespace DiscImageChef.Core
byte[] trackContents =
new byte[scpTrack.Entries.Last().dataOffset +
scpTrack.Entries.Last().trackLength - scpImage.Header.offsets[t] + 1];
scpStream.Position = scpImage.Header.offsets[t];
scpStream.Read(trackContents, 0, trackContents.Length);
scpBlockTrackType.Size = (ulong)trackContents.Length;
@@ -839,12 +913,12 @@ namespace DiscImageChef.Core
scpBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray();
}
else
DicConsole
.ErrorWriteLine("SuperCardPro image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
DicConsole.
ErrorWriteLine("SuperCardPro image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
scpImage.Header.end + 1, image.Info.Cylinders);
else
DicConsole
.ErrorWriteLine("SuperCardPro image do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
DicConsole.
ErrorWriteLine("SuperCardPro image do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
2, image.Info.Heads);
}
}
@@ -852,33 +926,45 @@ namespace DiscImageChef.Core
#region KryoFlux
string kfFile = null;
string basename = Path.Combine(Path.GetDirectoryName(imagePath),
Path.GetFileNameWithoutExtension(imagePath));
bool kfDir = false;
if(aborted) return;
if(aborted)
return;
if(Directory.Exists(basename))
{
string[] possibleKfStarts = Directory.GetFiles(basename, "*.raw", SearchOption.TopDirectoryOnly);
if(possibleKfStarts.Length > 0)
{
kfFile = possibleKfStarts[0];
kfDir = true;
}
}
else if(File.Exists(basename + "00.0.raw")) kfFile = basename + "00.0.raw";
else if(File.Exists(basename + "00.1.raw")) kfFile = basename + "00.1.raw";
else if(File.Exists(basename + "00.0.raw"))
kfFile = basename + "00.0.raw";
else if(File.Exists(basename + "00.1.raw"))
kfFile = basename + "00.1.raw";
if(kfFile != null)
{
UpdateStatus("Hashing KryoFlux images...");
KryoFlux kfImage = new KryoFlux();
ZZZNoFilter kfFilter = new ZZZNoFilter();
var kfImage = new KryoFlux();
var kfFilter = new ZZZNoFilter();
kfFilter.Open(kfFile);
if(image.Info.Heads <= 2 && kfImage.Identify(kfFilter))
if(image.Info.Heads <= 2 &&
kfImage.Identify(kfFilter))
{
try { kfImage.Open(kfFilter); }
try
{
kfImage.Open(kfFilter);
}
catch(NotImplementedException) { }
if(kfImage.Info.Heads == image.Info.Heads)
@@ -890,20 +976,19 @@ namespace DiscImageChef.Core
foreach(KeyValuePair<byte, IFilter> kvp in kfImage.tracks)
{
if(aborted) return;
if(aborted)
return;
BlockTrackType kfBlockTrackType = new BlockTrackType
var kfBlockTrackType = new BlockTrackType
{
Cylinder = kvp.Key / image.Info.Heads,
Head = (ushort)(kvp.Key % image.Info.Heads),
Cylinder = kvp.Key / image.Info.Heads, Head = (ushort)(kvp.Key % image.Info.Heads),
Image = new ImageType
{
format = kfImage.Format,
Value = kfDir
? Path
.Combine(Path.GetFileName(Path.GetDirectoryName(kvp.Value.GetBasePath())),
kvp.Value.GetFilename())
: kvp.Value.GetFilename(),
? Path.
Combine(Path.GetFileName(Path.GetDirectoryName(kvp.Value.GetBasePath())),
kvp.Value.GetFilename()) : kvp.Value.GetFilename(),
offset = 0
}
};
@@ -932,12 +1017,12 @@ namespace DiscImageChef.Core
kfBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray();
}
else
DicConsole
.ErrorWriteLine("KryoFlux image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
DicConsole.
ErrorWriteLine("KryoFlux image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
kfImage.Info.Cylinders, image.Info.Cylinders);
else
DicConsole
.ErrorWriteLine("KryoFluximage do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
DicConsole.
ErrorWriteLine("KryoFluximage do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
kfImage.Info.Heads, image.Info.Heads);
}
}
@@ -947,16 +1032,23 @@ namespace DiscImageChef.Core
string dfiFilePath = Path.Combine(Path.GetDirectoryName(imagePath),
Path.GetFileNameWithoutExtension(imagePath) + ".dfi");
if(aborted) return;
if(!File.Exists(dfiFilePath)) return;
if(aborted)
return;
DiscFerret dfiImage = new DiscFerret();
ZZZNoFilter dfiFilter = new ZZZNoFilter();
if(!File.Exists(dfiFilePath))
return;
var dfiImage = new DiscFerret();
var dfiFilter = new ZZZNoFilter();
dfiFilter.Open(dfiFilePath);
if(!dfiImage.Identify(dfiFilter)) return;
if(!dfiImage.Identify(dfiFilter))
return;
try { dfiImage.Open(dfiFilter); }
try
{
dfiImage.Open(dfiFilter);
}
catch(NotImplementedException) { }
UpdateStatus("Hashing DiscFerret image...");
@@ -970,13 +1062,16 @@ namespace DiscImageChef.Core
foreach(int t in dfiImage.TrackOffsets.Keys)
{
if(aborted) return;
if(aborted)
return;
BlockTrackType dfiBlockTrackType = new BlockTrackType
var dfiBlockTrackType = new BlockTrackType
{
Cylinder = (uint)(t / image.Info.Heads),
Head = (ushort)(t % image.Info.Heads),
Image = new ImageType {format = dfiImage.Format, Value = Path.GetFileName(dfiFilePath)}
Cylinder = (uint)(t / image.Info.Heads), Head = (ushort)(t % image.Info.Heads), Image =
new ImageType
{
format = dfiImage.Format, Value = Path.GetFileName(dfiFilePath)
}
};
if(dfiBlockTrackType.Cylinder < image.Info.Cylinders)
@@ -1007,12 +1102,12 @@ namespace DiscImageChef.Core
dfiBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray();
}
else
DicConsole
.ErrorWriteLine("DiscFerret image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
DicConsole.
ErrorWriteLine("DiscFerret image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
dfiImage.Info.Cylinders, image.Info.Cylinders);
else
DicConsole
.ErrorWriteLine("DiscFerret image do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
DicConsole.
ErrorWriteLine("DiscFerret image do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
dfiImage.Info.Heads, image.Info.Heads);
#endregion

View File

@@ -52,9 +52,7 @@ namespace DiscImageChef.Core
{
public partial class Sidecar
{
/// <summary>
/// Creates a metadata sidecar for an optical disc (e.g. CD, DVD, GD, BD, XGD, GOD)
/// </summary>
/// <summary>Creates a metadata sidecar for an optical disc (e.g. CD, DVD, GD, BD, XGD, GOD)</summary>
/// <param name="image">Image</param>
/// <param name="filterId">Filter uuid</param>
/// <param name="imagePath">Image path</param>
@@ -62,30 +60,29 @@ namespace DiscImageChef.Core
/// <param name="plugins">Image plugins</param>
/// <param name="imgChecksums">List of image checksums</param>
/// <param name="sidecar">Metadata sidecar</param>
void OpticalDisc(IOpticalMediaImage image, Guid filterId, string imagePath,
FileInfo fi, PluginBase plugins,
void OpticalDisc(IOpticalMediaImage image, Guid filterId, string imagePath, FileInfo fi, PluginBase plugins,
List<ChecksumType> imgChecksums, ref CICMMetadataType sidecar, Encoding encoding)
{
if(aborted) return;
if(aborted)
return;
sidecar.OpticalDisc = new[]
{
new OpticalDiscType
{
Checksums = imgChecksums.ToArray(),
Image = new ImageType
Checksums = imgChecksums.ToArray(), Image = new ImageType
{
format = image.Format,
offset = 0,
offsetSpecified = true,
Value = Path.GetFileName(imagePath)
format = image.Format, offset = 0, offsetSpecified = true, Value = Path.GetFileName(imagePath)
},
Size = (ulong)fi.Length,
Sequence = new SequenceType {MediaTitle = image.Info.MediaTitle}
Size = (ulong)fi.Length, Sequence = new SequenceType
{
MediaTitle = image.Info.MediaTitle
}
}
};
if(image.Info.MediaSequence != 0 && image.Info.LastMediaSequence != 0)
if(image.Info.MediaSequence != 0 &&
image.Info.LastMediaSequence != 0)
{
sidecar.OpticalDisc[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence;
sidecar.OpticalDisc[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence;
@@ -99,9 +96,11 @@ namespace DiscImageChef.Core
MediaType dskType = image.Info.MediaType;
UpdateStatus("Hashing media tags...");
foreach(MediaTagType tagType in image.Info.ReadableMediaTags)
{
if(aborted) return;
if(aborted)
return;
switch(tagType)
{
@@ -112,10 +111,15 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.CD_ATIP)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.CD_ATIP).Length
};
ATIP.CDATIP? atip = ATIP.Decode(image.ReadDiskTag(MediaTagType.CD_ATIP));
if(atip.HasValue)
if(atip.Value.DDCD) dskType = atip.Value.DiscType ? MediaType.DDCDRW : MediaType.DDCDR;
else dskType = atip.Value.DiscType ? MediaType.CDRW : MediaType.CDR;
if(atip.Value.DDCD)
dskType = atip.Value.DiscType ? MediaType.DDCDRW : MediaType.DDCDR;
else
dskType = atip.Value.DiscType ? MediaType.CDRW : MediaType.CDR;
break;
case MediaTagType.DVD_BCA:
sidecar.OpticalDisc[0].BCA = new DumpType
@@ -124,6 +128,7 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.DVD_BCA)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.DVD_BCA).Length
};
break;
case MediaTagType.BD_BCA:
sidecar.OpticalDisc[0].BCA = new DumpType
@@ -132,6 +137,7 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.BD_BCA)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.BD_BCA).Length
};
break;
case MediaTagType.DVD_CMI:
sidecar.OpticalDisc[0].CMI = new DumpType
@@ -140,19 +146,24 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.DVD_CMI)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.DVD_CMI).Length
};
CSS_CPRM.LeadInCopyright? cmi =
CSS_CPRM.DecodeLeadInCopyright(image.ReadDiskTag(MediaTagType.DVD_CMI));
if(cmi.HasValue)
switch(cmi.Value.CopyrightType)
{
case CopyrightType.AACS:
sidecar.OpticalDisc[0].CopyProtection = "AACS";
break;
case CopyrightType.CSS:
sidecar.OpticalDisc[0].CopyProtection = "CSS";
break;
case CopyrightType.CPRM:
sidecar.OpticalDisc[0].CopyProtection = "CPRM";
break;
}
@@ -164,15 +175,24 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.DVD_DMI)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.DVD_DMI).Length
};
if(DMI.IsXbox(image.ReadDiskTag(MediaTagType.DVD_DMI)))
{
dskType = MediaType.XGD;
sidecar.OpticalDisc[0].Dimensions = new DimensionsType {Diameter = 120, Thickness = 1.2};
sidecar.OpticalDisc[0].Dimensions = new DimensionsType
{
Diameter = 120, Thickness = 1.2
};
}
else if(DMI.IsXbox360(image.ReadDiskTag(MediaTagType.DVD_DMI)))
{
dskType = MediaType.XGD2;
sidecar.OpticalDisc[0].Dimensions = new DimensionsType {Diameter = 120, Thickness = 1.2};
sidecar.OpticalDisc[0].Dimensions = new DimensionsType
{
Diameter = 120, Thickness = 1.2
};
}
break;
@@ -183,65 +203,91 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.DVD_PFI)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.DVD_PFI).Length
};
PFI.PhysicalFormatInformation? pfi = PFI.Decode(image.ReadDiskTag(MediaTagType.DVD_PFI));
if(pfi.HasValue)
if(dskType != MediaType.XGD && dskType != MediaType.XGD2 &&
if(dskType != MediaType.XGD &&
dskType != MediaType.XGD2 &&
dskType != MediaType.XGD3 &&
dskType != MediaType.PS2DVD && dskType != MediaType.PS3DVD && dskType != MediaType.Nuon)
dskType != MediaType.PS2DVD &&
dskType != MediaType.PS3DVD &&
dskType != MediaType.Nuon)
{
switch(pfi.Value.DiskCategory)
{
case DiskCategory.DVDPR:
dskType = MediaType.DVDPR;
break;
case DiskCategory.DVDPRDL:
dskType = MediaType.DVDPRDL;
break;
case DiskCategory.DVDPRW:
dskType = MediaType.DVDPRW;
break;
case DiskCategory.DVDPRWDL:
dskType = MediaType.DVDPRWDL;
break;
case DiskCategory.DVDR:
dskType = MediaType.DVDR;
break;
case DiskCategory.DVDRAM:
dskType = MediaType.DVDRAM;
break;
case DiskCategory.DVDROM:
dskType = MediaType.DVDROM;
break;
case DiskCategory.DVDRW:
dskType = MediaType.DVDRW;
break;
case DiskCategory.HDDVDR:
dskType = MediaType.HDDVDR;
break;
case DiskCategory.HDDVDRAM:
dskType = MediaType.HDDVDRAM;
break;
case DiskCategory.HDDVDROM:
dskType = MediaType.HDDVDROM;
break;
case DiskCategory.HDDVDRW:
dskType = MediaType.HDDVDRW;
break;
case DiskCategory.Nintendo:
dskType = MediaType.GOD;
break;
case DiskCategory.UMD:
dskType = MediaType.UMD;
break;
}
if(dskType == MediaType.DVDR && pfi.Value.PartVersion == 6) dskType = MediaType.DVDRDL;
if(dskType == MediaType.DVDRW && pfi.Value.PartVersion == 3)
if(dskType == MediaType.DVDR &&
pfi.Value.PartVersion == 6)
dskType = MediaType.DVDRDL;
if(dskType == MediaType.DVDRW &&
pfi.Value.PartVersion == 3)
dskType = MediaType.DVDRWDL;
if(dskType == MediaType.GOD && pfi.Value.DiscSize == DVDSize.OneTwenty)
if(dskType == MediaType.GOD &&
pfi.Value.DiscSize == DVDSize.OneTwenty)
dskType = MediaType.WOD;
sidecar.OpticalDisc[0].Dimensions = new DimensionsType();
if(dskType == MediaType.UMD)
{
sidecar.OpticalDisc[0].Dimensions.Height = 64;
@@ -257,11 +303,13 @@ namespace DiscImageChef.Core
sidecar.OpticalDisc[0].Dimensions.Diameter = 80;
sidecar.OpticalDisc[0].Dimensions.DiameterSpecified = true;
sidecar.OpticalDisc[0].Dimensions.Thickness = 1.2;
break;
case DVDSize.OneTwenty:
sidecar.OpticalDisc[0].Dimensions.Diameter = 120;
sidecar.OpticalDisc[0].Dimensions.DiameterSpecified = true;
sidecar.OpticalDisc[0].Dimensions.Thickness = 1.2;
break;
}
}
@@ -274,6 +322,7 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.CD_PMA)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.CD_PMA).Length
};
break;
case MediaTagType.CD_FullTOC:
sidecar.OpticalDisc[0].TOC = new DumpType
@@ -282,6 +331,7 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.CD_FullTOC)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.CD_FullTOC).Length
};
break;
case MediaTagType.CD_FirstTrackPregap:
sidecar.OpticalDisc[0].FirstTrackPregrap = new[]
@@ -289,12 +339,12 @@ namespace DiscImageChef.Core
new BorderType
{
Image = Path.GetFileName(imagePath),
Checksums = Checksum
.GetChecksums(image.ReadDiskTag(MediaTagType.CD_FirstTrackPregap))
.ToArray(),
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.CD_FirstTrackPregap)).
ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.CD_FirstTrackPregap).Length
}
};
break;
case MediaTagType.CD_LeadIn:
sidecar.OpticalDisc[0].LeadIn = new[]
@@ -302,29 +352,26 @@ namespace DiscImageChef.Core
new BorderType
{
Image = Path.GetFileName(imagePath),
Checksums = Checksum
.GetChecksums(image.ReadDiskTag(MediaTagType.CD_LeadIn)).ToArray(),
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.CD_LeadIn)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.CD_LeadIn).Length
}
};
break;
case MediaTagType.Xbox_SecuritySector:
if(sidecar.OpticalDisc[0].Xbox == null) sidecar.OpticalDisc[0].Xbox = new XboxType();
if(sidecar.OpticalDisc[0].Xbox == null)
sidecar.OpticalDisc[0].Xbox = new XboxType();
sidecar.OpticalDisc[0].Xbox.SecuritySectors = new[]
{
new XboxSecuritySectorsType
{
RequestNumber = 0,
RequestVersion = 1,
SecuritySectors = new DumpType
RequestNumber = 0, RequestVersion = 1, SecuritySectors = new DumpType
{
Image = Path.GetFileName(imagePath),
Checksums =
Checksum
.GetChecksums(image.ReadDiskTag(MediaTagType
.Xbox_SecuritySector))
.ToArray(),
Checksums = Checksum.
GetChecksums(image.ReadDiskTag(MediaTagType.Xbox_SecuritySector)).
ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.Xbox_SecuritySector).Length
}
}
@@ -332,7 +379,8 @@ namespace DiscImageChef.Core
break;
case MediaTagType.Xbox_PFI:
if(sidecar.OpticalDisc[0].Xbox == null) sidecar.OpticalDisc[0].Xbox = new XboxType();
if(sidecar.OpticalDisc[0].Xbox == null)
sidecar.OpticalDisc[0].Xbox = new XboxType();
sidecar.OpticalDisc[0].Xbox.PFI = new DumpType
{
@@ -340,9 +388,11 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.Xbox_PFI)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.Xbox_PFI).Length
};
break;
case MediaTagType.Xbox_DMI:
if(sidecar.OpticalDisc[0].Xbox == null) sidecar.OpticalDisc[0].Xbox = new XboxType();
if(sidecar.OpticalDisc[0].Xbox == null)
sidecar.OpticalDisc[0].Xbox = new XboxType();
sidecar.OpticalDisc[0].Xbox.DMI = new DumpType
{
@@ -350,6 +400,7 @@ namespace DiscImageChef.Core
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.Xbox_DMI)).ToArray(),
Size = (ulong)image.ReadDiskTag(MediaTagType.Xbox_DMI).Length
};
break;
}
}
@@ -359,10 +410,14 @@ namespace DiscImageChef.Core
List<Session> sessions = image.Sessions;
sidecar.OpticalDisc[0].Sessions = (uint)(sessions?.Count ?? 1);
}
catch { sidecar.OpticalDisc[0].Sessions = 1; }
catch
{
sidecar.OpticalDisc[0].Sessions = 1;
}
List<Track> tracks = image.Tracks;
List<TrackType> trksLst = null;
if(tracks != null)
{
sidecar.OpticalDisc[0].Tracks = new uint[1];
@@ -370,10 +425,12 @@ namespace DiscImageChef.Core
trksLst = new List<TrackType>();
}
if(sidecar.OpticalDisc[0].Dimensions == null && image.Info.MediaType != MediaType.Unknown)
if(sidecar.OpticalDisc[0].Dimensions == null &&
image.Info.MediaType != MediaType.Unknown)
sidecar.OpticalDisc[0].Dimensions = Dimensions.DimensionsFromMediaType(image.Info.MediaType);
if(aborted) return;
if(aborted)
return;
InitProgress();
@@ -382,61 +439,78 @@ namespace DiscImageChef.Core
Partitions.AddSchemesToStats(partitions);
UpdateStatus("Hashing tracks...");
foreach(Track trk in tracks)
{
if(aborted)
{
EndProgress();
return;
}
TrackType xmlTrk = new TrackType();
var xmlTrk = new TrackType();
switch(trk.TrackType)
{
case CommonTypes.Enums.TrackType.Audio:
xmlTrk.TrackType1 = TrackTypeTrackType.audio;
break;
case CommonTypes.Enums.TrackType.CdMode2Form2:
xmlTrk.TrackType1 = TrackTypeTrackType.m2f2;
break;
case CommonTypes.Enums.TrackType.CdMode2Formless:
xmlTrk.TrackType1 = TrackTypeTrackType.mode2;
break;
case CommonTypes.Enums.TrackType.CdMode2Form1:
xmlTrk.TrackType1 = TrackTypeTrackType.m2f1;
break;
case CommonTypes.Enums.TrackType.CdMode1:
xmlTrk.TrackType1 = TrackTypeTrackType.mode1;
break;
case CommonTypes.Enums.TrackType.Data:
switch(sidecar.OpticalDisc[0].DiscType)
{
case"BD":
xmlTrk.TrackType1 = TrackTypeTrackType.bluray;
break;
case"DDCD":
xmlTrk.TrackType1 = TrackTypeTrackType.ddcd;
break;
case"DVD":
xmlTrk.TrackType1 = TrackTypeTrackType.dvd;
break;
case"HD DVD":
xmlTrk.TrackType1 = TrackTypeTrackType.hddvd;
break;
default:
xmlTrk.TrackType1 = TrackTypeTrackType.mode1;
break;
}
break;
}
xmlTrk.Sequence =
new TrackSequenceType {Session = trk.TrackSession, TrackNumber = trk.TrackSequence};
xmlTrk.Sequence = new TrackSequenceType
{
Session = trk.TrackSession, TrackNumber = trk.TrackSequence
};
xmlTrk.StartSector = trk.TrackStartSector;
xmlTrk.EndSector = trk.TrackEndSector;
if(trk.Indexes != null && trk.Indexes.ContainsKey(0))
if(trk.Indexes != null &&
trk.Indexes.ContainsKey(0))
if(trk.Indexes.TryGetValue(0, out ulong idx0))
xmlTrk.StartSector = idx0;
@@ -446,14 +520,19 @@ namespace DiscImageChef.Core
case"GD":
xmlTrk.StartMSF = LbaToMsf((long)xmlTrk.StartSector);
xmlTrk.EndMSF = LbaToMsf((long)xmlTrk.EndSector);
break;
case"DDCD":
xmlTrk.StartMSF = DdcdLbaToMsf((long)xmlTrk.StartSector);
xmlTrk.EndMSF = DdcdLbaToMsf((long)xmlTrk.EndSector);
break;
}
xmlTrk.Image = new ImageType {Value = Path.GetFileName(trk.TrackFile), format = trk.TrackFileType};
xmlTrk.Image = new ImageType
{
Value = Path.GetFileName(trk.TrackFile), format = trk.TrackFileType
};
if(trk.TrackFileOffset > 0)
{
@@ -470,8 +549,10 @@ namespace DiscImageChef.Core
// If there is only one track, and it's the same as the image file (e.g. ".iso" files), don't re-checksum.
if(image.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000") &&
// Only if filter is none...
(filterId == new Guid("12345678-AAAA-BBBB-CCCC-123456789000") ||
// ...or AppleDouble
filterId == new Guid("1b2165ee-c9df-4b21-bbbb-9e5892b2df4d")))
xmlTrk.Checksums = sidecar.OpticalDisc[0].Checksums;
@@ -482,15 +563,17 @@ namespace DiscImageChef.Core
// For fast debugging, skip checksum
//goto skipChecksum;
Checksum trkChkWorker = new Checksum();
var trkChkWorker = new Checksum();
InitProgress2();
while(doneSectors < sectors)
{
if(aborted)
{
EndProgress();
EndProgress2();
return;
}
@@ -499,16 +582,20 @@ namespace DiscImageChef.Core
if(sectors - doneSectors >= sectorsToRead)
{
sector = image.ReadSectorsLong(doneSectors, sectorsToRead, xmlTrk.Sequence.TrackNumber);
UpdateProgress2("Hashings sector {0} of {1}", (long)doneSectors,
(long)(trk.TrackEndSector - trk.TrackStartSector + 1));
doneSectors += sectorsToRead;
}
else
{
sector = image.ReadSectorsLong(doneSectors, (uint)(sectors - doneSectors),
xmlTrk.Sequence.TrackNumber);
UpdateProgress2("Hashings sector {0} of {1}", (long)doneSectors,
(long)(trk.TrackEndSector - trk.TrackStartSector + 1));
doneSectors += sectors - doneSectors;
}
@@ -526,7 +613,11 @@ namespace DiscImageChef.Core
{
xmlTrk.SubChannel = new SubChannelType
{
Image = new ImageType {Value = trk.TrackSubchannelFile},
Image = new ImageType
{
Value = trk.TrackSubchannelFile
},
// TODO: Packed subchannel has different size?
Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * 96
};
@@ -536,14 +627,17 @@ namespace DiscImageChef.Core
case TrackSubchannelType.Packed:
case TrackSubchannelType.PackedInterleaved:
xmlTrk.SubChannel.Image.format = "rw";
break;
case TrackSubchannelType.Raw:
case TrackSubchannelType.RawInterleaved:
xmlTrk.SubChannel.Image.format = "rw_raw";
break;
case TrackSubchannelType.Q16:
case TrackSubchannelType.Q16Interleaved:
xmlTrk.SubChannel.Image.format = "q16";
break;
}
@@ -553,18 +647,20 @@ namespace DiscImageChef.Core
xmlTrk.SubChannel.Image.offsetSpecified = true;
}
Checksum subChkWorker = new Checksum();
var subChkWorker = new Checksum();
sectors = xmlTrk.EndSector - xmlTrk.StartSector + 1;
doneSectors = 0;
InitProgress2();
while(doneSectors < sectors)
{
if(aborted)
{
EndProgress();
EndProgress2();
return;
}
@@ -574,8 +670,10 @@ namespace DiscImageChef.Core
{
sector = image.ReadSectorsTag(doneSectors, sectorsToRead, xmlTrk.Sequence.TrackNumber,
SectorTagType.CdSectorSubchannel);
UpdateProgress2("Hashings subchannel sector {0} of {1}", (long)doneSectors,
(long)(trk.TrackEndSector - trk.TrackStartSector + 1));
doneSectors += sectorsToRead;
}
else
@@ -583,8 +681,10 @@ namespace DiscImageChef.Core
sector = image.ReadSectorsTag(doneSectors, (uint)(sectors - doneSectors),
xmlTrk.Sequence.TrackNumber,
SectorTagType.CdSectorSubchannel);
UpdateProgress2("Hashings subchannel sector {0} of {1}", (long)doneSectors,
(long)(trk.TrackEndSector - trk.TrackStartSector + 1));
doneSectors += sectors - doneSectors;
}
@@ -601,25 +701,25 @@ namespace DiscImageChef.Core
// For fast debugging, skip checksum
//skipChecksum:
List<Partition> trkPartitions = partitions
.Where(p => p.Start >= trk.TrackStartSector &&
List<Partition> trkPartitions = partitions.
Where(p => p.Start >= trk.TrackStartSector &&
p.End <= trk.TrackEndSector).ToList();
xmlTrk.FileSystemInformation = new PartitionType[1];
if(trkPartitions.Count > 0)
{
xmlTrk.FileSystemInformation = new PartitionType[trkPartitions.Count];
for(int i = 0; i < trkPartitions.Count; i++)
{
xmlTrk.FileSystemInformation[i] = new PartitionType
{
Description = trkPartitions[i].Description,
EndSector = trkPartitions[i].End,
Name = trkPartitions[i].Name,
Sequence = (uint)trkPartitions[i].Sequence,
StartSector = trkPartitions[i].Start,
Type = trkPartitions[i].Type
Description = trkPartitions[i].Description, EndSector = trkPartitions[i].End,
Name = trkPartitions[i].Name, Sequence = (uint)trkPartitions[i].Sequence,
StartSector = trkPartitions[i].Start, Type = trkPartitions[i].Type
};
List<FileSystemType> lstFs = new List<FileSystemType>();
foreach(IFilesystem plugin in plugins.PluginsList.Values)
@@ -628,10 +728,12 @@ namespace DiscImageChef.Core
if(aborted)
{
EndProgress();
return;
}
if(!plugin.Identify(image, trkPartitions[i])) continue;
if(!plugin.Identify(image, trkPartitions[i]))
continue;
plugin.GetInformation(image, trkPartitions[i], out _, encoding);
lstFs.Add(plugin.XmlFsType);
@@ -641,15 +743,19 @@ namespace DiscImageChef.Core
{
case"Opera":
dskType = MediaType.ThreeDO;
break;
case"PC Engine filesystem":
dskType = MediaType.SuperCDROM2;
break;
case"Nintendo Wii filesystem":
dskType = MediaType.WOD;
break;
case"Nintendo Gamecube filesystem":
dskType = MediaType.GOD;
break;
}
}
@@ -660,7 +766,8 @@ namespace DiscImageChef.Core
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
if(lstFs.Count > 0) xmlTrk.FileSystemInformation[i].FileSystems = lstFs.ToArray();
if(lstFs.Count > 0)
xmlTrk.FileSystemInformation[i].FileSystems = lstFs.ToArray();
}
}
else
@@ -669,26 +776,27 @@ namespace DiscImageChef.Core
{
EndSector = xmlTrk.EndSector, StartSector = xmlTrk.StartSector
};
List<FileSystemType> lstFs = new List<FileSystemType>();
Partition xmlPart = new Partition
var xmlPart = new Partition
{
Start = xmlTrk.StartSector,
Length = xmlTrk.EndSector - xmlTrk.StartSector + 1,
Type = xmlTrk.TrackType1.ToString(),
Size = xmlTrk.Size,
Sequence = xmlTrk.Sequence.TrackNumber
Start = xmlTrk.StartSector, Length = xmlTrk.EndSector - xmlTrk.StartSector + 1,
Type = xmlTrk.TrackType1.ToString(), Size = xmlTrk.Size, Sequence = xmlTrk.Sequence.TrackNumber
};
foreach(IFilesystem plugin in plugins.PluginsList.Values)
try
{
if(aborted)
{
EndProgress();
return;
}
if(!plugin.Identify(image, xmlPart)) continue;
if(!plugin.Identify(image, xmlPart))
continue;
plugin.GetInformation(image, xmlPart, out _, encoding);
lstFs.Add(plugin.XmlFsType);
@@ -698,15 +806,19 @@ namespace DiscImageChef.Core
{
case"Opera":
dskType = MediaType.ThreeDO;
break;
case"PC Engine filesystem":
dskType = MediaType.SuperCDROM2;
break;
case"Nintendo Wii filesystem":
dskType = MediaType.WOD;
break;
case"Nintendo Gamecube filesystem":
dskType = MediaType.GOD;
break;
}
}
@@ -717,7 +829,8 @@ namespace DiscImageChef.Core
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
if(lstFs.Count > 0) xmlTrk.FileSystemInformation[0].FileSystems = lstFs.ToArray();
if(lstFs.Count > 0)
xmlTrk.FileSystemInformation[0].FileSystems = lstFs.ToArray();
}
trksLst.Add(xmlTrk);
@@ -725,25 +838,29 @@ namespace DiscImageChef.Core
EndProgress();
if(trksLst != null) sidecar.OpticalDisc[0].Track = trksLst.ToArray();
if(trksLst != null)
sidecar.OpticalDisc[0].Track = trksLst.ToArray();
// All XGD3 all have the same number of blocks
if(dskType == MediaType.XGD2 && sidecar.OpticalDisc[0].Track.Length == 1)
if(dskType == MediaType.XGD2 &&
sidecar.OpticalDisc[0].Track.Length == 1)
{
ulong blocks = sidecar.OpticalDisc[0].Track[0].EndSector - sidecar.OpticalDisc[0].Track[0].StartSector +
1;
if(blocks == 25063 || // Locked (or non compatible drive)
blocks == 4229664 || // Xtreme unlock
blocks == 4246304) // Wxripper unlock
dskType = MediaType.XGD3;
}
CommonTypes.Metadata.MediaType.MediaTypeToString(dskType, out string dscType, out string dscSubType);
sidecar.OpticalDisc[0].DiscType = dscType;
sidecar.OpticalDisc[0].DiscSubType = dscSubType;
(string type, string subType) discType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType);
sidecar.OpticalDisc[0].DiscType = discType.type;
sidecar.OpticalDisc[0].DiscSubType = discType.subType;
Statistics.AddMedia(dskType, false);
if(image.DumpHardware != null) sidecar.OpticalDisc[0].DumpHardwareArray = image.DumpHardware.ToArray();
if(image.DumpHardware != null)
sidecar.OpticalDisc[0].DumpHardwareArray = image.DumpHardware.ToArray();
else if(!string.IsNullOrEmpty(image.Info.DriveManufacturer) ||
!string.IsNullOrEmpty(image.Info.DriveModel) ||
!string.IsNullOrEmpty(image.Info.DriveFirmwareRevision) ||
@@ -752,12 +869,17 @@ namespace DiscImageChef.Core
{
new DumpHardwareType
{
Extents = new[] {new ExtentType {Start = 0, End = image.Info.Sectors}},
Manufacturer = image.Info.DriveManufacturer,
Model = image.Info.DriveModel,
Firmware = image.Info.DriveFirmwareRevision,
Serial = image.Info.DriveSerialNumber,
Software = new SoftwareType
Extents = new[]
{
new ExtentType
{
Start = 0, End = image.Info.Sectors
}
},
Manufacturer = image.Info.DriveManufacturer, Model = image.Info.DriveModel,
Firmware = image.Info.DriveFirmwareRevision, Serial = image.Info.DriveSerialNumber,
Software =
new SoftwareType
{
Name = image.Info.Application, Version = image.Info.ApplicationVersion
}