diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml
index 484e03fbd..20ad456dc 100644
--- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml
+++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml
@@ -235,6 +235,7 @@
+
diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs
index 5bd21a5f6..d6faa5977 100644
--- a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs
+++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs
@@ -1645,111 +1645,9 @@ namespace DiscImageChef.Core.Devices.Dumping
EndProgress?.Invoke();
// TODO: Enable when underlying images support lead-outs
- /*
- if(persistent)
- {
- UpdateStatus?.Invoke("Reading lead-outs");
- dumpLog.WriteLine("Reading lead-outs");
-
- InitProgress?.Invoke();
- foreach(Tuple leadout in leadOutExtents.ToArray())
- for(ulong i = leadout.Item1; i <= leadout.Item2; i++)
- {
- if(aborted)
- {
- currentTry.Extents = ExtentsConverter.ToMetadata(extents);
- dumpLog.WriteLine("Aborted!");
- break;
- }
-
- double cmdDuration = 0;
-
- #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;
- #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
-
- PulseProgress?.Invoke(string.Format("Reading sector {0} at lead-out ({1:F3} MiB/sec.)", i, blocks,
- currentSpeed));
-
- if(readcd)
- {
- sense = dev.ReadCd(out cmdBuf, out senseBuf, (uint)i, blockSize, 1,
- MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
- true, true, MmcErrorField.None, supportedSubchannel, dev.Timeout,
- out cmdDuration);
- totalDuration += cmdDuration;
- }
- else if(read16)
- sense = dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i, blockSize, 0, 1,
- false, dev.Timeout, out cmdDuration);
- else if(read12)
- sense = dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i,
- blockSize, 0, 1, false, dev.Timeout, out cmdDuration);
- else if(read10)
- sense = dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i,
- blockSize, 0, 1, dev.Timeout, out cmdDuration);
- else if(read6)
- sense = dev.Read6(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, dev.Timeout,
- out cmdDuration);
-
- if(!sense && !dev.Error)
- {
- mhddLog.Write(i, cmdDuration);
- ibgLog.Write(i, currentSpeed * 1024);
- extents.Add(i, blocksToRead, true);
- leadOutExtents.Remove(i);
- DateTime writeStart = DateTime.Now;
- if(supportedSubchannel != MmcSubchannel.None)
- {
- byte[] data = new byte[SECTOR_SIZE * blocksToRead];
- byte[] sub = new byte[subSize * blocksToRead];
-
- for(int b = 0; b < blocksToRead; b++)
- {
- Array.Copy(cmdBuf, (int)(0 + b * blockSize), data, SECTOR_SIZE * b,
- SECTOR_SIZE);
- Array.Copy(cmdBuf, (int)(SECTOR_SIZE + b * blockSize), sub, subSize * b,
- subSize);
- }
-
- outputPlugin.WriteSectorsLong(data, i, blocksToRead);
- outputPlugin.WriteSectorsTag(sub, i, blocksToRead, SectorTagType.CdSectorSubchannel);
- }
- else outputPlugin.WriteSectors(cmdBuf, i, blocksToRead);
-
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
- }
- else
- {
- // TODO: Reset device after X errors
- if(stopOnError) return; // TODO: Return more cleanly
-
- // Write empty data
- DateTime writeStart = DateTime.Now;
- if(supportedSubchannel != MmcSubchannel.None)
- {
- outputPlugin.WriteSectorsLong(new byte[SECTOR_SIZE * skip], i, 1);
- outputPlugin.WriteSectorsTag(new byte[subSize * skip], i, 1,
- SectorTagType.CdSectorSubchannel);
- }
- else outputPlugin.WriteSectors(new byte[blockSize * skip], i, 1);
-
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
-
- mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
-
- ibgLog.Write(i, 0);
- }
-
- double newSpeed =
- (double)blockSize * blocksToRead / 1048576 / (cmdDuration / 1000);
- if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed;
- resume.NextBlock = i + 1;
- }
-
- EndProgress?.Invoke();
- }*/
+ DumpCdLeadOuts(blocks, blockSize, ref currentSpeed, currentTry, extents, ibgLog, ref imageWriteDuration,
+ leadOutExtents, ref maxSpeed, mhddLog, ref minSpeed, read6, read10, read12, read16, readcd,
+ supportedSubchannel, subSize, ref totalDuration);
end = DateTime.UtcNow;
mhddLog.Close();
diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc/LeadOuts.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc/LeadOuts.cs
new file mode 100644
index 000000000..6b7f18878
--- /dev/null
+++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc/LeadOuts.cs
@@ -0,0 +1,198 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : CompactDisc.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Core algorithms.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Dumps CDs and DDCDs.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2019 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using DiscImageChef.CommonTypes.Enums;
+using DiscImageChef.CommonTypes.Extents;
+using DiscImageChef.Core.Logging;
+using DiscImageChef.Devices;
+using Schemas;
+
+// ReSharper disable JoinDeclarationAndInitializer
+// ReSharper disable InlineOutVariableDeclaration
+// ReSharper disable TooWideLocalVariableScope
+
+namespace DiscImageChef.Core.Devices.Dumping
+{
+ partial class Dump
+ {
+ ///
+ /// Total number of positive sectors
+ /// Size of the read sector in bytes
+ /// Current read speed
+ /// Current dump hardware try
+ /// Extents
+ /// IMGBurn log
+ /// Duration of image write
+ /// Lead-out extents
+ /// Maximum speed
+ /// MHDD log
+ /// Minimum speed
+ /// Device supports READ(6)
+ /// Device supports READ(10)
+ /// Device supports READ(12)
+ /// Device supports READ(16)
+ /// Device supports READ CD
+ /// Drive's maximum supported subchannel
+ /// Subchannel size in bytes
+ /// Total commands duration
+ void DumpCdLeadOuts(ulong blocks, uint blockSize, ref double currentSpeed, DumpHardwareType currentTry,
+ ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration,
+ ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog, ref double minSpeed,
+ bool read6, bool read10, bool read12, bool read16, bool readcd,
+ MmcSubchannel supportedSubchannel, uint subSize, ref double totalDuration)
+ {
+ byte[] cmdBuf = null; // Data buffer
+ const uint sectorSize = 2352; // Full sector size
+ bool sense = true; // Sense indicator
+
+ UpdateStatus?.Invoke("Reading lead-outs");
+ _dumpLog.WriteLine("Reading lead-outs");
+
+ InitProgress?.Invoke();
+
+ foreach((ulong item1, ulong item2) in leadOutExtents.ToArray())
+ for(ulong i = item1; i <= item2; i++)
+ {
+ if(_aborted)
+ {
+ currentTry.Extents = ExtentsConverter.ToMetadata(extents);
+ _dumpLog.WriteLine("Aborted!");
+
+ break;
+ }
+
+ double cmdDuration = 0;
+
+ #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
+
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ if(currentSpeed > maxSpeed &&
+ currentSpeed != 0)
+ maxSpeed = currentSpeed;
+
+ if(currentSpeed < minSpeed &&
+ currentSpeed != 0)
+ minSpeed = currentSpeed;
+
+ // ReSharper restore CompareOfFloatsByEqualityOperator
+ #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
+
+ PulseProgress?.Invoke($"Reading sector {i} at lead-out ({currentSpeed:F3} MiB/sec.)");
+
+ if(readcd)
+ {
+ sense = _dev.ReadCd(out cmdBuf, out _, (uint)i, blockSize, 1, MmcSectorTypes.AllTypes, false,
+ false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
+ supportedSubchannel, _dev.Timeout, out cmdDuration);
+
+ totalDuration += cmdDuration;
+ }
+ else if(read16)
+ sense = _dev.Read16(out cmdBuf, out _, 0, false, true, false, i, blockSize, 0, 1, false,
+ _dev.Timeout, out cmdDuration);
+ else if(read12)
+ sense = _dev.Read12(out cmdBuf, out _, 0, false, true, false, false, (uint)i, blockSize, 0, 1,
+ false, _dev.Timeout, out cmdDuration);
+ else if(read10)
+ sense = _dev.Read10(out cmdBuf, out _, 0, false, true, false, false, (uint)i, blockSize, 0, 1,
+ _dev.Timeout, out cmdDuration);
+ else if(read6)
+ sense = _dev.Read6(out cmdBuf, out _, (uint)i, blockSize, 1, _dev.Timeout, out cmdDuration);
+
+ if(!sense &&
+ !_dev.Error)
+ {
+ mhddLog.Write(i, cmdDuration);
+ ibgLog.Write(i, currentSpeed * 1024);
+ extents.Add(i, _maximumReadable, true);
+ leadOutExtents.Remove(i);
+ DateTime writeStart = DateTime.Now;
+
+ if(supportedSubchannel != MmcSubchannel.None)
+ {
+ byte[] data = new byte[sectorSize * _maximumReadable];
+ byte[] sub = new byte[subSize * _maximumReadable];
+
+ for(int b = 0; b < _maximumReadable; b++)
+ {
+ Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
+
+ Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
+ }
+
+ _outputPlugin.WriteSectorsLong(data, i, _maximumReadable);
+ _outputPlugin.WriteSectorsTag(sub, i, _maximumReadable, SectorTagType.CdSectorSubchannel);
+ }
+ else
+ _outputPlugin.WriteSectors(cmdBuf, i, _maximumReadable);
+
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+ }
+ else
+ {
+ // TODO: Reset device after X errors
+ if(_stopOnError)
+ return; // TODO: Return more cleanly
+
+ // Write empty data
+ DateTime writeStart = DateTime.Now;
+
+ if(supportedSubchannel != MmcSubchannel.None)
+ {
+ _outputPlugin.WriteSectorsLong(new byte[sectorSize * _skip], i, 1);
+
+ _outputPlugin.WriteSectorsTag(new byte[subSize * _skip], i, 1,
+ SectorTagType.CdSectorSubchannel);
+ }
+ else
+ _outputPlugin.WriteSectors(new byte[blockSize * _skip], i, 1);
+
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+
+ mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
+
+ ibgLog.Write(i, 0);
+ }
+
+ double newSpeed = ((double)blockSize * _maximumReadable) / 1048576 / (cmdDuration / 1000);
+
+ if(!double.IsInfinity(newSpeed))
+ currentSpeed = newSpeed;
+
+ _resume.NextBlock = i + 1;
+ }
+
+ EndProgress?.Invoke();
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscImageChef.Core/DiscImageChef.Core.csproj b/DiscImageChef.Core/DiscImageChef.Core.csproj
index faa12d05d..0b65444b4 100644
--- a/DiscImageChef.Core/DiscImageChef.Core.csproj
+++ b/DiscImageChef.Core/DiscImageChef.Core.csproj
@@ -48,6 +48,7 @@
+