diff --git a/Aaru.Compression/ADC.cs b/Aaru.Compression/ADC.cs
index d0884e7ae..cff6f5008 100644
--- a/Aaru.Compression/ADC.cs
+++ b/Aaru.Compression/ADC.cs
@@ -39,149 +39,148 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-namespace Aaru.Compression
+namespace Aaru.Compression;
+
+/// Implements the Apple version of RLE
+public static class ADC
{
- /// Implements the Apple version of RLE
- public static class ADC
+ ///
+ /// Set to true if this algorithm is supported, false otherwise.
+ ///
+ public static bool IsSupported => true;
+
+ [DllImport("libAaru.Compression.Native", SetLastError = true)]
+ static extern int AARU_adc_decode_buffer(byte[] dst_buffer, int dst_size, byte[] src_buffer, int src_size);
+
+ const int PLAIN = 1;
+ const int TWO_BYTE = 2;
+ const int THREE_BYTE = 3;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static int GetChunkType(byte byt) => (byt & 0x80) == 0x80
+ ? PLAIN
+ : (byt & 0x40) == 0x40
+ ? THREE_BYTE
+ : TWO_BYTE;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static int GetChunkSize(byte byt) => GetChunkType(byt) switch
{
- ///
- /// Set to true if this algorithm is supported, false otherwise.
- ///
- public static bool IsSupported => true;
+ PLAIN => (byt & 0x7F) + 1,
+ TWO_BYTE => ((byt & 0x3F) >> 2) + 3,
+ THREE_BYTE => (byt & 0x3F) + 4,
+ _ => -1
+ };
- [DllImport("libAaru.Compression.Native", SetLastError = true)]
- static extern int AARU_adc_decode_buffer(byte[] dst_buffer, int dst_size, byte[] src_buffer, int src_size);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static int GetOffset(ReadOnlySpan chunk) => GetChunkType(chunk[0]) switch
+ {
+ PLAIN => 0,
+ TWO_BYTE => ((chunk[0] & 0x03) << 8) + chunk[1],
+ THREE_BYTE => (chunk[1] << 8) + chunk[2],
+ _ => -1
+ };
- const int PLAIN = 1;
- const int TWO_BYTE = 2;
- const int THREE_BYTE = 3;
+ /// Decompresses a byte buffer that's compressed with ADC
+ /// Compressed buffer
+ /// Buffer to hold decompressed data
+ /// How many bytes are stored on
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
+ public static int DecodeBuffer(byte[] source, byte[] destination)
+ {
+ if(Native.IsSupported)
+ return AARU_adc_decode_buffer(destination, destination.Length, source, source.Length);
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int GetChunkType(byte byt) => (byt & 0x80) == 0x80
- ? PLAIN
- : (byt & 0x40) == 0x40
- ? THREE_BYTE
- : TWO_BYTE;
+ int inputPosition = 0;
+ int chunkSize;
+ int offset;
+ int chunkType;
+ int outPosition = 0;
+ Span temp = stackalloc byte[3];
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int GetChunkSize(byte byt) => GetChunkType(byt) switch
+ while(inputPosition < source.Length)
{
- PLAIN => (byt & 0x7F) + 1,
- TWO_BYTE => ((byt & 0x3F) >> 2) + 3,
- THREE_BYTE => (byt & 0x3F) + 4,
- _ => -1
- };
+ byte readByte = source[inputPosition++];
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int GetOffset(ReadOnlySpan chunk) => GetChunkType(chunk[0]) switch
- {
- PLAIN => 0,
- TWO_BYTE => ((chunk[0] & 0x03) << 8) + chunk[1],
- THREE_BYTE => (chunk[1] << 8) + chunk[2],
- _ => -1
- };
+ chunkType = GetChunkType(readByte);
- /// Decompresses a byte buffer that's compressed with ADC
- /// Compressed buffer
- /// Buffer to hold decompressed data
- /// How many bytes are stored on
- [MethodImpl(MethodImplOptions.AggressiveOptimization)]
- public static int DecodeBuffer(byte[] source, byte[] destination)
- {
- if(Native.IsSupported)
- return AARU_adc_decode_buffer(destination, destination.Length, source, source.Length);
-
- int inputPosition = 0;
- int chunkSize;
- int offset;
- int chunkType;
- int outPosition = 0;
- Span temp = stackalloc byte[3];
-
- while(inputPosition < source.Length)
+ switch(chunkType)
{
- byte readByte = source[inputPosition++];
+ case PLAIN:
+ chunkSize = GetChunkSize(readByte);
- chunkType = GetChunkType(readByte);
+ if(outPosition + chunkSize > destination.Length)
+ goto finished;
- switch(chunkType)
- {
- case PLAIN:
- chunkSize = GetChunkSize(readByte);
+ Array.Copy(source, inputPosition, destination, outPosition, chunkSize);
+ outPosition += chunkSize;
+ inputPosition += chunkSize;
- if(outPosition + chunkSize > destination.Length)
- goto finished;
+ break;
+ case TWO_BYTE:
+ chunkSize = GetChunkSize(readByte);
+ temp[0] = readByte;
+ temp[1] = source[inputPosition++];
+ offset = GetOffset(temp);
- Array.Copy(source, inputPosition, destination, outPosition, chunkSize);
- outPosition += chunkSize;
- inputPosition += chunkSize;
+ if(outPosition + chunkSize > destination.Length)
+ goto finished;
- break;
- case TWO_BYTE:
- chunkSize = GetChunkSize(readByte);
- temp[0] = readByte;
- temp[1] = source[inputPosition++];
- offset = GetOffset(temp);
+ if(offset == 0)
+ {
+ byte lastByte = destination[outPosition - 1];
- if(outPosition + chunkSize > destination.Length)
- goto finished;
-
- if(offset == 0)
+ for(int i = 0; i < chunkSize; i++)
{
- byte lastByte = destination[outPosition - 1];
-
- for(int i = 0; i < chunkSize; i++)
- {
- destination[outPosition] = lastByte;
- outPosition++;
- }
+ destination[outPosition] = lastByte;
+ outPosition++;
}
- else
+ }
+ else
+ {
+ for(int i = 0; i < chunkSize; i++)
{
- for(int i = 0; i < chunkSize; i++)
- {
- destination[outPosition] = destination[outPosition - offset - 1];
- outPosition++;
- }
+ destination[outPosition] = destination[outPosition - offset - 1];
+ outPosition++;
}
+ }
- break;
- case THREE_BYTE:
- chunkSize = GetChunkSize(readByte);
- temp[0] = readByte;
- temp[1] = source[inputPosition++];
- temp[2] = source[inputPosition++];
- offset = GetOffset(temp);
+ break;
+ case THREE_BYTE:
+ chunkSize = GetChunkSize(readByte);
+ temp[0] = readByte;
+ temp[1] = source[inputPosition++];
+ temp[2] = source[inputPosition++];
+ offset = GetOffset(temp);
- if(outPosition + chunkSize > destination.Length)
- goto finished;
+ if(outPosition + chunkSize > destination.Length)
+ goto finished;
- if(offset == 0)
+ if(offset == 0)
+ {
+ byte lastByte = destination[outPosition - 1];
+
+ for(int i = 0; i < chunkSize; i++)
{
- byte lastByte = destination[outPosition - 1];
-
- for(int i = 0; i < chunkSize; i++)
- {
- destination[outPosition] = lastByte;
- outPosition++;
- }
+ destination[outPosition] = lastByte;
+ outPosition++;
}
- else
+ }
+ else
+ {
+ for(int i = 0; i < chunkSize; i++)
{
- for(int i = 0; i < chunkSize; i++)
- {
- destination[outPosition] = destination[outPosition - offset - 1];
- outPosition++;
- }
+ destination[outPosition] = destination[outPosition - offset - 1];
+ outPosition++;
}
+ }
- break;
- }
+ break;
}
-
- finished:
-
- return outPosition;
}
+
+ finished:
+
+ return outPosition;
}
}
\ No newline at end of file
diff --git a/Aaru.Compression/AppleRle.cs b/Aaru.Compression/AppleRle.cs
index 513fc2f59..569d15aac 100644
--- a/Aaru.Compression/AppleRle.cs
+++ b/Aaru.Compression/AppleRle.cs
@@ -33,105 +33,104 @@
using System.Runtime.InteropServices;
-namespace Aaru.Compression
+namespace Aaru.Compression;
+
+/// Implements the Apple version of RLE
+public static class AppleRle
{
- /// Implements the Apple version of RLE
- public static class AppleRle
+ ///
+ /// Set to true if this algorithm is supported, false otherwise.
+ ///
+ public static bool IsSupported => true;
+
+ [DllImport("libAaru.Compression.Native", SetLastError = true)]
+ static extern int AARU_apple_rle_decode_buffer(byte[] dst_buffer, int dst_size, byte[] src_buffer, int src_size);
+
+ const uint DART_CHUNK = 20960;
+
+ /// Decodes a buffer compressed with Apple RLE
+ /// Encoded buffer
+ /// Buffer where to write the decoded data
+ /// The number of decoded bytes
+ public static int DecodeBuffer(byte[] source, byte[] destination)
{
- ///
- /// Set to true if this algorithm is supported, false otherwise.
- ///
- public static bool IsSupported => true;
+ if(Native.IsSupported)
+ return AARU_apple_rle_decode_buffer(destination, destination.Length, source, source.Length);
- [DllImport("libAaru.Compression.Native", SetLastError = true)]
- static extern int AARU_apple_rle_decode_buffer(byte[] dst_buffer, int dst_size, byte[] src_buffer, int src_size);
+ int count = 0;
+ bool nextA = true; // true if A, false if B
+ byte repeatedByteA = 0, repeatedByteB = 0;
+ bool repeatMode = false; // true if we're repeating, false if we're just copying
+ int inPosition = 0, outPosition = 0;
- const uint DART_CHUNK = 20960;
-
- /// Decodes a buffer compressed with Apple RLE
- /// Encoded buffer
- /// Buffer where to write the decoded data
- /// The number of decoded bytes
- public static int DecodeBuffer(byte[] source, byte[] destination)
+ while(inPosition <= source.Length &&
+ outPosition <= destination.Length)
{
- if(Native.IsSupported)
- return AARU_apple_rle_decode_buffer(destination, destination.Length, source, source.Length);
-
- int count = 0;
- bool nextA = true; // true if A, false if B
- byte repeatedByteA = 0, repeatedByteB = 0;
- bool repeatMode = false; // true if we're repeating, false if we're just copying
- int inPosition = 0, outPosition = 0;
-
- while(inPosition <= source.Length &&
- outPosition <= destination.Length)
+ switch(repeatMode)
{
- switch(repeatMode)
+ case true when count > 0:
{
- case true when count > 0:
+ count--;
+
+ if(nextA)
{
- count--;
-
- if(nextA)
- {
- nextA = false;
-
- destination[outPosition++] = repeatedByteA;
-
- continue;
- }
-
- nextA = true;
-
- destination[outPosition++] = repeatedByteB;
-
- continue;
- }
- case false when count > 0:
- count--;
-
- destination[outPosition++] = source[inPosition++];
-
- continue;
- }
-
- if(inPosition == source.Length)
- break;
-
- while(true)
- {
- byte b1 = source[inPosition++];
- byte b2 = source[inPosition++];
- short s = (short)((b1 << 8) | b2);
-
- if(s == 0 ||
- s >= DART_CHUNK ||
- s <= -DART_CHUNK)
- continue;
-
- if(s < 0)
- {
- repeatMode = true;
- repeatedByteA = source[inPosition++];
- repeatedByteB = source[inPosition++];
- count = (-s * 2) - 1;
- nextA = false;
+ nextA = false;
destination[outPosition++] = repeatedByteA;
- break;
+ continue;
}
- repeatMode = false;
- count = (s * 2) - 1;
+ nextA = true;
+
+ destination[outPosition++] = repeatedByteB;
+
+ continue;
+ }
+ case false when count > 0:
+ count--;
destination[outPosition++] = source[inPosition++];
- break;
- }
+ continue;
}
- return outPosition;
+ if(inPosition == source.Length)
+ break;
+
+ while(true)
+ {
+ byte b1 = source[inPosition++];
+ byte b2 = source[inPosition++];
+ short s = (short)((b1 << 8) | b2);
+
+ if(s == 0 ||
+ s >= DART_CHUNK ||
+ s <= -DART_CHUNK)
+ continue;
+
+ if(s < 0)
+ {
+ repeatMode = true;
+ repeatedByteA = source[inPosition++];
+ repeatedByteB = source[inPosition++];
+ count = (-s * 2) - 1;
+ nextA = false;
+
+ destination[outPosition++] = repeatedByteA;
+
+ break;
+ }
+
+ repeatMode = false;
+ count = (s * 2) - 1;
+
+ destination[outPosition++] = source[inPosition++];
+
+ break;
+ }
}
+
+ return outPosition;
}
}
\ No newline at end of file
diff --git a/Aaru.Compression/Native.cs b/Aaru.Compression/Native.cs
index 3b4d59ea7..59b88218f 100644
--- a/Aaru.Compression/Native.cs
+++ b/Aaru.Compression/Native.cs
@@ -32,52 +32,51 @@
using System.Runtime.InteropServices;
-namespace Aaru.Compression
+namespace Aaru.Compression;
+
+public static class Native
{
- public static class Native
+ static bool _checked;
+ static bool _supported;
+
+ /// Set to return native as never supported
+ public static bool ForceManaged { get; set; }
+
+ ///
+ /// If set to true the native library was found and loaded correctly and its reported version is
+ /// compatible.
+ ///
+ public static bool IsSupported
{
- static bool _checked;
- static bool _supported;
-
- /// Set to return native as never supported
- public static bool ForceManaged { get; set; }
-
- ///
- /// If set to true the native library was found and loaded correctly and its reported version is
- /// compatible.
- ///
- public static bool IsSupported
+ get
{
- get
- {
- if(ForceManaged)
- return false;
-
- if(_checked)
- return _supported;
-
- ulong version;
- _checked = true;
-
- try
- {
- version = AARU_get_acn_version();
- }
- catch
- {
- _supported = false;
-
- return false;
- }
-
- // TODO: Check version compatibility
- _supported = version >= 0x06000000;
+ if(ForceManaged)
+ return false;
+ if(_checked)
return _supported;
- }
- }
- [DllImport("libAaru.Compression.Native", SetLastError = true)]
- static extern ulong AARU_get_acn_version();
+ ulong version;
+ _checked = true;
+
+ try
+ {
+ version = AARU_get_acn_version();
+ }
+ catch
+ {
+ _supported = false;
+
+ return false;
+ }
+
+ // TODO: Check version compatibility
+ _supported = version >= 0x06000000;
+
+ return _supported;
+ }
}
+
+ [DllImport("libAaru.Compression.Native", SetLastError = true)]
+ static extern ulong AARU_get_acn_version();
}
\ No newline at end of file
diff --git a/Aaru.Compression/TeleDiskLzh.cs b/Aaru.Compression/TeleDiskLzh.cs
index 3958ce884..f62a774dc 100644
--- a/Aaru.Compression/TeleDiskLzh.cs
+++ b/Aaru.Compression/TeleDiskLzh.cs
@@ -45,415 +45,414 @@
using System;
using System.IO;
-namespace Aaru.Compression
+namespace Aaru.Compression;
+
+/*
+ * Based on Japanese version 29-NOV-1988
+ * LZSS coded by Haruhiko OKUMURA
+ * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
+ * Edited and translated to English by Kenji RIKITAKE
+ */
+/// Implements the TeleDisk version of LZH
+public class TeleDiskLzh
{
+ ///
+ /// Set to true if this algorithm is supported, false otherwise.
+ ///
+ public static bool IsSupported => true;
+
+ const int BUFSZ = 512;
+
+ /* LZSS Parameters */
+
+ const int N = 4096; /* Size of string buffer */
+ const int F = 60; /* Size of look-ahead buffer */
+ const int THRESHOLD = 2;
+
+ /* Huffman coding parameters */
+
+ const int N_CHAR = 256 - THRESHOLD + F;
+ /* character code (= 0..N_CHAR-1) */
+ const int T = (N_CHAR * 2) - 1; /* Size of table */
+ const int ROOT = T - 1; /* root position */
+ const int MAX_FREQ = 0x8000;
+
/*
- * Based on Japanese version 29-NOV-1988
- * LZSS coded by Haruhiko OKUMURA
- * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
- * Edited and translated to English by Kenji RIKITAKE
+ * Tables for encoding/decoding upper 6 bits of
+ * sliding dictionary pointer
*/
- /// Implements the TeleDisk version of LZH
- public class TeleDiskLzh
+
+ /* decoder table */
+ readonly byte[] _dCode =
{
- ///
- /// Set to true if this algorithm is supported, false otherwise.
- ///
- public static bool IsSupported => true;
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+ 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10,
+ 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14,
+ 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A,
+ 0x1B, 0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
+ 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C,
+ 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
+ 0x3C, 0x3D, 0x3E, 0x3F
+ };
- const int BUFSZ = 512;
+ readonly byte[] _dLen =
+ {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08
+ };
+ readonly ushort[] _freq = new ushort[T + 1]; /* cumulative freq table */
- /* LZSS Parameters */
+ readonly Stream _inStream;
- const int N = 4096; /* Size of string buffer */
- const int F = 60; /* Size of look-ahead buffer */
- const int THRESHOLD = 2;
+ /*
+ * pointing parent nodes.
+ * area [T..(T + N_CHAR - 1)] are pointers for leaves
+ */
+ readonly short[] _prnt = new short[T + N_CHAR];
- /* Huffman coding parameters */
+ /* pointing children nodes (son[], son[] + 1)*/
+ readonly short[] _son = new short[T];
+ readonly byte[] _textBuf = new byte[N + F - 1];
- const int N_CHAR = 256 - THRESHOLD + F;
- /* character code (= 0..N_CHAR-1) */
- const int T = (N_CHAR * 2) - 1; /* Size of table */
- const int ROOT = T - 1; /* root position */
- const int MAX_FREQ = 0x8000;
+ ushort _getbuf;
+ byte _getlen;
- /*
- * Tables for encoding/decoding upper 6 bits of
- * sliding dictionary pointer
- */
+ Tdlzhuf _tdctl;
- /* decoder table */
- readonly byte[] _dCode =
- {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
- 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
- 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10,
- 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14,
- 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A,
- 0x1B, 0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
- 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C,
- 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
- 0x3C, 0x3D, 0x3E, 0x3F
- };
+ /// Implements the TeleDisk LZH algorithm over the specified stream.
+ /// Stream with compressed data.
+ public TeleDiskLzh(Stream dataStream)
+ {
+ int i;
+ _getbuf = 0;
+ _getlen = 0;
+ _tdctl = new Tdlzhuf();
+ _tdctl.Ibufcnt = _tdctl.Ibufndx = 0; // input buffer is empty
+ _tdctl.Bufcnt = 0;
+ StartHuff();
- readonly byte[] _dLen =
- {
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
- 0x08, 0x08, 0x08, 0x08
- };
- readonly ushort[] _freq = new ushort[T + 1]; /* cumulative freq table */
+ for(i = 0; i < N - F; i++)
+ _textBuf[i] = 0x20;
- readonly Stream _inStream;
+ _tdctl.R = N - F;
+ _inStream = dataStream;
+ }
- /*
- * pointing parent nodes.
- * area [T..(T + N_CHAR - 1)] are pointers for leaves
- */
- readonly short[] _prnt = new short[T + N_CHAR];
+ /* DeCompression
- /* pointing children nodes (son[], son[] + 1)*/
- readonly short[] _son = new short[T];
- readonly byte[] _textBuf = new byte[N + F - 1];
+ split out initialization code to init_Decode()
- ushort _getbuf;
- byte _getlen;
+ */
- Tdlzhuf _tdctl;
+ /// Decompresses data
+ /// Buffer to write the decompressed data to
+ /// Number of bytes to decompress
+ /// Number of decompressed bytes
+ public int Decode(out byte[] buf, int len) /* Decoding/Uncompressing */
+ {
+ short c;
+ buf = new byte[len];
+ int count; // was an unsigned long, seems unnecessary
- /// Implements the TeleDisk LZH algorithm over the specified stream.
- /// Stream with compressed data.
- public TeleDiskLzh(Stream dataStream)
- {
- int i;
- _getbuf = 0;
- _getlen = 0;
- _tdctl = new Tdlzhuf();
- _tdctl.Ibufcnt = _tdctl.Ibufndx = 0; // input buffer is empty
- _tdctl.Bufcnt = 0;
- StartHuff();
+ for(count = 0; count < len;)
+ if(_tdctl.Bufcnt == 0)
+ {
+ if((c = DecodeChar()) < 0)
+ return count; // fatal error
- for(i = 0; i < N - F; i++)
- _textBuf[i] = 0x20;
-
- _tdctl.R = N - F;
- _inStream = dataStream;
- }
-
- /* DeCompression
-
- split out initialization code to init_Decode()
-
- */
-
- /// Decompresses data
- /// Buffer to write the decompressed data to
- /// Number of bytes to decompress
- /// Number of decompressed bytes
- public int Decode(out byte[] buf, int len) /* Decoding/Uncompressing */
- {
- short c;
- buf = new byte[len];
- int count; // was an unsigned long, seems unnecessary
-
- for(count = 0; count < len;)
- if(_tdctl.Bufcnt == 0)
+ if(c < 256)
{
- if((c = DecodeChar()) < 0)
- return count; // fatal error
-
- if(c < 256)
- {
- buf[count] = (byte)c;
- _textBuf[_tdctl.R++] = (byte)c;
- _tdctl.R &= N - 1;
- count++;
- }
- else
- {
- short pos;
-
- if((pos = DecodePosition()) < 0)
- return count; // fatal error
-
- _tdctl.Bufpos = (ushort)((_tdctl.R - pos - 1) & (N - 1));
- _tdctl.Bufcnt = (ushort)(c - 255 + THRESHOLD);
- _tdctl.Bufndx = 0;
- }
+ buf[count] = (byte)c;
+ _textBuf[_tdctl.R++] = (byte)c;
+ _tdctl.R &= N - 1;
+ count++;
}
else
{
- // still chars from last string
- while(_tdctl.Bufndx < _tdctl.Bufcnt &&
- count < len)
- {
- c = _textBuf[(_tdctl.Bufpos + _tdctl.Bufndx) & (N - 1)];
- buf[count] = (byte)c;
- _tdctl.Bufndx++;
- _textBuf[_tdctl.R++] = (byte)c;
- _tdctl.R &= N - 1;
- count++;
- }
+ short pos;
- // reset bufcnt after copy string from text_buf[]
- if(_tdctl.Bufndx >= _tdctl.Bufcnt)
- _tdctl.Bufndx = _tdctl.Bufcnt = 0;
+ if((pos = DecodePosition()) < 0)
+ return count; // fatal error
+
+ _tdctl.Bufpos = (ushort)((_tdctl.R - pos - 1) & (N - 1));
+ _tdctl.Bufcnt = (ushort)(c - 255 + THRESHOLD);
+ _tdctl.Bufndx = 0;
+ }
+ }
+ else
+ {
+ // still chars from last string
+ while(_tdctl.Bufndx < _tdctl.Bufcnt &&
+ count < len)
+ {
+ c = _textBuf[(_tdctl.Bufpos + _tdctl.Bufndx) & (N - 1)];
+ buf[count] = (byte)c;
+ _tdctl.Bufndx++;
+ _textBuf[_tdctl.R++] = (byte)c;
+ _tdctl.R &= N - 1;
+ count++;
}
- return count; // count == len, success
- }
-
- long DataRead(out byte[] buf, long size)
- {
- if(size > _inStream.Length - _inStream.Position)
- size = _inStream.Length - _inStream.Position;
-
- buf = new byte[size];
- _inStream.Read(buf, 0, (int)size);
-
- return size;
- }
-
- int NextWord()
- {
- if(_tdctl.Ibufndx >= _tdctl.Ibufcnt)
- {
- _tdctl.Ibufndx = 0;
- _tdctl.Ibufcnt = (ushort)DataRead(out _tdctl.Inbuf, BUFSZ);
-
- if(_tdctl.Ibufcnt <= 0)
- return -1;
+ // reset bufcnt after copy string from text_buf[]
+ if(_tdctl.Bufndx >= _tdctl.Bufcnt)
+ _tdctl.Bufndx = _tdctl.Bufcnt = 0;
}
- while(_getlen <= 8)
- {
- // typically reads a word at a time
- _getbuf |= (ushort)(_tdctl.Inbuf[_tdctl.Ibufndx++] << (8 - _getlen));
- _getlen += 8;
- }
+ return count; // count == len, success
+ }
- return 0;
- }
+ long DataRead(out byte[] buf, long size)
+ {
+ if(size > _inStream.Length - _inStream.Position)
+ size = _inStream.Length - _inStream.Position;
- int GetBit() /* get one bit */
+ buf = new byte[size];
+ _inStream.Read(buf, 0, (int)size);
+
+ return size;
+ }
+
+ int NextWord()
+ {
+ if(_tdctl.Ibufndx >= _tdctl.Ibufcnt)
{
- if(NextWord() < 0)
+ _tdctl.Ibufndx = 0;
+ _tdctl.Ibufcnt = (ushort)DataRead(out _tdctl.Inbuf, BUFSZ);
+
+ if(_tdctl.Ibufcnt <= 0)
return -1;
-
- short i = (short)_getbuf;
- _getbuf <<= 1;
- _getlen--;
-
- return i < 0 ? 1 : 0;
}
- int GetByte() /* get a byte */
+ while(_getlen <= 8)
{
- if(NextWord() != 0)
- return -1;
-
- ushort i = _getbuf;
- _getbuf <<= 8;
- _getlen -= 8;
- i = (ushort)(i >> 8);
-
- return i;
+ // typically reads a word at a time
+ _getbuf |= (ushort)(_tdctl.Inbuf[_tdctl.Ibufndx++] << (8 - _getlen));
+ _getlen += 8;
}
- /* initialize freq tree */
+ return 0;
+ }
- void StartHuff()
+ int GetBit() /* get one bit */
+ {
+ if(NextWord() < 0)
+ return -1;
+
+ short i = (short)_getbuf;
+ _getbuf <<= 1;
+ _getlen--;
+
+ return i < 0 ? 1 : 0;
+ }
+
+ int GetByte() /* get a byte */
+ {
+ if(NextWord() != 0)
+ return -1;
+
+ ushort i = _getbuf;
+ _getbuf <<= 8;
+ _getlen -= 8;
+ i = (ushort)(i >> 8);
+
+ return i;
+ }
+
+ /* initialize freq tree */
+
+ void StartHuff()
+ {
+ int i;
+
+ for(i = 0; i < N_CHAR; i++)
{
- int i;
+ _freq[i] = 1;
+ _son[i] = (short)(i + T);
+ _prnt[i + T] = (short)i;
+ }
- for(i = 0; i < N_CHAR; i++)
+ i = 0;
+ int j = N_CHAR;
+
+ while(j <= ROOT)
+ {
+ _freq[j] = (ushort)(_freq[i] + _freq[i + 1]);
+ _son[j] = (short)i;
+ _prnt[i] = _prnt[i + 1] = (short)j;
+ i += 2;
+ j++;
+ }
+
+ _freq[T] = 0xffff;
+ _prnt[ROOT] = 0;
+ }
+
+ /* reconstruct freq tree */
+
+ void Reconst()
+ {
+ short i, k;
+
+ /* halven cumulative freq for leaf nodes */
+ short j = 0;
+
+ for(i = 0; i < T; i++)
+ if(_son[i] >= T)
{
- _freq[i] = 1;
- _son[i] = (short)(i + T);
- _prnt[i + T] = (short)i;
- }
-
- i = 0;
- int j = N_CHAR;
-
- while(j <= ROOT)
- {
- _freq[j] = (ushort)(_freq[i] + _freq[i + 1]);
- _son[j] = (short)i;
- _prnt[i] = _prnt[i + 1] = (short)j;
- i += 2;
+ _freq[j] = (ushort)((_freq[i] + 1) / 2);
+ _son[j] = _son[i];
j++;
}
- _freq[T] = 0xffff;
- _prnt[ROOT] = 0;
+ /* make a tree : first, connect children nodes */
+ for(i = 0, j = N_CHAR; j < T; i += 2, j++)
+ {
+ k = (short)(i + 1);
+ ushort f = _freq[j] = (ushort)(_freq[i] + _freq[k]);
+
+ for(k = (short)(j - 1); f < _freq[k]; k--) {}
+
+ k++;
+ ushort l = (ushort)((j - k) * 2);
+
+ Array.ConstrainedCopy(_freq, k, _freq, k + 1, l);
+ _freq[k] = f;
+ Array.ConstrainedCopy(_son, k, _son, k + 1, l);
+ _son[k] = i;
}
- /* reconstruct freq tree */
+ /* connect parent nodes */
+ for(i = 0; i < T; i++)
+ if((k = _son[i]) >= T)
+ _prnt[k] = i;
+ else
+ _prnt[k] = _prnt[k + 1] = i;
+ }
- void Reconst()
+ /* update freq tree */
+
+ void Update(int c)
+ {
+ if(_freq[ROOT] == MAX_FREQ)
+ Reconst();
+
+ c = _prnt[c + T];
+
+ do
{
- short i, k;
+ int k = ++_freq[c];
- /* halven cumulative freq for leaf nodes */
- short j = 0;
+ /* swap nodes to keep the tree freq-ordered */
+ int l;
- for(i = 0; i < T; i++)
- if(_son[i] >= T)
- {
- _freq[j] = (ushort)((_freq[i] + 1) / 2);
- _son[j] = _son[i];
- j++;
- }
+ if(k <= _freq[l = c + 1])
+ continue;
- /* make a tree : first, connect children nodes */
- for(i = 0, j = N_CHAR; j < T; i += 2, j++)
- {
- k = (short)(i + 1);
- ushort f = _freq[j] = (ushort)(_freq[i] + _freq[k]);
+ while(k > _freq[++l]) {}
- for(k = (short)(j - 1); f < _freq[k]; k--) {}
+ l--;
+ _freq[c] = _freq[l];
+ _freq[l] = (ushort)k;
- k++;
- ushort l = (ushort)((j - k) * 2);
+ int i = _son[c];
+ _prnt[i] = (short)l;
- Array.ConstrainedCopy(_freq, k, _freq, k + 1, l);
- _freq[k] = f;
- Array.ConstrainedCopy(_son, k, _son, k + 1, l);
- _son[k] = i;
- }
+ if(i < T)
+ _prnt[i + 1] = (short)l;
- /* connect parent nodes */
- for(i = 0; i < T; i++)
- if((k = _son[i]) >= T)
- _prnt[k] = i;
- else
- _prnt[k] = _prnt[k + 1] = i;
- }
+ int j = _son[l];
+ _son[l] = (short)i;
- /* update freq tree */
+ _prnt[j] = (short)c;
- void Update(int c)
+ if(j < T)
+ _prnt[j + 1] = (short)c;
+
+ _son[c] = (short)j;
+
+ c = l;
+ } while((c = _prnt[c]) != 0); /* do it until reaching the root */
+ }
+
+ short DecodeChar()
+ {
+ ushort c = (ushort)_son[ROOT];
+
+ /*
+ * start searching tree from the root to leaves.
+ * choose node #(son[]) if input bit == 0
+ * else choose #(son[]+1) (input bit == 1)
+ */
+ while(c < T)
{
- if(_freq[ROOT] == MAX_FREQ)
- Reconst();
+ int ret;
- c = _prnt[c + T];
-
- do
- {
- int k = ++_freq[c];
-
- /* swap nodes to keep the tree freq-ordered */
- int l;
-
- if(k <= _freq[l = c + 1])
- continue;
-
- while(k > _freq[++l]) {}
-
- l--;
- _freq[c] = _freq[l];
- _freq[l] = (ushort)k;
-
- int i = _son[c];
- _prnt[i] = (short)l;
-
- if(i < T)
- _prnt[i + 1] = (short)l;
-
- int j = _son[l];
- _son[l] = (short)i;
-
- _prnt[j] = (short)c;
-
- if(j < T)
- _prnt[j + 1] = (short)c;
-
- _son[c] = (short)j;
-
- c = l;
- } while((c = _prnt[c]) != 0); /* do it until reaching the root */
- }
-
- short DecodeChar()
- {
- ushort c = (ushort)_son[ROOT];
-
- /*
- * start searching tree from the root to leaves.
- * choose node #(son[]) if input bit == 0
- * else choose #(son[]+1) (input bit == 1)
- */
- while(c < T)
- {
- int ret;
-
- if((ret = GetBit()) < 0)
- return -1;
-
- c += (ushort)ret;
- c = (ushort)_son[c];
- }
-
- c -= T;
- Update(c);
-
- return (short)c;
- }
-
- short DecodePosition()
- {
- short bit;
-
- /* decode upper 6 bits from given table */
- if((bit = (short)GetByte()) < 0)
+ if((ret = GetBit()) < 0)
return -1;
- ushort i = (ushort)bit;
- ushort c = (ushort)(_dCode[i] << 6);
- ushort j = _dLen[i];
-
- /* input lower 6 bits directly */
- j -= 2;
-
- while(j-- > 0)
- {
- if((bit = (short)GetBit()) < 0)
- return -1;
-
- i = (ushort)((i << 1) + bit);
- }
-
- return (short)(c | (i & 0x3f));
+ c += (ushort)ret;
+ c = (ushort)_son[c];
}
- /* update when cumulative frequency */
- /* reaches to this value */
- struct Tdlzhuf
+ c -= T;
+ Update(c);
+
+ return (short)c;
+ }
+
+ short DecodePosition()
+ {
+ short bit;
+
+ /* decode upper 6 bits from given table */
+ if((bit = (short)GetByte()) < 0)
+ return -1;
+
+ ushort i = (ushort)bit;
+ ushort c = (ushort)(_dCode[i] << 6);
+ ushort j = _dLen[i];
+
+ /* input lower 6 bits directly */
+ j -= 2;
+
+ while(j-- > 0)
{
- public ushort R, Bufcnt, Bufndx, Bufpos, // string buffer
- // the following to allow block reads from input in next_word()
- Ibufcnt, Ibufndx; // input buffer counters
- public byte[] Inbuf; // input buffer
+ if((bit = (short)GetBit()) < 0)
+ return -1;
+
+ i = (ushort)((i << 1) + bit);
}
+
+ return (short)(c | (i & 0x3f));
+ }
+ /* update when cumulative frequency */
+ /* reaches to this value */
+
+ struct Tdlzhuf
+ {
+ public ushort R, Bufcnt, Bufndx, Bufpos, // string buffer
+ // the following to allow block reads from input in next_word()
+ Ibufcnt, Ibufndx; // input buffer counters
+ public byte[] Inbuf; // input buffer
}
}
\ No newline at end of file
diff --git a/Aaru.Core/Checksum.cs b/Aaru.Core/Checksum.cs
index c2077fd20..9cb023244 100644
--- a/Aaru.Core/Checksum.cs
+++ b/Aaru.Core/Checksum.cs
@@ -37,834 +37,833 @@ using Aaru.Checksums;
using Aaru.CommonTypes.Interfaces;
using Schemas;
-namespace Aaru.Core
+namespace Aaru.Core;
+
+/// Enabled checksums
+[Flags]
+public enum EnableChecksum
{
- /// Enabled checksums
- [Flags]
- public enum EnableChecksum
+ /// Enables Adler-32
+ Adler32 = 1,
+ /// Enables CRC-16
+ Crc16 = 2,
+ /// Enables CRC-32
+ Crc32 = 4,
+ /// Enables CRC-64
+ Crc64 = 8,
+ /// Enables MD5
+ Md5 = 16,
+ /// Enables SHA1
+ Sha1 = 64,
+ /// Enables SHA2-256
+ Sha256 = 128,
+ /// Enables SHA2-384
+ Sha384 = 256,
+ /// Enables SHA2-512
+ Sha512 = 512,
+ /// Enables SpamSum
+ SpamSum = 1024,
+ /// Enables Fletcher-16
+ Fletcher16 = 2048,
+ /// Enables Fletcher-32
+ Fletcher32 = 4096,
+ /// Enables all known checksums
+ All = Adler32 | Crc16 | Crc32 | Crc64 | Md5 | Sha1 | Sha256 | Sha384 | Sha512 | SpamSum | Fletcher16 |
+ Fletcher32
+}
+
+/// Checksums and hashes data, with different algorithms, multithreaded
+public sealed class Checksum
+{
+ readonly IChecksum _adler32Ctx;
+ readonly IChecksum _crc16Ctx;
+ readonly IChecksum _crc32Ctx;
+ readonly IChecksum _crc64Ctx;
+ readonly EnableChecksum _enabled;
+ readonly IChecksum _f16Ctx;
+ readonly IChecksum _f32Ctx;
+ readonly IChecksum _md5Ctx;
+ readonly IChecksum _sha1Ctx;
+ readonly IChecksum _sha256Ctx;
+ readonly IChecksum _sha384Ctx;
+ readonly IChecksum _sha512Ctx;
+ readonly IChecksum _ssCtx;
+ HashPacket _adlerPkt;
+ Thread _adlerThread;
+ HashPacket _crc16Pkt;
+ Thread _crc16Thread;
+ HashPacket _crc32Pkt;
+ Thread _crc32Thread;
+ HashPacket _crc64Pkt;
+ Thread _crc64Thread;
+ HashPacket _f16Pkt;
+ Thread _f16Thread;
+ HashPacket _f32Pkt;
+ Thread _f32Thread;
+ HashPacket _md5Pkt;
+ Thread _md5Thread;
+ HashPacket _sha1Pkt;
+ Thread _sha1Thread;
+ HashPacket _sha256Pkt;
+ Thread _sha256Thread;
+ HashPacket _sha384Pkt;
+ Thread _sha384Thread;
+ HashPacket _sha512Pkt;
+ Thread _sha512Thread;
+ HashPacket _spamsumPkt;
+ Thread _spamsumThread;
+
+ /// Initializes an instance of the checksum operations
+ /// Enabled checksums
+ public Checksum(EnableChecksum enabled = EnableChecksum.All)
{
- /// Enables Adler-32
- Adler32 = 1,
- /// Enables CRC-16
- Crc16 = 2,
- /// Enables CRC-32
- Crc32 = 4,
- /// Enables CRC-64
- Crc64 = 8,
- /// Enables MD5
- Md5 = 16,
- /// Enables SHA1
- Sha1 = 64,
- /// Enables SHA2-256
- Sha256 = 128,
- /// Enables SHA2-384
- Sha384 = 256,
- /// Enables SHA2-512
- Sha512 = 512,
- /// Enables SpamSum
- SpamSum = 1024,
- /// Enables Fletcher-16
- Fletcher16 = 2048,
- /// Enables Fletcher-32
- Fletcher32 = 4096,
- /// Enables all known checksums
- All = Adler32 | Crc16 | Crc32 | Crc64 | Md5 | Sha1 | Sha256 | Sha384 | Sha512 | SpamSum | Fletcher16 |
- Fletcher32
+ _enabled = enabled;
+
+ if(enabled.HasFlag(EnableChecksum.Adler32))
+ {
+ _adler32Ctx = new Adler32Context();
+
+ _adlerPkt = new HashPacket
+ {
+ Context = _adler32Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc16))
+ {
+ _crc16Ctx = new CRC16IBMContext();
+
+ _crc16Pkt = new HashPacket
+ {
+ Context = _crc16Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc32))
+ {
+ _crc32Ctx = new Crc32Context();
+
+ _crc32Pkt = new HashPacket
+ {
+ Context = _crc32Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc64))
+ {
+ _crc64Ctx = new Crc64Context();
+
+ _crc64Pkt = new HashPacket
+ {
+ Context = _crc64Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Md5))
+ {
+ _md5Ctx = new Md5Context();
+
+ _md5Pkt = new HashPacket
+ {
+ Context = _md5Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha1))
+ {
+ _sha1Ctx = new Sha1Context();
+
+ _sha1Pkt = new HashPacket
+ {
+ Context = _sha1Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha256))
+ {
+ _sha256Ctx = new Sha256Context();
+
+ _sha256Pkt = new HashPacket
+ {
+ Context = _sha256Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha384))
+ {
+ _sha384Ctx = new Sha384Context();
+
+ _sha384Pkt = new HashPacket
+ {
+ Context = _sha384Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha512))
+ {
+ _sha512Ctx = new Sha512Context();
+
+ _sha512Pkt = new HashPacket
+ {
+ Context = _sha512Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.SpamSum))
+ {
+ _ssCtx = new SpamSumContext();
+
+ _spamsumPkt = new HashPacket
+ {
+ Context = _ssCtx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Fletcher16))
+ {
+ _f16Ctx = new Fletcher16Context();
+
+ _f16Pkt = new HashPacket
+ {
+ Context = _f16Ctx
+ };
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Fletcher32))
+ {
+ _f32Ctx = new Fletcher32Context();
+
+ _f32Pkt = new HashPacket
+ {
+ Context = _f32Ctx
+ };
+ }
+
+ _adlerThread = new Thread(UpdateHash);
+ _crc16Thread = new Thread(UpdateHash);
+ _crc32Thread = new Thread(UpdateHash);
+ _crc64Thread = new Thread(UpdateHash);
+ _md5Thread = new Thread(UpdateHash);
+ _sha1Thread = new Thread(UpdateHash);
+ _sha256Thread = new Thread(UpdateHash);
+ _sha384Thread = new Thread(UpdateHash);
+ _sha512Thread = new Thread(UpdateHash);
+ _spamsumThread = new Thread(UpdateHash);
+ _f16Thread = new Thread(UpdateHash);
+ _f32Thread = new Thread(UpdateHash);
}
- /// Checksums and hashes data, with different algorithms, multithreaded
- public sealed class Checksum
+ /// Updates the checksum with new data
+ /// New data
+ public void Update(byte[] data)
{
- readonly IChecksum _adler32Ctx;
- readonly IChecksum _crc16Ctx;
- readonly IChecksum _crc32Ctx;
- readonly IChecksum _crc64Ctx;
- readonly EnableChecksum _enabled;
- readonly IChecksum _f16Ctx;
- readonly IChecksum _f32Ctx;
- readonly IChecksum _md5Ctx;
- readonly IChecksum _sha1Ctx;
- readonly IChecksum _sha256Ctx;
- readonly IChecksum _sha384Ctx;
- readonly IChecksum _sha512Ctx;
- readonly IChecksum _ssCtx;
- HashPacket _adlerPkt;
- Thread _adlerThread;
- HashPacket _crc16Pkt;
- Thread _crc16Thread;
- HashPacket _crc32Pkt;
- Thread _crc32Thread;
- HashPacket _crc64Pkt;
- Thread _crc64Thread;
- HashPacket _f16Pkt;
- Thread _f16Thread;
- HashPacket _f32Pkt;
- Thread _f32Thread;
- HashPacket _md5Pkt;
- Thread _md5Thread;
- HashPacket _sha1Pkt;
- Thread _sha1Thread;
- HashPacket _sha256Pkt;
- Thread _sha256Thread;
- HashPacket _sha384Pkt;
- Thread _sha384Thread;
- HashPacket _sha512Pkt;
- Thread _sha512Thread;
- HashPacket _spamsumPkt;
- Thread _spamsumThread;
-
- /// Initializes an instance of the checksum operations
- /// Enabled checksums
- public Checksum(EnableChecksum enabled = EnableChecksum.All)
+ if(_enabled.HasFlag(EnableChecksum.Adler32))
{
- _enabled = enabled;
+ _adlerPkt.Data = data;
+ _adlerThread.Start(_adlerPkt);
+ }
- if(enabled.HasFlag(EnableChecksum.Adler32))
- {
- _adler32Ctx = new Adler32Context();
+ if(_enabled.HasFlag(EnableChecksum.Crc16))
+ {
+ _crc16Pkt.Data = data;
+ _crc16Thread.Start(_crc16Pkt);
+ }
- _adlerPkt = new HashPacket
- {
- Context = _adler32Ctx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Crc32))
+ {
+ _crc32Pkt.Data = data;
+ _crc32Thread.Start(_crc32Pkt);
+ }
- if(enabled.HasFlag(EnableChecksum.Crc16))
- {
- _crc16Ctx = new CRC16IBMContext();
+ if(_enabled.HasFlag(EnableChecksum.Crc64))
+ {
+ _crc64Pkt.Data = data;
+ _crc64Thread.Start(_crc64Pkt);
+ }
- _crc16Pkt = new HashPacket
- {
- Context = _crc16Ctx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Md5))
+ {
+ _md5Pkt.Data = data;
+ _md5Thread.Start(_md5Pkt);
+ }
- if(enabled.HasFlag(EnableChecksum.Crc32))
- {
- _crc32Ctx = new Crc32Context();
+ if(_enabled.HasFlag(EnableChecksum.Sha1))
+ {
+ _sha1Pkt.Data = data;
+ _sha1Thread.Start(_sha1Pkt);
+ }
- _crc32Pkt = new HashPacket
- {
- Context = _crc32Ctx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Sha256))
+ {
+ _sha256Pkt.Data = data;
+ _sha256Thread.Start(_sha256Pkt);
+ }
- if(enabled.HasFlag(EnableChecksum.Crc64))
- {
- _crc64Ctx = new Crc64Context();
+ if(_enabled.HasFlag(EnableChecksum.Sha384))
+ {
+ _sha384Pkt.Data = data;
+ _sha384Thread.Start(_sha384Pkt);
+ }
- _crc64Pkt = new HashPacket
- {
- Context = _crc64Ctx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Sha512))
+ {
+ _sha512Pkt.Data = data;
+ _sha512Thread.Start(_sha512Pkt);
+ }
- if(enabled.HasFlag(EnableChecksum.Md5))
- {
- _md5Ctx = new Md5Context();
+ if(_enabled.HasFlag(EnableChecksum.SpamSum))
+ {
+ _spamsumPkt.Data = data;
+ _spamsumThread.Start(_spamsumPkt);
+ }
- _md5Pkt = new HashPacket
- {
- Context = _md5Ctx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Fletcher16))
+ {
+ _f16Pkt.Data = data;
+ _f16Thread.Start(_f16Pkt);
+ }
- if(enabled.HasFlag(EnableChecksum.Sha1))
- {
- _sha1Ctx = new Sha1Context();
+ if(_enabled.HasFlag(EnableChecksum.Fletcher32))
+ {
+ _f32Pkt.Data = data;
+ _f32Thread.Start(_f32Pkt);
+ }
- _sha1Pkt = new HashPacket
- {
- Context = _sha1Ctx
- };
- }
+ while(_adlerThread.IsAlive ||
+ _crc16Thread.IsAlive ||
+ _crc32Thread.IsAlive ||
+ _crc64Thread.IsAlive ||
+ _md5Thread.IsAlive ||
+ _sha1Thread.IsAlive ||
+ _sha256Thread.IsAlive ||
+ _sha384Thread.IsAlive ||
+ _sha512Thread.IsAlive ||
+ _spamsumThread.IsAlive ||
+ _f16Thread.IsAlive ||
+ _f32Thread.IsAlive) {}
- if(enabled.HasFlag(EnableChecksum.Sha256))
- {
- _sha256Ctx = new Sha256Context();
+ if(_enabled.HasFlag(EnableChecksum.Adler32))
+ _adlerThread = new Thread(UpdateHash);
- _sha256Pkt = new HashPacket
- {
- Context = _sha256Ctx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Crc16))
+ _crc16Thread = new Thread(UpdateHash);
- if(enabled.HasFlag(EnableChecksum.Sha384))
- {
- _sha384Ctx = new Sha384Context();
+ if(_enabled.HasFlag(EnableChecksum.Crc32))
+ _crc32Thread = new Thread(UpdateHash);
- _sha384Pkt = new HashPacket
- {
- Context = _sha384Ctx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Crc16))
+ _crc64Thread = new Thread(UpdateHash);
- if(enabled.HasFlag(EnableChecksum.Sha512))
- {
- _sha512Ctx = new Sha512Context();
+ if(_enabled.HasFlag(EnableChecksum.Md5))
+ _md5Thread = new Thread(UpdateHash);
- _sha512Pkt = new HashPacket
- {
- Context = _sha512Ctx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Sha1))
+ _sha1Thread = new Thread(UpdateHash);
- if(enabled.HasFlag(EnableChecksum.SpamSum))
- {
- _ssCtx = new SpamSumContext();
+ if(_enabled.HasFlag(EnableChecksum.Sha256))
+ _sha256Thread = new Thread(UpdateHash);
- _spamsumPkt = new HashPacket
- {
- Context = _ssCtx
- };
- }
+ if(_enabled.HasFlag(EnableChecksum.Sha384))
+ _sha384Thread = new Thread(UpdateHash);
- if(enabled.HasFlag(EnableChecksum.Fletcher16))
- {
- _f16Ctx = new Fletcher16Context();
+ if(_enabled.HasFlag(EnableChecksum.Sha512))
+ _sha512Thread = new Thread(UpdateHash);
- _f16Pkt = new HashPacket
- {
- Context = _f16Ctx
- };
- }
-
- if(enabled.HasFlag(EnableChecksum.Fletcher32))
- {
- _f32Ctx = new Fletcher32Context();
-
- _f32Pkt = new HashPacket
- {
- Context = _f32Ctx
- };
- }
-
- _adlerThread = new Thread(UpdateHash);
- _crc16Thread = new Thread(UpdateHash);
- _crc32Thread = new Thread(UpdateHash);
- _crc64Thread = new Thread(UpdateHash);
- _md5Thread = new Thread(UpdateHash);
- _sha1Thread = new Thread(UpdateHash);
- _sha256Thread = new Thread(UpdateHash);
- _sha384Thread = new Thread(UpdateHash);
- _sha512Thread = new Thread(UpdateHash);
+ if(_enabled.HasFlag(EnableChecksum.SpamSum))
_spamsumThread = new Thread(UpdateHash);
- _f16Thread = new Thread(UpdateHash);
- _f32Thread = new Thread(UpdateHash);
- }
- /// Updates the checksum with new data
- /// New data
- public void Update(byte[] data)
+ if(_enabled.HasFlag(EnableChecksum.Fletcher16))
+ _f16Thread = new Thread(UpdateHash);
+
+ if(_enabled.HasFlag(EnableChecksum.Fletcher32))
+ _f32Thread = new Thread(UpdateHash);
+ }
+
+ /// Finishes the checksums
+ /// Returns the checksum results
+ public List End()
+ {
+ List chks = new List();
+
+ ChecksumType chk;
+
+ if(_enabled.HasFlag(EnableChecksum.All))
{
- if(_enabled.HasFlag(EnableChecksum.Adler32))
- {
- _adlerPkt.Data = data;
- _adlerThread.Start(_adlerPkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Crc16))
- {
- _crc16Pkt.Data = data;
- _crc16Thread.Start(_crc16Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Crc32))
- {
- _crc32Pkt.Data = data;
- _crc32Thread.Start(_crc32Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Crc64))
- {
- _crc64Pkt.Data = data;
- _crc64Thread.Start(_crc64Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Md5))
- {
- _md5Pkt.Data = data;
- _md5Thread.Start(_md5Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Sha1))
- {
- _sha1Pkt.Data = data;
- _sha1Thread.Start(_sha1Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Sha256))
- {
- _sha256Pkt.Data = data;
- _sha256Thread.Start(_sha256Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Sha384))
- {
- _sha384Pkt.Data = data;
- _sha384Thread.Start(_sha384Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Sha512))
- {
- _sha512Pkt.Data = data;
- _sha512Thread.Start(_sha512Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.SpamSum))
- {
- _spamsumPkt.Data = data;
- _spamsumThread.Start(_spamsumPkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Fletcher16))
- {
- _f16Pkt.Data = data;
- _f16Thread.Start(_f16Pkt);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Fletcher32))
- {
- _f32Pkt.Data = data;
- _f32Thread.Start(_f32Pkt);
- }
-
- while(_adlerThread.IsAlive ||
- _crc16Thread.IsAlive ||
- _crc32Thread.IsAlive ||
- _crc64Thread.IsAlive ||
- _md5Thread.IsAlive ||
- _sha1Thread.IsAlive ||
- _sha256Thread.IsAlive ||
- _sha384Thread.IsAlive ||
- _sha512Thread.IsAlive ||
- _spamsumThread.IsAlive ||
- _f16Thread.IsAlive ||
- _f32Thread.IsAlive) {}
-
- if(_enabled.HasFlag(EnableChecksum.Adler32))
- _adlerThread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Crc16))
- _crc16Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Crc32))
- _crc32Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Crc16))
- _crc64Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Md5))
- _md5Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Sha1))
- _sha1Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Sha256))
- _sha256Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Sha384))
- _sha384Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Sha512))
- _sha512Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.SpamSum))
- _spamsumThread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Fletcher16))
- _f16Thread = new Thread(UpdateHash);
-
- if(_enabled.HasFlag(EnableChecksum.Fletcher32))
- _f32Thread = new Thread(UpdateHash);
- }
-
- /// Finishes the checksums
- /// Returns the checksum results
- public List End()
- {
- List chks = new List();
-
- ChecksumType chk;
-
- if(_enabled.HasFlag(EnableChecksum.All))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.adler32,
- Value = _adler32Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Crc16))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.crc16,
- Value = _crc16Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Crc32))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.crc32,
- Value = _crc32Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Crc64))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.crc64,
- Value = _crc64Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Md5))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.md5,
- Value = _md5Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Sha1))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.sha1,
- Value = _sha1Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Sha256))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.sha256,
- Value = _sha256Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Sha384))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.sha384,
- Value = _sha384Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Sha512))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.sha512,
- Value = _sha512Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.SpamSum))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.spamsum,
- Value = _ssCtx.End()
- };
-
- chks.Add(chk);
- }
-
- if(_enabled.HasFlag(EnableChecksum.Fletcher16))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.fletcher16,
- Value = _f16Ctx.End()
- };
-
- chks.Add(chk);
- }
-
- if(!_enabled.HasFlag(EnableChecksum.Fletcher32))
- return chks;
-
chk = new ChecksumType
{
- type = ChecksumTypeType.fletcher32,
- Value = _f32Ctx.End()
+ type = ChecksumTypeType.adler32,
+ Value = _adler32Ctx.End()
};
chks.Add(chk);
+ }
+ if(_enabled.HasFlag(EnableChecksum.Crc16))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.crc16,
+ Value = _crc16Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.Crc32))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.crc32,
+ Value = _crc32Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.Crc64))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.crc64,
+ Value = _crc64Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.Md5))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.md5,
+ Value = _md5Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.Sha1))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.sha1,
+ Value = _sha1Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.Sha256))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.sha256,
+ Value = _sha256Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.Sha384))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.sha384,
+ Value = _sha384Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.Sha512))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.sha512,
+ Value = _sha512Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.SpamSum))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.spamsum,
+ Value = _ssCtx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(_enabled.HasFlag(EnableChecksum.Fletcher16))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.fletcher16,
+ Value = _f16Ctx.End()
+ };
+
+ chks.Add(chk);
+ }
+
+ if(!_enabled.HasFlag(EnableChecksum.Fletcher32))
return chks;
- }
- internal static List GetChecksums(byte[] data, EnableChecksum enabled = EnableChecksum.All)
+ chk = new ChecksumType
{
- IChecksum adler32CtxData = null;
- IChecksum crc16CtxData = null;
- IChecksum crc32CtxData = null;
- IChecksum crc64CtxData = null;
- IChecksum md5CtxData = null;
- IChecksum sha1CtxData = null;
- IChecksum sha256CtxData = null;
- IChecksum sha384CtxData = null;
- IChecksum sha512CtxData = null;
- IChecksum ssctxData = null;
- IChecksum f16CtxData = null;
- IChecksum f32CtxData = null;
+ type = ChecksumTypeType.fletcher32,
+ Value = _f32Ctx.End()
+ };
- var adlerThreadData = new Thread(UpdateHash);
- var crc16ThreadData = new Thread(UpdateHash);
- var crc32ThreadData = new Thread(UpdateHash);
- var crc64ThreadData = new Thread(UpdateHash);
- var md5ThreadData = new Thread(UpdateHash);
- var sha1ThreadData = new Thread(UpdateHash);
- var sha256ThreadData = new Thread(UpdateHash);
- var sha384ThreadData = new Thread(UpdateHash);
- var sha512ThreadData = new Thread(UpdateHash);
- var spamsumThreadData = new Thread(UpdateHash);
- var f16ThreadData = new Thread(UpdateHash);
- var f32ThreadData = new Thread(UpdateHash);
+ chks.Add(chk);
- if(enabled.HasFlag(EnableChecksum.Adler32))
- {
- adler32CtxData = new Adler32Context();
-
- var adlerPktData = new HashPacket
- {
- Context = adler32CtxData,
- Data = data
- };
-
- adlerThreadData.Start(adlerPktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Crc16))
- {
- crc16CtxData = new CRC16IBMContext();
-
- var crc16PktData = new HashPacket
- {
- Context = crc16CtxData,
- Data = data
- };
-
- crc16ThreadData.Start(crc16PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Crc32))
- {
- crc32CtxData = new Crc32Context();
-
- var crc32PktData = new HashPacket
- {
- Context = crc32CtxData,
- Data = data
- };
-
- crc32ThreadData.Start(crc32PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Crc64))
- {
- crc64CtxData = new Crc64Context();
-
- var crc64PktData = new HashPacket
- {
- Context = crc64CtxData,
- Data = data
- };
-
- crc64ThreadData.Start(crc64PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Md5))
- {
- md5CtxData = new Md5Context();
-
- var md5PktData = new HashPacket
- {
- Context = md5CtxData,
- Data = data
- };
-
- md5ThreadData.Start(md5PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Sha1))
- {
- sha1CtxData = new Sha1Context();
-
- var sha1PktData = new HashPacket
- {
- Context = sha1CtxData,
- Data = data
- };
-
- sha1ThreadData.Start(sha1PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Sha256))
- {
- sha256CtxData = new Sha256Context();
-
- var sha256PktData = new HashPacket
- {
- Context = sha256CtxData,
- Data = data
- };
-
- sha256ThreadData.Start(sha256PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Sha384))
- {
- sha384CtxData = new Sha384Context();
-
- var sha384PktData = new HashPacket
- {
- Context = sha384CtxData,
- Data = data
- };
-
- sha384ThreadData.Start(sha384PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Sha512))
- {
- sha512CtxData = new Sha512Context();
-
- var sha512PktData = new HashPacket
- {
- Context = sha512CtxData,
- Data = data
- };
-
- sha512ThreadData.Start(sha512PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.SpamSum))
- {
- ssctxData = new SpamSumContext();
-
- var spamsumPktData = new HashPacket
- {
- Context = ssctxData,
- Data = data
- };
-
- spamsumThreadData.Start(spamsumPktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Fletcher16))
- {
- f16CtxData = new Fletcher16Context();
-
- var f16PktData = new HashPacket
- {
- Context = f16CtxData,
- Data = data
- };
-
- f16ThreadData.Start(f16PktData);
- }
-
- if(enabled.HasFlag(EnableChecksum.Fletcher32))
- {
- f32CtxData = new Fletcher32Context();
-
- var f32PktData = new HashPacket
- {
- Context = f32CtxData,
- Data = data
- };
-
- f32ThreadData.Start(f32PktData);
- }
-
- while(adlerThreadData.IsAlive ||
- crc16ThreadData.IsAlive ||
- crc32ThreadData.IsAlive ||
- crc64ThreadData.IsAlive ||
- md5ThreadData.IsAlive ||
- sha1ThreadData.IsAlive ||
- sha256ThreadData.IsAlive ||
- sha384ThreadData.IsAlive ||
- sha512ThreadData.IsAlive ||
- spamsumThreadData.IsAlive ||
- f16ThreadData.IsAlive ||
- f32ThreadData.IsAlive) {}
-
- List dataChecksums = new List();
- ChecksumType chk;
-
- if(enabled.HasFlag(EnableChecksum.Adler32))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.adler32,
- Value = adler32CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Crc16))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.crc16,
- Value = crc16CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Crc32))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.crc32,
- Value = crc32CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Crc64))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.crc64,
- Value = crc64CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Md5))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.md5,
- Value = md5CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Sha1))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.sha1,
- Value = sha1CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Sha256))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.sha256,
- Value = sha256CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Sha384))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.sha384,
- Value = sha384CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Sha512))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.sha512,
- Value = sha512CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.SpamSum))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.spamsum,
- Value = ssctxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Fletcher16))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.fletcher16,
- Value = f16CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- if(enabled.HasFlag(EnableChecksum.Fletcher32))
- {
- chk = new ChecksumType
- {
- type = ChecksumTypeType.fletcher32,
- Value = f32CtxData.End()
- };
-
- dataChecksums.Add(chk);
- }
-
- return dataChecksums;
- }
-
- #region Threading helpers
- struct HashPacket
- {
- public IChecksum Context;
- public byte[] Data;
- }
-
- static void UpdateHash(object packet) => ((HashPacket)packet).Context.Update(((HashPacket)packet).Data);
- #endregion Threading helpers
+ return chks;
}
+
+ internal static List GetChecksums(byte[] data, EnableChecksum enabled = EnableChecksum.All)
+ {
+ IChecksum adler32CtxData = null;
+ IChecksum crc16CtxData = null;
+ IChecksum crc32CtxData = null;
+ IChecksum crc64CtxData = null;
+ IChecksum md5CtxData = null;
+ IChecksum sha1CtxData = null;
+ IChecksum sha256CtxData = null;
+ IChecksum sha384CtxData = null;
+ IChecksum sha512CtxData = null;
+ IChecksum ssctxData = null;
+ IChecksum f16CtxData = null;
+ IChecksum f32CtxData = null;
+
+ var adlerThreadData = new Thread(UpdateHash);
+ var crc16ThreadData = new Thread(UpdateHash);
+ var crc32ThreadData = new Thread(UpdateHash);
+ var crc64ThreadData = new Thread(UpdateHash);
+ var md5ThreadData = new Thread(UpdateHash);
+ var sha1ThreadData = new Thread(UpdateHash);
+ var sha256ThreadData = new Thread(UpdateHash);
+ var sha384ThreadData = new Thread(UpdateHash);
+ var sha512ThreadData = new Thread(UpdateHash);
+ var spamsumThreadData = new Thread(UpdateHash);
+ var f16ThreadData = new Thread(UpdateHash);
+ var f32ThreadData = new Thread(UpdateHash);
+
+ if(enabled.HasFlag(EnableChecksum.Adler32))
+ {
+ adler32CtxData = new Adler32Context();
+
+ var adlerPktData = new HashPacket
+ {
+ Context = adler32CtxData,
+ Data = data
+ };
+
+ adlerThreadData.Start(adlerPktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc16))
+ {
+ crc16CtxData = new CRC16IBMContext();
+
+ var crc16PktData = new HashPacket
+ {
+ Context = crc16CtxData,
+ Data = data
+ };
+
+ crc16ThreadData.Start(crc16PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc32))
+ {
+ crc32CtxData = new Crc32Context();
+
+ var crc32PktData = new HashPacket
+ {
+ Context = crc32CtxData,
+ Data = data
+ };
+
+ crc32ThreadData.Start(crc32PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc64))
+ {
+ crc64CtxData = new Crc64Context();
+
+ var crc64PktData = new HashPacket
+ {
+ Context = crc64CtxData,
+ Data = data
+ };
+
+ crc64ThreadData.Start(crc64PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Md5))
+ {
+ md5CtxData = new Md5Context();
+
+ var md5PktData = new HashPacket
+ {
+ Context = md5CtxData,
+ Data = data
+ };
+
+ md5ThreadData.Start(md5PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha1))
+ {
+ sha1CtxData = new Sha1Context();
+
+ var sha1PktData = new HashPacket
+ {
+ Context = sha1CtxData,
+ Data = data
+ };
+
+ sha1ThreadData.Start(sha1PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha256))
+ {
+ sha256CtxData = new Sha256Context();
+
+ var sha256PktData = new HashPacket
+ {
+ Context = sha256CtxData,
+ Data = data
+ };
+
+ sha256ThreadData.Start(sha256PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha384))
+ {
+ sha384CtxData = new Sha384Context();
+
+ var sha384PktData = new HashPacket
+ {
+ Context = sha384CtxData,
+ Data = data
+ };
+
+ sha384ThreadData.Start(sha384PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha512))
+ {
+ sha512CtxData = new Sha512Context();
+
+ var sha512PktData = new HashPacket
+ {
+ Context = sha512CtxData,
+ Data = data
+ };
+
+ sha512ThreadData.Start(sha512PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.SpamSum))
+ {
+ ssctxData = new SpamSumContext();
+
+ var spamsumPktData = new HashPacket
+ {
+ Context = ssctxData,
+ Data = data
+ };
+
+ spamsumThreadData.Start(spamsumPktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Fletcher16))
+ {
+ f16CtxData = new Fletcher16Context();
+
+ var f16PktData = new HashPacket
+ {
+ Context = f16CtxData,
+ Data = data
+ };
+
+ f16ThreadData.Start(f16PktData);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Fletcher32))
+ {
+ f32CtxData = new Fletcher32Context();
+
+ var f32PktData = new HashPacket
+ {
+ Context = f32CtxData,
+ Data = data
+ };
+
+ f32ThreadData.Start(f32PktData);
+ }
+
+ while(adlerThreadData.IsAlive ||
+ crc16ThreadData.IsAlive ||
+ crc32ThreadData.IsAlive ||
+ crc64ThreadData.IsAlive ||
+ md5ThreadData.IsAlive ||
+ sha1ThreadData.IsAlive ||
+ sha256ThreadData.IsAlive ||
+ sha384ThreadData.IsAlive ||
+ sha512ThreadData.IsAlive ||
+ spamsumThreadData.IsAlive ||
+ f16ThreadData.IsAlive ||
+ f32ThreadData.IsAlive) {}
+
+ List dataChecksums = new List();
+ ChecksumType chk;
+
+ if(enabled.HasFlag(EnableChecksum.Adler32))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.adler32,
+ Value = adler32CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc16))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.crc16,
+ Value = crc16CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc32))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.crc32,
+ Value = crc32CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Crc64))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.crc64,
+ Value = crc64CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Md5))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.md5,
+ Value = md5CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha1))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.sha1,
+ Value = sha1CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha256))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.sha256,
+ Value = sha256CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha384))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.sha384,
+ Value = sha384CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Sha512))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.sha512,
+ Value = sha512CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.SpamSum))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.spamsum,
+ Value = ssctxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Fletcher16))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.fletcher16,
+ Value = f16CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ if(enabled.HasFlag(EnableChecksum.Fletcher32))
+ {
+ chk = new ChecksumType
+ {
+ type = ChecksumTypeType.fletcher32,
+ Value = f32CtxData.End()
+ };
+
+ dataChecksums.Add(chk);
+ }
+
+ return dataChecksums;
+ }
+
+ #region Threading helpers
+ struct HashPacket
+ {
+ public IChecksum Context;
+ public byte[] Data;
+ }
+
+ static void UpdateHash(object packet) => ((HashPacket)packet).Context.Update(((HashPacket)packet).Data);
+ #endregion Threading helpers
}
\ No newline at end of file
diff --git a/Aaru.Core/DataFile.cs b/Aaru.Core/DataFile.cs
index df6477aee..dcf40a524 100644
--- a/Aaru.Core/DataFile.cs
+++ b/Aaru.Core/DataFile.cs
@@ -34,127 +34,126 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using Aaru.Console;
-namespace Aaru.Core
+namespace Aaru.Core;
+
+/// Abstracts a datafile with a block based interface
+[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global"),
+ SuppressMessage("ReSharper", "UnusedMember.Global")]
+public sealed class DataFile
{
- /// Abstracts a datafile with a block based interface
- [SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global"),
- SuppressMessage("ReSharper", "UnusedMember.Global")]
- public sealed class DataFile
+ readonly FileStream _dataFs;
+
+ /// Opens, or create, a new file
+ /// File
+ public DataFile(string outputFile) =>
+ _dataFs = new FileStream(outputFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);
+
+ /// Closes the file
+ public void Close() => _dataFs?.Close();
+
+ /// Reads bytes at current position
+ /// Array to place read data within
+ /// Offset of where data will be read
+ /// How many bytes to read
+ /// How many bytes were read
+ public int Read(byte[] array, int offset, int count) => _dataFs.Read(array, offset, count);
+
+ /// Seeks to the specified block
+ /// Block to seek to
+ /// Block size in bytes
+ /// Position
+ public long Seek(ulong block, ulong blockSize) => _dataFs.Seek((long)(block * blockSize), SeekOrigin.Begin);
+
+ /// Seeks to specified byte position
+ /// Byte position
+ /// Where to count for position
+ /// Position
+ public long Seek(ulong offset, SeekOrigin origin) => _dataFs.Seek((long)offset, origin);
+
+ /// Seeks to specified byte position
+ /// Byte position
+ /// Where to count for position
+ /// Position
+ public long Seek(long offset, SeekOrigin origin) => _dataFs.Seek(offset, origin);
+
+ /// Writes data at current position
+ /// Data
+ public void Write(byte[] data) => Write(data, 0, data.Length);
+
+ /// Writes data at current position
+ /// Data
+ /// Offset of data from where to start taking data to write
+ /// How many bytes to write
+ public void Write(byte[] data, int offset, int count) => _dataFs.Write(data, offset, count);
+
+ /// Writes data at specified block
+ /// Data
+ /// Block
+ /// Bytes per block
+ public void WriteAt(byte[] data, ulong block, uint blockSize) =>
+ WriteAt(data, block, blockSize, 0, data.Length);
+
+ /// Writes data at specified block
+ /// Data
+ /// Block
+ /// Bytes per block
+ /// Offset of data from where to start taking data to write
+ /// How many bytes to write
+ public void WriteAt(byte[] data, ulong block, uint blockSize, int offset, int count)
{
- readonly FileStream _dataFs;
+ _dataFs.Seek((long)(block * blockSize), SeekOrigin.Begin);
+ _dataFs.Write(data, offset, count);
+ }
- /// Opens, or create, a new file
- /// File
- public DataFile(string outputFile) =>
- _dataFs = new FileStream(outputFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);
+ /// Current file position
+ public long Position => _dataFs.Position;
- /// Closes the file
- public void Close() => _dataFs?.Close();
+ /// Writes data to a newly created file
+ /// Who asked the file to be written (class, plugin, etc.)
+ /// Data to write
+ /// First part of the file name
+ /// Last part of the file name
+ /// What is the data about?
+ public static void WriteTo(string who, string outputPrefix, string outputSuffix, string whatWriting,
+ byte[] data)
+ {
+ if(!string.IsNullOrEmpty(outputPrefix) &&
+ !string.IsNullOrEmpty(outputSuffix))
+ WriteTo(who, outputPrefix + outputSuffix, data, whatWriting);
+ }
- /// Reads bytes at current position
- /// Array to place read data within
- /// Offset of where data will be read
- /// How many bytes to read
- /// How many bytes were read
- public int Read(byte[] array, int offset, int count) => _dataFs.Read(array, offset, count);
+ /// Writes data to a newly created file
+ /// Who asked the file to be written (class, plugin, etc.)
+ /// Filename to create
+ /// Data to write
+ /// What is the data about?
+ /// If set to true overwrites the file, does nothing otherwise
+ public static void WriteTo(string who, string filename, byte[] data, string whatWriting = null,
+ bool overwrite = false)
+ {
+ if(string.IsNullOrEmpty(filename))
+ return;
- /// Seeks to the specified block
- /// Block to seek to
- /// Block size in bytes
- /// Position
- public long Seek(ulong block, ulong blockSize) => _dataFs.Seek((long)(block * blockSize), SeekOrigin.Begin);
+ if(File.Exists(filename))
+ if(overwrite)
+ File.Delete(filename);
+ else
+ {
+ AaruConsole.ErrorWriteLine("Not overwriting file {0}", filename);
- /// Seeks to specified byte position
- /// Byte position
- /// Where to count for position
- /// Position
- public long Seek(ulong offset, SeekOrigin origin) => _dataFs.Seek((long)offset, origin);
-
- /// Seeks to specified byte position
- /// Byte position
- /// Where to count for position
- /// Position
- public long Seek(long offset, SeekOrigin origin) => _dataFs.Seek(offset, origin);
-
- /// Writes data at current position
- /// Data
- public void Write(byte[] data) => Write(data, 0, data.Length);
-
- /// Writes data at current position
- /// Data
- /// Offset of data from where to start taking data to write
- /// How many bytes to write
- public void Write(byte[] data, int offset, int count) => _dataFs.Write(data, offset, count);
-
- /// Writes data at specified block
- /// Data
- /// Block
- /// Bytes per block
- public void WriteAt(byte[] data, ulong block, uint blockSize) =>
- WriteAt(data, block, blockSize, 0, data.Length);
-
- /// Writes data at specified block
- /// Data
- /// Block
- /// Bytes per block
- /// Offset of data from where to start taking data to write
- /// How many bytes to write
- public void WriteAt(byte[] data, ulong block, uint blockSize, int offset, int count)
- {
- _dataFs.Seek((long)(block * blockSize), SeekOrigin.Begin);
- _dataFs.Write(data, offset, count);
- }
-
- /// Current file position
- public long Position => _dataFs.Position;
-
- /// Writes data to a newly created file
- /// Who asked the file to be written (class, plugin, etc.)
- /// Data to write
- /// First part of the file name
- /// Last part of the file name
- /// What is the data about?
- public static void WriteTo(string who, string outputPrefix, string outputSuffix, string whatWriting,
- byte[] data)
- {
- if(!string.IsNullOrEmpty(outputPrefix) &&
- !string.IsNullOrEmpty(outputSuffix))
- WriteTo(who, outputPrefix + outputSuffix, data, whatWriting);
- }
-
- /// Writes data to a newly created file
- /// Who asked the file to be written (class, plugin, etc.)
- /// Filename to create
- /// Data to write
- /// What is the data about?
- /// If set to true overwrites the file, does nothing otherwise
- public static void WriteTo(string who, string filename, byte[] data, string whatWriting = null,
- bool overwrite = false)
- {
- if(string.IsNullOrEmpty(filename))
return;
-
- if(File.Exists(filename))
- if(overwrite)
- File.Delete(filename);
- else
- {
- AaruConsole.ErrorWriteLine("Not overwriting file {0}", filename);
-
- return;
- }
-
- try
- {
- AaruConsole.DebugWriteLine(who, "Writing " + whatWriting + " to {0}", filename);
- var outputFs = new FileStream(filename, FileMode.CreateNew);
- outputFs.Write(data, 0, data.Length);
- outputFs.Close();
- }
- catch
- {
- AaruConsole.ErrorWriteLine("Unable to write file {0}", filename);
}
+
+ try
+ {
+ AaruConsole.DebugWriteLine(who, "Writing " + whatWriting + " to {0}", filename);
+ var outputFs = new FileStream(filename, FileMode.CreateNew);
+ outputFs.Write(data, 0, data.Length);
+ outputFs.Close();
+ }
+ catch
+ {
+ AaruConsole.ErrorWriteLine("Unable to write file {0}", filename);
}
}
}
\ No newline at end of file
diff --git a/Aaru.Core/Devices/Dumping/ATA.cs b/Aaru.Core/Devices/Dumping/ATA.cs
index a2e454b99..03f10035c 100644
--- a/Aaru.Core/Devices/Dumping/ATA.cs
+++ b/Aaru.Core/Devices/Dumping/ATA.cs
@@ -48,225 +48,331 @@ using Identify = Aaru.CommonTypes.Structs.Devices.ATA.Identify;
using Tuple = Aaru.Decoders.PCMCIA.Tuple;
using Version = Aaru.CommonTypes.Interop.Version;
-namespace Aaru.Core.Devices.Dumping
-{
- /// Implements dumping ATA devices
- public partial class Dump
- {
- /// Dumps an ATA device
- void Ata()
- {
- bool recoveredError;
- var outputFormat = _outputPlugin as IWritableImage;
+namespace Aaru.Core.Devices.Dumping;
- if(_dumpRaw)
+/// Implements dumping ATA devices
+public partial class Dump
+{
+ /// Dumps an ATA device
+ void Ata()
+ {
+ bool recoveredError;
+ var outputFormat = _outputPlugin as IWritableImage;
+
+ if(_dumpRaw)
+ {
+ if(_force)
+ ErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, continuing...");
+ else
{
- 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;
+ }
+ }
+
+ const ushort ataProfile = 0x0001;
+ const uint timeout = 5;
+ double imageWriteDuration = 0;
+ MediaType mediaType = MediaType.Unknown;
+
+ UpdateStatus?.Invoke("Requesting ATA IDENTIFY DEVICE.");
+ _dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE.");
+ bool sense = _dev.AtaIdentify(out byte[] cmdBuf, out AtaErrorRegistersChs errorChs);
+
+ if(sense)
+ _errorLog?.WriteLine("ATA IDENTIFY DEVICE", _dev.Error, _dev.LastError, errorChs);
+ else if(Identify.Decode(cmdBuf).HasValue)
+ {
+ Identify.IdentifyDevice? ataIdNullable = Identify.Decode(cmdBuf);
+
+ if(ataIdNullable != null)
+ {
+ Identify.IdentifyDevice ataId = ataIdNullable.Value;
+ byte[] ataIdentify = cmdBuf;
+ cmdBuf = Array.Empty();
+
+ DateTime start;
+ DateTime end;
+ double totalDuration = 0;
+ double currentSpeed = 0;
+ double maxSpeed = double.MinValue;
+ double minSpeed = double.MaxValue;
+
+ // Initialize reader
+ UpdateStatus?.Invoke("Initializing reader.");
+ _dumpLog.WriteLine("Initializing reader.");
+ var ataReader = new Reader(_dev, timeout, ataIdentify, _errorLog);
+
+ // Fill reader blocks
+ ulong blocks = ataReader.GetDeviceBlocks();
+
+ // Check block sizes
+ if(ataReader.GetBlockSize())
{
- StoppingErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, aborting...");
+ _dumpLog.WriteLine("ERROR: Cannot get block size: {0}.", ataReader.ErrorMessage);
+ ErrorMessage(ataReader.ErrorMessage);
return;
}
- }
- const ushort ataProfile = 0x0001;
- const uint timeout = 5;
- double imageWriteDuration = 0;
- MediaType mediaType = MediaType.Unknown;
+ uint blockSize = ataReader.LogicalBlockSize;
+ uint physicalSectorSize = ataReader.PhysicalBlockSize;
- UpdateStatus?.Invoke("Requesting ATA IDENTIFY DEVICE.");
- _dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE.");
- bool sense = _dev.AtaIdentify(out byte[] cmdBuf, out AtaErrorRegistersChs errorChs);
-
- if(sense)
- _errorLog?.WriteLine("ATA IDENTIFY DEVICE", _dev.Error, _dev.LastError, errorChs);
- else if(Identify.Decode(cmdBuf).HasValue)
- {
- Identify.IdentifyDevice? ataIdNullable = Identify.Decode(cmdBuf);
-
- if(ataIdNullable != null)
+ if(ataReader.FindReadCommand())
{
- Identify.IdentifyDevice ataId = ataIdNullable.Value;
- byte[] ataIdentify = cmdBuf;
- cmdBuf = Array.Empty();
+ _dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", ataReader.ErrorMessage);
+ ErrorMessage(ataReader.ErrorMessage);
- DateTime start;
- DateTime end;
- double totalDuration = 0;
- double currentSpeed = 0;
- double maxSpeed = double.MinValue;
- double minSpeed = double.MaxValue;
+ return;
+ }
- // Initialize reader
- UpdateStatus?.Invoke("Initializing reader.");
- _dumpLog.WriteLine("Initializing reader.");
- var ataReader = new Reader(_dev, timeout, ataIdentify, _errorLog);
+ // Check how many blocks to read, if error show and return
+ if(ataReader.GetBlocksToRead(_maximumReadable))
+ {
+ _dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", ataReader.ErrorMessage);
+ ErrorMessage(ataReader.ErrorMessage);
- // Fill reader blocks
- ulong blocks = ataReader.GetDeviceBlocks();
+ return;
+ }
- // Check block sizes
- if(ataReader.GetBlockSize())
+ uint blocksToRead = ataReader.BlocksToRead;
+ ushort cylinders = ataReader.Cylinders;
+ byte heads = ataReader.Heads;
+ 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 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,
+ _dev.FirmwareRevision, _private, _force);
+
+ if(currentTry == null ||
+ extents == null)
+ {
+ StoppingErrorMessage?.Invoke("Could not process resume file, not continuing...");
+
+ return;
+ }
+
+ MhddLog mhddLog;
+ IbgLog ibgLog;
+ double duration;
+
+ bool ret = true;
+
+ if(_dev.IsUsb &&
+ _dev.UsbDescriptors != null &&
+ !outputFormat.SupportedMediaTags.Contains(MediaTagType.USB_Descriptors))
+ {
+ ret = false;
+ _dumpLog.WriteLine("Output format does not support USB descriptors.");
+ ErrorMessage("Output format does not support USB descriptors.");
+ }
+
+ if(_dev.IsPcmcia &&
+ _dev.Cis != null &&
+ !outputFormat.SupportedMediaTags.Contains(MediaTagType.PCMCIA_CIS))
+ {
+ ret = false;
+ _dumpLog.WriteLine("Output format does not support PCMCIA CIS descriptors.");
+ ErrorMessage("Output format does not support PCMCIA CIS descriptors.");
+ }
+
+ if(!outputFormat.SupportedMediaTags.Contains(MediaTagType.ATA_IDENTIFY))
+ {
+ ret = false;
+ _dumpLog.WriteLine("Output format does not support ATA IDENTIFY.");
+ ErrorMessage("Output format does not support ATA IDENTIFY.");
+ }
+
+ if(!ret)
+ {
+ _dumpLog.WriteLine("Several media tags not supported, {0}continuing...", _force ? "" : "not ");
+
+ if(_force)
+ ErrorMessage("Several media tags not supported, continuing...");
+ else
{
- _dumpLog.WriteLine("ERROR: Cannot get block size: {0}.", ataReader.ErrorMessage);
- ErrorMessage(ataReader.ErrorMessage);
+ StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing...");
return;
}
+ }
- uint blockSize = ataReader.LogicalBlockSize;
- uint physicalSectorSize = ataReader.PhysicalBlockSize;
+ mediaType = MediaTypeFromDevice.GetFromAta(_dev.Manufacturer, _dev.Model, _dev.IsRemovable,
+ _dev.IsCompactFlash, _dev.IsPcmcia, blocks);
- if(ataReader.FindReadCommand())
+ ret = outputFormat.Create(_outputPath, mediaType, _formatOptions, blocks, blockSize);
+
+ // Cannot create image
+ if(!ret)
+ {
+ _dumpLog.WriteLine("Error creating output image, not continuing.");
+ _dumpLog.WriteLine(outputFormat.ErrorMessage);
+
+ StoppingErrorMessage?.Invoke("Error creating output image, not continuing." +
+ Environment.NewLine + outputFormat.ErrorMessage);
+
+ return;
+ }
+
+ // Setting geometry
+ outputFormat.SetGeometry(cylinders, heads, sectors);
+
+ if(ataReader.IsLba)
+ {
+ UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");
+
+ if(_skip < blocksToRead)
+ _skip = blocksToRead;
+
+ mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead,
+ _private);
+
+ ibgLog = new IbgLog(_outputPrefix + ".ibg", ataProfile);
+
+ if(_resume.NextBlock > 0)
{
- _dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", ataReader.ErrorMessage);
- ErrorMessage(ataReader.ErrorMessage);
-
- return;
+ UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}.");
+ _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock);
}
- // Check how many blocks to read, if error show and return
- if(ataReader.GetBlocksToRead(_maximumReadable))
+ bool newTrim = false;
+
+ start = DateTime.UtcNow;
+ DateTime timeSpeedStart = DateTime.UtcNow;
+ ulong sectorSpeedStart = 0;
+ InitProgress?.Invoke();
+
+ for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
{
- _dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", ataReader.ErrorMessage);
- ErrorMessage(ataReader.ErrorMessage);
+ if(_aborted)
+ {
+ currentTry.Extents = ExtentsConverter.ToMetadata(extents);
+ UpdateStatus?.Invoke("Aborted!");
+ _dumpLog.WriteLine("Aborted!");
- return;
- }
+ break;
+ }
- uint blocksToRead = ataReader.BlocksToRead;
- ushort cylinders = ataReader.Cylinders;
- byte heads = ataReader.Heads;
- byte sectors = ataReader.Sectors;
+ if(blocks - i < blocksToRead)
+ blocksToRead = (byte)(blocks - i);
- UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes).");
+ if(currentSpeed > maxSpeed &&
+ currentSpeed > 0)
+ maxSpeed = currentSpeed;
- UpdateStatus?.
- Invoke($"Device reports {cylinders} cylinders {heads} heads {sectors} sectors per track.");
+ if(currentSpeed < minSpeed &&
+ currentSpeed > 0)
+ minSpeed = currentSpeed;
- 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);
+ UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)",
+ (long)i, (long)blocks);
- _dumpLog.WriteLine("Device reports {0} cylinders {1} heads {2} sectors per track.", cylinders,
- heads, sectors);
+ bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration, out _, out _);
- _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,
- _dev.FirmwareRevision, _private, _force);
-
- if(currentTry == null ||
- extents == null)
- {
- StoppingErrorMessage?.Invoke("Could not process resume file, not continuing...");
-
- return;
- }
-
- MhddLog mhddLog;
- IbgLog ibgLog;
- double duration;
-
- bool ret = true;
-
- if(_dev.IsUsb &&
- _dev.UsbDescriptors != null &&
- !outputFormat.SupportedMediaTags.Contains(MediaTagType.USB_Descriptors))
- {
- ret = false;
- _dumpLog.WriteLine("Output format does not support USB descriptors.");
- ErrorMessage("Output format does not support USB descriptors.");
- }
-
- if(_dev.IsPcmcia &&
- _dev.Cis != null &&
- !outputFormat.SupportedMediaTags.Contains(MediaTagType.PCMCIA_CIS))
- {
- ret = false;
- _dumpLog.WriteLine("Output format does not support PCMCIA CIS descriptors.");
- ErrorMessage("Output format does not support PCMCIA CIS descriptors.");
- }
-
- if(!outputFormat.SupportedMediaTags.Contains(MediaTagType.ATA_IDENTIFY))
- {
- ret = false;
- _dumpLog.WriteLine("Output format does not support ATA IDENTIFY.");
- ErrorMessage("Output format does not support ATA IDENTIFY.");
- }
-
- if(!ret)
- {
- _dumpLog.WriteLine("Several media tags not supported, {0}continuing...", _force ? "" : "not ");
-
- if(_force)
- ErrorMessage("Several media tags not supported, continuing...");
+ if(!error)
+ {
+ mhddLog.Write(i, duration);
+ ibgLog.Write(i, currentSpeed * 1024);
+ DateTime writeStart = DateTime.Now;
+ outputFormat.WriteSectors(cmdBuf, i, blocksToRead);
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+ extents.Add(i, blocksToRead, true);
+ }
else
{
- StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing...");
+ if(i + _skip > blocks)
+ _skip = (uint)(blocks - i);
- return;
- }
- }
+ for(ulong b = i; b < i + _skip; b++)
+ _resume.BadBlocks.Add(b);
- mediaType = MediaTypeFromDevice.GetFromAta(_dev.Manufacturer, _dev.Model, _dev.IsRemovable,
- _dev.IsCompactFlash, _dev.IsPcmcia, blocks);
+ mhddLog.Write(i, duration < 500 ? 65535 : duration);
- ret = outputFormat.Create(_outputPath, mediaType, _formatOptions, blocks, blockSize);
-
- // Cannot create image
- if(!ret)
- {
- _dumpLog.WriteLine("Error creating output image, not continuing.");
- _dumpLog.WriteLine(outputFormat.ErrorMessage);
-
- StoppingErrorMessage?.Invoke("Error creating output image, not continuing." +
- Environment.NewLine + outputFormat.ErrorMessage);
-
- return;
- }
-
- // Setting geometry
- outputFormat.SetGeometry(cylinders, heads, sectors);
-
- if(ataReader.IsLba)
- {
- UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");
-
- if(_skip < blocksToRead)
- _skip = blocksToRead;
-
- mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead,
- _private);
-
- ibgLog = new IbgLog(_outputPrefix + ".ibg", ataProfile);
-
- if(_resume.NextBlock > 0)
- {
- UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}.");
- _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock);
+ ibgLog.Write(i, 0);
+ DateTime writeStart = DateTime.Now;
+ outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip);
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+ _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
+ i += _skip - blocksToRead;
+ newTrim = true;
}
- bool newTrim = false;
+ sectorSpeedStart += blocksToRead;
+ _resume.NextBlock = i + blocksToRead;
+ double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
+
+ if(elapsed <= 0)
+ continue;
+
+ currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
+ sectorSpeedStart = 0;
+ timeSpeedStart = DateTime.UtcNow;
+ }
+
+ _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();
+
+ 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 {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
+
+ UpdateStatus?.
+ Invoke($"Average write speed {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.",
+ blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
+
+ _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
+ blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
+
+ #region Trimming
+ if(_resume.BadBlocks.Count > 0 &&
+ !_aborted &&
+ _trim &&
+ newTrim)
+ {
start = DateTime.UtcNow;
- DateTime timeSpeedStart = DateTime.UtcNow;
- ulong sectorSpeedStart = 0;
+ UpdateStatus?.Invoke("Trimming skipped sectors");
+ _dumpLog.WriteLine("Trimming skipped sectors");
+
+ ulong[] tmpArray = _resume.BadBlocks.ToArray();
InitProgress?.Invoke();
- for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
+ foreach(ulong badSector in tmpArray)
{
if(_aborted)
{
@@ -277,147 +383,111 @@ namespace Aaru.Core.Devices.Dumping
break;
}
- if(blocks - i < blocksToRead)
- blocksToRead = (byte)(blocks - i);
+ PulseProgress?.Invoke($"Trimming sector {badSector}");
- if(currentSpeed > maxSpeed &&
- currentSpeed > 0)
- maxSpeed = currentSpeed;
+ bool error =
+ ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError, out _);
- if(currentSpeed < minSpeed &&
- currentSpeed > 0)
- minSpeed = currentSpeed;
+ totalDuration += duration;
- UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)",
- (long)i, (long)blocks);
-
- bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration, out _, out _);
-
- if(!error)
- {
- mhddLog.Write(i, duration);
- ibgLog.Write(i, currentSpeed * 1024);
- DateTime writeStart = DateTime.Now;
- outputFormat.WriteSectors(cmdBuf, i, blocksToRead);
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
- extents.Add(i, blocksToRead, true);
- }
- else
- {
- if(i + _skip > blocks)
- _skip = (uint)(blocks - i);
-
- for(ulong b = i; b < i + _skip; b++)
- _resume.BadBlocks.Add(b);
-
- mhddLog.Write(i, duration < 500 ? 65535 : duration);
-
- ibgLog.Write(i, 0);
- DateTime writeStart = DateTime.Now;
- outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip);
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
- _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
- i += _skip - blocksToRead;
- newTrim = true;
- }
-
- sectorSpeedStart += blocksToRead;
- _resume.NextBlock = i + blocksToRead;
-
- double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
-
- if(elapsed <= 0)
+ if(error && !recoveredError)
continue;
- currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
- sectorSpeedStart = 0;
- timeSpeedStart = DateTime.UtcNow;
+ _resume.BadBlocks.Remove(badSector);
+ extents.Add(badSector);
+ outputFormat.WriteSector(cmdBuf, badSector);
}
- _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();
-
- end = DateTime.Now;
EndProgress?.Invoke();
- mhddLog.Close();
+ end = DateTime.UtcNow;
+ UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds.");
+ _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds);
+ }
+ #endregion Trimming
- ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
- blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath);
+ #region Error handling
+ if(_resume.BadBlocks.Count > 0 &&
+ !_aborted &&
+ _retryPasses > 0)
+ {
+ int pass = 1;
+ bool forward = true;
- UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds.");
+ InitProgress?.Invoke();
+ repeatRetryLba:
+ ulong[] tmpArray = _resume.BadBlocks.ToArray();
- UpdateStatus?.
- Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
-
- UpdateStatus?.
- Invoke($"Average write speed {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.",
- blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
-
- _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
- blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
-
- #region Trimming
- if(_resume.BadBlocks.Count > 0 &&
- !_aborted &&
- _trim &&
- newTrim)
+ foreach(ulong badSector in tmpArray)
{
- start = DateTime.UtcNow;
- UpdateStatus?.Invoke("Trimming skipped sectors");
- _dumpLog.WriteLine("Trimming skipped sectors");
-
- ulong[] tmpArray = _resume.BadBlocks.ToArray();
- InitProgress?.Invoke();
-
- foreach(ulong badSector in tmpArray)
+ if(_aborted)
{
- if(_aborted)
- {
- currentTry.Extents = ExtentsConverter.ToMetadata(extents);
- UpdateStatus?.Invoke("Aborted!");
- _dumpLog.WriteLine("Aborted!");
+ currentTry.Extents = ExtentsConverter.ToMetadata(extents);
+ UpdateStatus?.Invoke("Aborted!");
+ _dumpLog.WriteLine("Aborted!");
- break;
- }
+ break;
+ }
- PulseProgress?.Invoke($"Trimming sector {badSector}");
+ PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector,
+ pass, forward ? "forward" : "reverse",
+ _persistent ? "recovering partial data, " : ""));
- bool error =
- ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError, out _);
+ bool error =
+ ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError, out _);
- totalDuration += duration;
-
- if(error && !recoveredError)
- continue;
+ totalDuration += duration;
+ if(!error || recoveredError)
+ {
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
outputFormat.WriteSector(cmdBuf, badSector);
+ UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");
+ _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
}
-
- EndProgress?.Invoke();
- end = DateTime.UtcNow;
- UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds.");
- _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds);
+ else if(_persistent)
+ outputFormat.WriteSector(cmdBuf, badSector);
}
- #endregion Trimming
- #region Error handling
- if(_resume.BadBlocks.Count > 0 &&
- !_aborted &&
- _retryPasses > 0)
+ if(pass < _retryPasses &&
+ !_aborted &&
+ _resume.BadBlocks.Count > 0)
{
- int pass = 1;
- bool forward = true;
+ pass++;
+ forward = !forward;
+ _resume.BadBlocks.Sort();
- InitProgress?.Invoke();
- repeatRetryLba:
- ulong[] tmpArray = _resume.BadBlocks.ToArray();
+ if(!forward)
+ _resume.BadBlocks.Reverse();
- foreach(ulong badSector in tmpArray)
+ goto repeatRetryLba;
+ }
+
+ EndProgress?.Invoke();
+ }
+ #endregion Error handling LBA
+
+ currentTry.Extents = ExtentsConverter.ToMetadata(extents);
+ }
+ else
+ {
+ mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead,
+ _private);
+
+ ibgLog = new IbgLog(_outputPrefix + ".ibg", ataProfile);
+
+ ulong currentBlock = 0;
+ blocks = (ulong)(cylinders * heads * sectors);
+ start = DateTime.UtcNow;
+ DateTime timeSpeedStart = DateTime.UtcNow;
+ ulong sectorSpeedStart = 0;
+ InitProgress?.Invoke();
+
+ for(ushort cy = 0; cy < cylinders; cy++)
+ {
+ for(byte hd = 0; hd < heads; hd++)
+ {
+ for(byte sc = 1; sc < sectors; sc++)
{
if(_aborted)
{
@@ -428,436 +498,365 @@ namespace Aaru.Core.Devices.Dumping
break;
}
- PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector,
- pass, forward ? "forward" : "reverse",
- _persistent ? "recovering partial data, " : ""));
+ if(currentSpeed > maxSpeed &&
+ currentSpeed > 0)
+ maxSpeed = currentSpeed;
+
+ if(currentSpeed < minSpeed &&
+ currentSpeed > 0)
+ minSpeed = currentSpeed;
+
+ PulseProgress?.
+ Invoke($"Reading cylinder {cy} head {hd} sector {sc} ({currentSpeed:F3} MiB/sec.)");
bool error =
- ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError, out _);
+ ataReader.ReadChs(out cmdBuf, cy, hd, sc, out duration, out recoveredError);
totalDuration += duration;
if(!error || recoveredError)
{
- _resume.BadBlocks.Remove(badSector);
- extents.Add(badSector);
- outputFormat.WriteSector(cmdBuf, badSector);
- UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");
- _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
+ mhddLog.Write(currentBlock, duration);
+ ibgLog.Write(currentBlock, currentSpeed * 1024);
+ DateTime writeStart = DateTime.Now;
+
+ outputFormat.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);
}
- else if(_persistent)
- outputFormat.WriteSector(cmdBuf, badSector);
- }
-
- if(pass < _retryPasses &&
- !_aborted &&
- _resume.BadBlocks.Count > 0)
- {
- pass++;
- forward = !forward;
- _resume.BadBlocks.Sort();
-
- if(!forward)
- _resume.BadBlocks.Reverse();
-
- goto repeatRetryLba;
- }
-
- EndProgress?.Invoke();
- }
- #endregion Error handling LBA
-
- currentTry.Extents = ExtentsConverter.ToMetadata(extents);
- }
- else
- {
- mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead,
- _private);
-
- ibgLog = new IbgLog(_outputPrefix + ".ibg", ataProfile);
-
- ulong currentBlock = 0;
- blocks = (ulong)(cylinders * heads * sectors);
- start = DateTime.UtcNow;
- DateTime timeSpeedStart = DateTime.UtcNow;
- ulong sectorSpeedStart = 0;
- InitProgress?.Invoke();
-
- for(ushort cy = 0; cy < cylinders; cy++)
- {
- for(byte hd = 0; hd < heads; hd++)
- {
- for(byte sc = 1; sc < sectors; sc++)
+ else
{
- if(_aborted)
- {
- currentTry.Extents = ExtentsConverter.ToMetadata(extents);
- UpdateStatus?.Invoke("Aborted!");
- _dumpLog.WriteLine("Aborted!");
+ _resume.BadBlocks.Add(currentBlock);
+ mhddLog.Write(currentBlock, duration < 500 ? 65535 : duration);
- break;
- }
+ ibgLog.Write(currentBlock, 0);
+ DateTime writeStart = DateTime.Now;
- if(currentSpeed > maxSpeed &&
- currentSpeed > 0)
- maxSpeed = currentSpeed;
+ outputFormat.WriteSector(new byte[blockSize],
+ (ulong)((((cy * heads) + hd) * sectors) + (sc - 1)));
- if(currentSpeed < minSpeed &&
- currentSpeed > 0)
- minSpeed = currentSpeed;
-
- PulseProgress?.
- Invoke($"Reading cylinder {cy} head {hd} sector {sc} ({currentSpeed:F3} MiB/sec.)");
-
- bool error =
- ataReader.ReadChs(out cmdBuf, cy, hd, sc, out duration, out recoveredError);
-
- totalDuration += duration;
-
- if(!error || recoveredError)
- {
- mhddLog.Write(currentBlock, duration);
- ibgLog.Write(currentBlock, currentSpeed * 1024);
- DateTime writeStart = DateTime.Now;
-
- outputFormat.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);
- }
- else
- {
- _resume.BadBlocks.Add(currentBlock);
- mhddLog.Write(currentBlock, duration < 500 ? 65535 : duration);
-
- ibgLog.Write(currentBlock, 0);
- DateTime writeStart = DateTime.Now;
-
- outputFormat.WriteSector(new byte[blockSize],
- (ulong)((((cy * heads) + hd) * sectors) + (sc - 1)));
-
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
- }
-
- sectorSpeedStart++;
- currentBlock++;
-
- double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
-
- if(elapsed <= 0)
- continue;
-
- currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
- sectorSpeedStart = 0;
- timeSpeedStart = DateTime.UtcNow;
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
}
+
+ sectorSpeedStart++;
+ currentBlock++;
+
+ double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
+
+ if(elapsed <= 0)
+ continue;
+
+ currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
+ sectorSpeedStart = 0;
+ timeSpeedStart = DateTime.UtcNow;
}
}
-
- _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();
-
- 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 {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
-
- UpdateStatus?.
- Invoke($"Average write speed {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.",
- blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
-
- _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
- blockSize * (double)(blocks + 1) / 1024 / (imageWriteDuration / 1000));
}
- foreach(ulong bad in _resume.BadBlocks)
- _dumpLog.WriteLine("Sector {0} could not be read.", bad);
+ _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();
- outputFormat.SetDumpHardware(_resume.Tries);
+ end = DateTime.Now;
+ EndProgress?.Invoke();
+ mhddLog.Close();
- // TODO: Non-removable
- var metadata = new CommonTypes.Structs.ImageInfo
+ 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 {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec.");
+
+ UpdateStatus?.
+ Invoke($"Average write speed {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.",
+ blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
+
+ _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
+ blockSize * (double)(blocks + 1) / 1024 / (imageWriteDuration / 1000));
+ }
+
+ foreach(ulong bad in _resume.BadBlocks)
+ _dumpLog.WriteLine("Sector {0} could not be read.", bad);
+
+ outputFormat.SetDumpHardware(_resume.Tries);
+
+ // TODO: Non-removable
+ var metadata = new CommonTypes.Structs.ImageInfo
+ {
+ Application = "Aaru",
+ ApplicationVersion = Version.GetVersion()
+ };
+
+ if(!outputFormat.SetMetadata(metadata))
+ ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine +
+ outputFormat.ErrorMessage);
+
+ if(_preSidecar != null)
+ outputFormat.SetCicmMetadata(_preSidecar);
+
+ _dumpLog.WriteLine("Closing output file.");
+ UpdateStatus?.Invoke("Closing output file.");
+ DateTime closeStart = DateTime.Now;
+ outputFormat.Close();
+ DateTime closeEnd = DateTime.Now;
+ UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds.");
+ _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds);
+
+ if(_aborted)
+ {
+ _dumpLog.WriteLine("Aborted!");
+ UpdateStatus?.Invoke("Aborted!");
+
+ return;
+ }
+
+ double totalChkDuration = 0;
+
+ outputFormat.WriteMediaTag(ataIdentify, MediaTagType.ATA_IDENTIFY);
+
+ if(_dev.IsUsb &&
+ _dev.UsbDescriptors != null)
+ outputFormat.WriteMediaTag(_dev.UsbDescriptors, MediaTagType.USB_Descriptors);
+
+ if(_dev.IsPcmcia &&
+ _dev.Cis != null)
+ outputFormat.WriteMediaTag(_dev.Cis, MediaTagType.PCMCIA_CIS);
+
+ if(_metadata)
+ {
+ _dumpLog.WriteLine("Creating sidecar.");
+ UpdateStatus?.Invoke("Creating sidecar.");
+ var filters = new FiltersList();
+ IFilter filter = filters.GetFilter(_outputPath);
+ IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
+ ErrorNumber opened = inputPlugin.Open(filter);
+
+ if(opened != ErrorNumber.NoError)
{
- Application = "Aaru",
- ApplicationVersion = Version.GetVersion()
- };
-
- if(!outputFormat.SetMetadata(metadata))
- ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine +
- outputFormat.ErrorMessage);
-
- if(_preSidecar != null)
- outputFormat.SetCicmMetadata(_preSidecar);
-
- _dumpLog.WriteLine("Closing output file.");
- UpdateStatus?.Invoke("Closing output file.");
- DateTime closeStart = DateTime.Now;
- outputFormat.Close();
- DateTime closeEnd = DateTime.Now;
- UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds.");
- _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds);
-
- if(_aborted)
- {
- _dumpLog.WriteLine("Aborted!");
- UpdateStatus?.Invoke("Aborted!");
+ StoppingErrorMessage?.Invoke($"Error {opened} opening created image.");
return;
}
- double totalChkDuration = 0;
+ DateTime chkStart = DateTime.UtcNow;
- outputFormat.WriteMediaTag(ataIdentify, MediaTagType.ATA_IDENTIFY);
+ _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding);
- if(_dev.IsUsb &&
- _dev.UsbDescriptors != null)
- outputFormat.WriteMediaTag(_dev.UsbDescriptors, MediaTagType.USB_Descriptors);
+ _sidecarClass.InitProgressEvent += InitProgress;
+ _sidecarClass.UpdateProgressEvent += UpdateProgress;
+ _sidecarClass.EndProgressEvent += EndProgress;
+ _sidecarClass.InitProgressEvent2 += InitProgress2;
+ _sidecarClass.UpdateProgressEvent2 += UpdateProgress2;
+ _sidecarClass.EndProgressEvent2 += EndProgress2;
+ _sidecarClass.UpdateStatusEvent += UpdateStatus;
+ CICMMetadataType sidecar = _sidecarClass.Create();
- if(_dev.IsPcmcia &&
- _dev.Cis != null)
- outputFormat.WriteMediaTag(_dev.Cis, MediaTagType.PCMCIA_CIS);
-
- if(_metadata)
+ if(!_aborted)
{
- _dumpLog.WriteLine("Creating sidecar.");
- UpdateStatus?.Invoke("Creating sidecar.");
- var filters = new FiltersList();
- IFilter filter = filters.GetFilter(_outputPath);
- IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
- ErrorNumber opened = inputPlugin.Open(filter);
-
- if(opened != ErrorNumber.NoError)
+ if(_preSidecar != null)
{
- StoppingErrorMessage?.Invoke($"Error {opened} opening created image.");
-
- return;
+ _preSidecar.BlockMedia = sidecar.BlockMedia;
+ sidecar = _preSidecar;
}
- DateTime chkStart = DateTime.UtcNow;
-
- _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding);
-
- _sidecarClass.InitProgressEvent += InitProgress;
- _sidecarClass.UpdateProgressEvent += UpdateProgress;
- _sidecarClass.EndProgressEvent += EndProgress;
- _sidecarClass.InitProgressEvent2 += InitProgress2;
- _sidecarClass.UpdateProgressEvent2 += UpdateProgress2;
- _sidecarClass.EndProgressEvent2 += EndProgress2;
- _sidecarClass.UpdateStatusEvent += UpdateStatus;
- CICMMetadataType sidecar = _sidecarClass.Create();
-
- if(!_aborted)
+ if(_dev.IsUsb &&
+ _dev.UsbDescriptors != null)
{
- if(_preSidecar != null)
+ _dumpLog.WriteLine("Reading USB descriptors.");
+ UpdateStatus?.Invoke("Reading USB descriptors.");
+
+ sidecar.BlockMedia[0].USB = new USBType
{
- _preSidecar.BlockMedia = sidecar.BlockMedia;
- sidecar = _preSidecar;
- }
-
- if(_dev.IsUsb &&
- _dev.UsbDescriptors != null)
- {
- _dumpLog.WriteLine("Reading USB descriptors.");
- UpdateStatus?.Invoke("Reading USB descriptors.");
-
- sidecar.BlockMedia[0].USB = new USBType
- {
- ProductID = _dev.UsbProductId,
- VendorID = _dev.UsbVendorId,
- Descriptors = new DumpType
- {
- Image = _outputPath,
- Size = (ulong)_dev.UsbDescriptors.Length,
- Checksums = Checksum.GetChecksums(_dev.UsbDescriptors).ToArray()
- }
- };
- }
-
- if(_dev.IsPcmcia &&
- _dev.Cis != null)
- {
- _dumpLog.WriteLine("Reading PCMCIA CIS.");
- UpdateStatus?.Invoke("Reading PCMCIA CIS.");
-
- sidecar.BlockMedia[0].PCMCIA = new PCMCIAType
- {
- CIS = new DumpType
- {
- Image = _outputPath,
- Size = (ulong)_dev.Cis.Length,
- Checksums = Checksum.GetChecksums(_dev.Cis).ToArray()
- }
- };
-
- _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)
- {
- case TupleCodes.CISTPL_MANFID:
- ManufacturerIdentificationTuple manufacturerId =
- CIS.DecodeManufacturerIdentificationTuple(tuple);
-
- if(manufacturerId != null)
- {
- sidecar.BlockMedia[0].PCMCIA.ManufacturerCode =
- manufacturerId.ManufacturerID;
-
- sidecar.BlockMedia[0].PCMCIA.CardCode = manufacturerId.CardID;
- sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true;
- sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true;
- }
-
- break;
- case TupleCodes.CISTPL_VERS_1:
- Level1VersionTuple version = CIS.DecodeLevel1VersionTuple(tuple);
-
- if(version != null)
- {
- sidecar.BlockMedia[0].PCMCIA.Manufacturer = version.Manufacturer;
- sidecar.BlockMedia[0].PCMCIA.ProductName = version.Product;
-
- sidecar.BlockMedia[0].PCMCIA.Compliance =
- $"{version.MajorVersion}.{version.MinorVersion}";
-
- sidecar.BlockMedia[0].PCMCIA.AdditionalInformation =
- version.AdditionalInformation;
- }
-
- break;
- }
- }
-
- if(_private)
- DeviceReport.ClearIdentify(ataIdentify);
-
- sidecar.BlockMedia[0].ATA = new ATAType
- {
- Identify = new DumpType
+ ProductID = _dev.UsbProductId,
+ VendorID = _dev.UsbVendorId,
+ Descriptors = new DumpType
{
Image = _outputPath,
- Size = (ulong)cmdBuf.Length,
- Checksums = Checksum.GetChecksums(cmdBuf).ToArray()
+ Size = (ulong)_dev.UsbDescriptors.Length,
+ Checksums = Checksum.GetChecksums(_dev.UsbDescriptors).ToArray()
+ }
+ };
+ }
+
+ if(_dev.IsPcmcia &&
+ _dev.Cis != null)
+ {
+ _dumpLog.WriteLine("Reading PCMCIA CIS.");
+ UpdateStatus?.Invoke("Reading PCMCIA CIS.");
+
+ sidecar.BlockMedia[0].PCMCIA = new PCMCIAType
+ {
+ CIS = new DumpType
+ {
+ Image = _outputPath,
+ Size = (ulong)_dev.Cis.Length,
+ Checksums = Checksum.GetChecksums(_dev.Cis).ToArray()
}
};
- DateTime chkEnd = DateTime.UtcNow;
+ _dumpLog.WriteLine("Decoding PCMCIA CIS.");
+ UpdateStatus?.Invoke("Decoding PCMCIA CIS.");
+ Tuple[] tuples = CIS.GetTuples(_dev.Cis);
- totalChkDuration = (chkEnd - chkStart).TotalMilliseconds;
- UpdateStatus?.Invoke($"Sidecar created in {(chkEnd - chkStart).TotalSeconds} seconds.");
+ if(tuples != null)
+ foreach(Tuple tuple in tuples)
+ switch(tuple.Code)
+ {
+ case TupleCodes.CISTPL_MANFID:
+ ManufacturerIdentificationTuple manufacturerId =
+ CIS.DecodeManufacturerIdentificationTuple(tuple);
- UpdateStatus?.
- Invoke($"Average checksum speed {blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec.");
+ if(manufacturerId != null)
+ {
+ sidecar.BlockMedia[0].PCMCIA.ManufacturerCode =
+ manufacturerId.ManufacturerID;
- _dumpLog.WriteLine("Sidecar created in {0} seconds.", (chkEnd - chkStart).TotalSeconds);
+ sidecar.BlockMedia[0].PCMCIA.CardCode = manufacturerId.CardID;
+ sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true;
+ sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true;
+ }
- _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
- blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000));
+ break;
+ case TupleCodes.CISTPL_VERS_1:
+ Level1VersionTuple version = CIS.DecodeLevel1VersionTuple(tuple);
- List<(ulong start, string type)> filesystems = new();
+ if(version != null)
+ {
+ sidecar.BlockMedia[0].PCMCIA.Manufacturer = version.Manufacturer;
+ sidecar.BlockMedia[0].PCMCIA.ProductName = version.Product;
- if(sidecar.BlockMedia[0].FileSystemInformation != null)
- filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation
- where partition.FileSystems != null
- from fileSystem in partition.FileSystems
- select (partition.StartSector, fileSystem.Type));
+ sidecar.BlockMedia[0].PCMCIA.Compliance =
+ $"{version.MajorVersion}.{version.MinorVersion}";
- if(filesystems.Count > 0)
- foreach(var filesystem in filesystems.Select(o => new
- {
- o.start,
- o.type
- }).Distinct())
- {
- UpdateStatus?.
- Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}");
+ sidecar.BlockMedia[0].PCMCIA.AdditionalInformation =
+ version.AdditionalInformation;
+ }
- _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type,
- filesystem.start);
- }
+ break;
+ }
+ }
- (string type, string subType) = CommonTypes.Metadata.MediaType.MediaTypeToString(mediaType);
+ if(_private)
+ DeviceReport.ClearIdentify(ataIdentify);
- sidecar.BlockMedia[0].DiskType = type;
- sidecar.BlockMedia[0].DiskSubType = subType;
- sidecar.BlockMedia[0].Interface = "ATA";
- sidecar.BlockMedia[0].LogicalBlocks = blocks;
- sidecar.BlockMedia[0].PhysicalBlockSize = physicalSectorSize;
- sidecar.BlockMedia[0].LogicalBlockSize = blockSize;
- sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer;
- sidecar.BlockMedia[0].Model = _dev.Model;
-
- if(!_private)
- sidecar.BlockMedia[0].Serial = _dev.Serial;
-
- sidecar.BlockMedia[0].Size = blocks * blockSize;
-
- if(cylinders > 0 &&
- heads > 0 &&
- sectors > 0)
+ sidecar.BlockMedia[0].ATA = new ATAType
+ {
+ Identify = new DumpType
{
- sidecar.BlockMedia[0].Cylinders = cylinders;
- sidecar.BlockMedia[0].CylindersSpecified = true;
- sidecar.BlockMedia[0].Heads = heads;
- sidecar.BlockMedia[0].HeadsSpecified = true;
- sidecar.BlockMedia[0].SectorsPerTrack = sectors;
- sidecar.BlockMedia[0].SectorsPerTrackSpecified = true;
+ Image = _outputPath,
+ Size = (ulong)cmdBuf.Length,
+ Checksums = Checksum.GetChecksums(cmdBuf).ToArray()
+ }
+ };
+
+ DateTime chkEnd = DateTime.UtcNow;
+
+ totalChkDuration = (chkEnd - chkStart).TotalMilliseconds;
+ UpdateStatus?.Invoke($"Sidecar created in {(chkEnd - chkStart).TotalSeconds} seconds.");
+
+ UpdateStatus?.
+ Invoke($"Average checksum speed {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.",
+ blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000));
+
+ List<(ulong start, string type)> filesystems = new();
+
+ if(sidecar.BlockMedia[0].FileSystemInformation != null)
+ filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation
+ where partition.FileSystems != null
+ from fileSystem in partition.FileSystems
+ select (partition.StartSector, fileSystem.Type));
+
+ if(filesystems.Count > 0)
+ foreach(var filesystem in filesystems.Select(o => new
+ {
+ 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);
}
- UpdateStatus?.Invoke("Writing metadata sidecar");
+ (string type, string subType) = CommonTypes.Metadata.MediaType.MediaTypeToString(mediaType);
- var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create);
+ sidecar.BlockMedia[0].DiskType = type;
+ sidecar.BlockMedia[0].DiskSubType = subType;
+ sidecar.BlockMedia[0].Interface = "ATA";
+ sidecar.BlockMedia[0].LogicalBlocks = blocks;
+ sidecar.BlockMedia[0].PhysicalBlockSize = physicalSectorSize;
+ sidecar.BlockMedia[0].LogicalBlockSize = blockSize;
+ sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer;
+ sidecar.BlockMedia[0].Model = _dev.Model;
- var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
- xmlSer.Serialize(xmlFs, sidecar);
- xmlFs.Close();
+ if(!_private)
+ sidecar.BlockMedia[0].Serial = _dev.Serial;
+
+ sidecar.BlockMedia[0].Size = blocks * blockSize;
+
+ if(cylinders > 0 &&
+ heads > 0 &&
+ sectors > 0)
+ {
+ sidecar.BlockMedia[0].Cylinders = cylinders;
+ sidecar.BlockMedia[0].CylindersSpecified = true;
+ sidecar.BlockMedia[0].Heads = heads;
+ sidecar.BlockMedia[0].HeadsSpecified = true;
+ sidecar.BlockMedia[0].SectorsPerTrack = sectors;
+ sidecar.BlockMedia[0].SectorsPerTrackSpecified = true;
}
+
+ UpdateStatus?.Invoke("Writing metadata sidecar");
+
+ var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create);
+
+ 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: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");
-
- if(maxSpeed > 0)
- UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec.");
-
- if(minSpeed > 0 &&
- minSpeed < double.MaxValue)
- 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();
-
- UpdateStatus?.Invoke("");
}
- Statistics.AddMedia(mediaType, true);
+ 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: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");
+
+ if(maxSpeed > 0)
+ UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec.");
+
+ if(minSpeed > 0 &&
+ minSpeed < double.MaxValue)
+ 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();
+
+ UpdateStatus?.Invoke("");
}
- else
- StoppingErrorMessage?.Invoke("Unable to communicate with ATA device.");
+
+ Statistics.AddMedia(mediaType, true);
}
+ else
+ StoppingErrorMessage?.Invoke("Unable to communicate with ATA device.");
}
}
\ No newline at end of file
diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs b/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs
index 7bf84424b..c567b7b81 100644
--- a/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs
+++ b/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs
@@ -45,373 +45,372 @@ using Schemas;
// ReSharper disable InlineOutVariableDeclaration
// ReSharper disable TooWideLocalVariableScope
-namespace Aaru.Core.Devices.Dumping
+namespace Aaru.Core.Devices.Dumping;
+
+partial class Dump
{
- partial class Dump
+ /// Detects if a sector contains data
+ /// Sector contents
+ /// true if it contains Yellow Book data, false otherwise
+ static bool IsData(byte[] sector)
{
- /// Detects if a sector contains data
- /// Sector contents
- /// true if it contains Yellow Book data, false otherwise
- static bool IsData(byte[] sector)
+ if(sector?.Length != 2352)
+ return false;
+
+ byte[] syncMark =
{
- if(sector?.Length != 2352)
- return false;
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
+ };
- byte[] syncMark =
- {
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
- };
+ byte[] testMark = new byte[12];
+ Array.Copy(sector, 0, testMark, 0, 12);
- byte[] testMark = new byte[12];
- Array.Copy(sector, 0, testMark, 0, 12);
+ return syncMark.SequenceEqual(testMark) && (sector[0xF] == 0 || sector[0xF] == 1 || sector[0xF] == 2);
+ }
- return syncMark.SequenceEqual(testMark) && (sector[0xF] == 0 || sector[0xF] == 1 || sector[0xF] == 2);
+ /// Detects if a sector contains scrambled data
+ /// Sector contents
+ /// What LBA we intended to read
+ /// Offset in bytes, if found
+ /// true if it contains Yellow Book data, false otherwise
+ static bool IsScrambledData(byte[] sector, int wantedLba, out int? offset)
+ {
+ offset = 0;
+
+ if(sector?.Length != 2352)
+ return false;
+
+ byte[] syncMark =
+ {
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
+ };
+
+ byte[] testMark = new byte[12];
+
+ for(int i = 0; i <= 2336; i++)
+ {
+ Array.Copy(sector, i, testMark, 0, 12);
+
+ if(!syncMark.SequenceEqual(testMark) ||
+ (sector[i + 0xF] != 0x60 && sector[i + 0xF] != 0x61 && sector[i + 0xF] != 0x62))
+ continue;
+
+ // De-scramble M and S
+ int minute = sector[i + 12] ^ 0x01;
+ int second = sector[i + 13] ^ 0x80;
+ int frame = sector[i + 14];
+
+ // Convert to binary
+ minute = (minute / 16 * 10) + (minute & 0x0F);
+ second = (second / 16 * 10) + (second & 0x0F);
+ frame = (frame / 16 * 10) + (frame & 0x0F);
+
+ // Calculate the first found LBA
+ int lba = (minute * 60 * 75) + (second * 75) + frame - 150;
+
+ // Calculate the difference between the found LBA and the requested one
+ int diff = wantedLba - lba;
+
+ offset = i + (2352 * diff);
+
+ return true;
}
- /// Detects if a sector contains scrambled data
- /// Sector contents
- /// What LBA we intended to read
- /// Offset in bytes, if found
- /// true if it contains Yellow Book data, false otherwise
- static bool IsScrambledData(byte[] sector, int wantedLba, out int? offset)
+ return false;
+ }
+
+ // TODO: Set pregap for Track 1
+ // TODO: Detect errors in sectors
+ /// Reads all the hidden track in CD-i Ready discs
+ /// 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
+ /// Read offset
+ /// Sectors needed to fix offset
+ /// Subchannel size in bytes
+ /// Drive's maximum supported subchannel
+ /// Total commands duration
+ /// Is the drive returning CD-i Ready hidden track as audio?
+ /// Disc tracks
+ /// Subchannel log
+ /// Subchannel desired to save
+ /// List of disc ISRCs
+ /// Disc media catalogue number
+ /// List of subchannels not yet dumped correctly
+ /// List of smallest pregap relative address per track
+ void ReadCdiReady(uint blockSize, ref double currentSpeed, DumpHardwareType currentTry, ExtentsULong extents,
+ IbgLog ibgLog, ref double imageWriteDuration, ExtentsULong leadOutExtents,
+ ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, uint subSize,
+ MmcSubchannel supportedSubchannel, ref double totalDuration, Track[] tracks,
+ SubchannelLog subLog, MmcSubchannel desiredSubchannel, Dictionary isrcs,
+ ref string mcn, HashSet subchannelExtents, ulong blocks, bool cdiReadyReadAsAudio,
+ int offsetBytes, int sectorsForOffset, Dictionary smallestPregapLbaPerTrack)
+ {
+ ulong sectorSpeedStart = 0; // Used to calculate correct speed
+ DateTime timeSpeedStart = DateTime.UtcNow; // Time of start for speed calculation
+ bool sense; // Sense indicator
+ byte[] cmdBuf; // Data buffer
+ byte[] senseBuf; // Sense buffer
+ double cmdDuration; // Command execution time
+ const uint sectorSize = 2352; // Full sector size
+ Track firstTrack = tracks.FirstOrDefault(t => t.Sequence == 1);
+ uint blocksToRead; // How many sectors to read at once
+ var outputOptical = _outputPlugin as IWritableOpticalImage;
+
+ if(firstTrack is null)
+ return;
+
+ if(cdiReadyReadAsAudio)
{
- offset = 0;
+ _dumpLog.WriteLine("Setting speed to 8x for CD-i Ready reading as audio.");
+ UpdateStatus?.Invoke("Setting speed to 8x for CD-i Ready reading as audio.");
- if(sector?.Length != 2352)
- return false;
+ _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _);
+ }
- byte[] syncMark =
+ InitProgress?.Invoke();
+
+ for(ulong i = _resume.NextBlock; i < firstTrack.StartSector; i += blocksToRead)
+ {
+ if(_aborted)
{
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
- };
+ currentTry.Extents = ExtentsConverter.ToMetadata(extents);
+ UpdateStatus?.Invoke("Aborted!");
+ _dumpLog.WriteLine("Aborted!");
- byte[] testMark = new byte[12];
-
- for(int i = 0; i <= 2336; i++)
- {
- Array.Copy(sector, i, testMark, 0, 12);
-
- if(!syncMark.SequenceEqual(testMark) ||
- (sector[i + 0xF] != 0x60 && sector[i + 0xF] != 0x61 && sector[i + 0xF] != 0x62))
- continue;
-
- // De-scramble M and S
- int minute = sector[i + 12] ^ 0x01;
- int second = sector[i + 13] ^ 0x80;
- int frame = sector[i + 14];
-
- // Convert to binary
- minute = (minute / 16 * 10) + (minute & 0x0F);
- second = (second / 16 * 10) + (second & 0x0F);
- frame = (frame / 16 * 10) + (frame & 0x0F);
-
- // Calculate the first found LBA
- int lba = (minute * 60 * 75) + (second * 75) + frame - 150;
-
- // Calculate the difference between the found LBA and the requested one
- int diff = wantedLba - lba;
-
- offset = i + (2352 * diff);
-
- return true;
+ break;
}
- return false;
- }
+ uint firstSectorToRead = (uint)i;
- // TODO: Set pregap for Track 1
- // TODO: Detect errors in sectors
- /// Reads all the hidden track in CD-i Ready discs
- /// 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
- /// Read offset
- /// Sectors needed to fix offset
- /// Subchannel size in bytes
- /// Drive's maximum supported subchannel
- /// Total commands duration
- /// Is the drive returning CD-i Ready hidden track as audio?
- /// Disc tracks
- /// Subchannel log
- /// Subchannel desired to save
- /// List of disc ISRCs
- /// Disc media catalogue number
- /// List of subchannels not yet dumped correctly
- /// List of smallest pregap relative address per track
- void ReadCdiReady(uint blockSize, ref double currentSpeed, DumpHardwareType currentTry, ExtentsULong extents,
- IbgLog ibgLog, ref double imageWriteDuration, ExtentsULong leadOutExtents,
- ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, uint subSize,
- MmcSubchannel supportedSubchannel, ref double totalDuration, Track[] tracks,
- SubchannelLog subLog, MmcSubchannel desiredSubchannel, Dictionary isrcs,
- ref string mcn, HashSet subchannelExtents, ulong blocks, bool cdiReadyReadAsAudio,
- int offsetBytes, int sectorsForOffset, Dictionary smallestPregapLbaPerTrack)
- {
- ulong sectorSpeedStart = 0; // Used to calculate correct speed
- DateTime timeSpeedStart = DateTime.UtcNow; // Time of start for speed calculation
- bool sense; // Sense indicator
- byte[] cmdBuf; // Data buffer
- byte[] senseBuf; // Sense buffer
- double cmdDuration; // Command execution time
- const uint sectorSize = 2352; // Full sector size
- Track firstTrack = tracks.FirstOrDefault(t => t.Sequence == 1);
- uint blocksToRead; // How many sectors to read at once
- var outputOptical = _outputPlugin as IWritableOpticalImage;
+ blocksToRead = _maximumReadable;
- if(firstTrack is null)
- return;
+ if(blocksToRead == 1 && cdiReadyReadAsAudio)
+ blocksToRead += (uint)sectorsForOffset;
if(cdiReadyReadAsAudio)
{
- _dumpLog.WriteLine("Setting speed to 8x for CD-i Ready reading as audio.");
- UpdateStatus?.Invoke("Setting speed to 8x for CD-i Ready reading as audio.");
-
- _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _);
+ if(offsetBytes < 0)
+ {
+ if(i == 0)
+ firstSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1
+ else
+ firstSectorToRead -= (uint)sectorsForOffset;
+ }
}
- InitProgress?.Invoke();
+ if(currentSpeed > maxSpeed &&
+ currentSpeed > 0)
+ maxSpeed = currentSpeed;
- for(ulong i = _resume.NextBlock; i < firstTrack.StartSector; i += blocksToRead)
+ if(currentSpeed < minSpeed &&
+ currentSpeed > 0)
+ minSpeed = currentSpeed;
+
+ UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
+ (long)blocks);
+
+ sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
+ MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true,
+ MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration);
+
+ totalDuration += cmdDuration;
+
+ double elapsed;
+
+ // Overcome the track mode change drive error
+ if(sense)
{
- if(_aborted)
+ for(uint r = 0; r < _maximumReadable; r++)
{
- currentTry.Extents = ExtentsConverter.ToMetadata(extents);
- UpdateStatus?.Invoke("Aborted!");
- _dumpLog.WriteLine("Aborted!");
+ UpdateProgress?.Invoke($"Reading sector {i + r} of {blocks} ({currentSpeed:F3} MiB/sec.)",
+ (long)i + r, (long)blocks);
- break;
- }
+ sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(i + r), blockSize,
+ (uint)sectorsForOffset + 1, MmcSectorTypes.AllTypes, false, false, true,
+ MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
+ supportedSubchannel, _dev.Timeout, out cmdDuration);
- uint firstSectorToRead = (uint)i;
+ totalDuration += cmdDuration;
- blocksToRead = _maximumReadable;
-
- if(blocksToRead == 1 && cdiReadyReadAsAudio)
- blocksToRead += (uint)sectorsForOffset;
-
- if(cdiReadyReadAsAudio)
- {
- if(offsetBytes < 0)
+ if(!sense &&
+ !_dev.Error)
{
- if(i == 0)
- firstSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1
- else
- firstSectorToRead -= (uint)sectorsForOffset;
- }
- }
+ mhddLog.Write(i + r, cmdDuration);
+ ibgLog.Write(i + r, currentSpeed * 1024);
+ extents.Add(i + r, 1, true);
+ DateTime writeStart = DateTime.Now;
- if(currentSpeed > maxSpeed &&
- currentSpeed > 0)
- maxSpeed = currentSpeed;
+ if(cdiReadyReadAsAudio)
+ FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
+ ref blocksToRead, subSize, ref cmdBuf, blockSize, false);
- if(currentSpeed < minSpeed &&
- currentSpeed > 0)
- minSpeed = currentSpeed;
-
- UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
- (long)blocks);
-
- sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
- MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true,
- MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration);
-
- totalDuration += cmdDuration;
-
- double elapsed;
-
- // Overcome the track mode change drive error
- if(sense)
- {
- for(uint r = 0; r < _maximumReadable; r++)
- {
- UpdateProgress?.Invoke($"Reading sector {i + r} of {blocks} ({currentSpeed:F3} MiB/sec.)",
- (long)i + r, (long)blocks);
-
- sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(i + r), blockSize,
- (uint)sectorsForOffset + 1, MmcSectorTypes.AllTypes, false, false, true,
- MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
- supportedSubchannel, _dev.Timeout, out cmdDuration);
-
- totalDuration += cmdDuration;
-
- if(!sense &&
- !_dev.Error)
+ if(supportedSubchannel != MmcSubchannel.None)
{
- mhddLog.Write(i + r, cmdDuration);
- ibgLog.Write(i + r, currentSpeed * 1024);
- extents.Add(i + r, 1, true);
- DateTime writeStart = DateTime.Now;
+ byte[] data = new byte[sectorSize];
+ byte[] sub = new byte[subSize];
+
+ Array.Copy(cmdBuf, 0, data, 0, sectorSize);
+
+ Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
if(cdiReadyReadAsAudio)
- FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
- ref blocksToRead, subSize, ref cmdBuf, blockSize, false);
+ data = Sector.Scramble(data);
- if(supportedSubchannel != MmcSubchannel.None)
+ outputOptical.WriteSectorsLong(data, i + r, 1);
+
+ bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
+ desiredSubchannel, sub, i + r, 1, subLog, isrcs, 1, ref mcn, tracks,
+ subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel,
+ _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true);
+
+ // Set tracks and go back
+ if(indexesChanged)
{
- byte[] data = new byte[sectorSize];
- byte[] sub = new byte[subSize];
+ (outputOptical as IWritableOpticalImage).SetTracks(tracks.ToList());
+ i -= _maximumReadable;
- Array.Copy(cmdBuf, 0, data, 0, sectorSize);
-
- Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
-
- if(cdiReadyReadAsAudio)
- data = Sector.Scramble(data);
-
- outputOptical.WriteSectorsLong(data, i + r, 1);
-
- bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
- desiredSubchannel, sub, i + r, 1, subLog, isrcs, 1, ref mcn, tracks,
- subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel,
- _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true);
-
- // Set tracks and go back
- if(indexesChanged)
- {
- (outputOptical as IWritableOpticalImage).SetTracks(tracks.ToList());
- i -= _maximumReadable;
-
- continue;
- }
+ continue;
}
- else
- {
- outputOptical.WriteSectorsLong(cmdBuf, i + r, 1);
- }
-
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
}
else
{
- _errorLog?.WriteLine(i + r, _dev.Error, _dev.LastError, senseBuf);
-
- leadOutExtents.Add(i + r, firstTrack.StartSector - 1);
-
- UpdateStatus?.
- Invoke($"Adding CD-i Ready hole from LBA {i + r} to {firstTrack.StartSector - 1} inclusive.");
-
- _dumpLog.WriteLine("Adding CD-i Ready hole from LBA {0} to {1} inclusive.", i + r,
- firstTrack.StartSector - 1);
-
- break;
+ outputOptical.WriteSectorsLong(cmdBuf, i + r, 1);
}
- sectorSpeedStart += r;
-
- _resume.NextBlock = i + r;
-
- elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
-
- if(elapsed <= 0)
- continue;
-
- currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
- sectorSpeedStart = 0;
- timeSpeedStart = DateTime.UtcNow;
- }
- }
-
- if(!sense &&
- !_dev.Error)
- {
- if(cdiReadyReadAsAudio)
- FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead,
- subSize, ref cmdBuf, blockSize, false);
-
- mhddLog.Write(i, cmdDuration);
- ibgLog.Write(i, currentSpeed * 1024);
- extents.Add(i, blocksToRead, true);
- DateTime writeStart = DateTime.Now;
-
- if(supportedSubchannel != MmcSubchannel.None)
- {
- byte[] data = new byte[sectorSize * blocksToRead];
- byte[] sub = new byte[subSize * blocksToRead];
- byte[] tmpData = new byte[sectorSize];
-
- for(int b = 0; b < blocksToRead; b++)
- {
- if(cdiReadyReadAsAudio)
- {
- Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), tmpData, 0, sectorSize);
- tmpData = Sector.Scramble(tmpData);
- Array.Copy(tmpData, 0, data, sectorSize * b, sectorSize);
- }
- else
- Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
-
- Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
- }
-
- outputOptical.WriteSectorsLong(data, i, blocksToRead);
-
- bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
- desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, 1, ref mcn, tracks,
- subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel,
- _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true);
-
- // Set tracks and go back
- if(indexesChanged)
- {
- (outputOptical as IWritableOpticalImage).SetTracks(tracks.ToList());
- i -= blocksToRead;
-
- continue;
- }
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
}
else
{
- if(cdiReadyReadAsAudio)
- {
- byte[] tmpData = new byte[sectorSize];
- byte[] data = new byte[sectorSize * blocksToRead];
+ _errorLog?.WriteLine(i + r, _dev.Error, _dev.LastError, senseBuf);
- for(int b = 0; b < blocksToRead; b++)
- {
- Array.Copy(cmdBuf, (int)(b * sectorSize), tmpData, 0, sectorSize);
- tmpData = Sector.Scramble(tmpData);
- Array.Copy(tmpData, 0, data, sectorSize * b, sectorSize);
- }
+ leadOutExtents.Add(i + r, firstTrack.StartSector - 1);
- outputOptical.WriteSectorsLong(data, i, blocksToRead);
- }
- else
- outputOptical.WriteSectorsLong(cmdBuf, i, blocksToRead);
+ UpdateStatus?.
+ Invoke($"Adding CD-i Ready hole from LBA {i + r} to {firstTrack.StartSector - 1} inclusive.");
+
+ _dumpLog.WriteLine("Adding CD-i Ready hole from LBA {0} to {1} inclusive.", i + r,
+ firstTrack.StartSector - 1);
+
+ break;
}
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+ sectorSpeedStart += r;
+
+ _resume.NextBlock = i + r;
+
+ elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
+
+ if(elapsed <= 0)
+ continue;
+
+ currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
+ sectorSpeedStart = 0;
+ timeSpeedStart = DateTime.UtcNow;
+ }
+ }
+
+ if(!sense &&
+ !_dev.Error)
+ {
+ if(cdiReadyReadAsAudio)
+ FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead,
+ subSize, ref cmdBuf, blockSize, false);
+
+ mhddLog.Write(i, cmdDuration);
+ ibgLog.Write(i, currentSpeed * 1024);
+ extents.Add(i, blocksToRead, true);
+ DateTime writeStart = DateTime.Now;
+
+ if(supportedSubchannel != MmcSubchannel.None)
+ {
+ byte[] data = new byte[sectorSize * blocksToRead];
+ byte[] sub = new byte[subSize * blocksToRead];
+ byte[] tmpData = new byte[sectorSize];
+
+ for(int b = 0; b < blocksToRead; b++)
+ {
+ if(cdiReadyReadAsAudio)
+ {
+ Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), tmpData, 0, sectorSize);
+ tmpData = Sector.Scramble(tmpData);
+ Array.Copy(tmpData, 0, data, sectorSize * b, sectorSize);
+ }
+ else
+ Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
+
+ Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
+ }
+
+ outputOptical.WriteSectorsLong(data, i, blocksToRead);
+
+ bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
+ desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, 1, ref mcn, tracks,
+ subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel,
+ _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true);
+
+ // Set tracks and go back
+ if(indexesChanged)
+ {
+ (outputOptical as IWritableOpticalImage).SetTracks(tracks.ToList());
+ i -= blocksToRead;
+
+ continue;
+ }
}
else
{
- _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf);
+ if(cdiReadyReadAsAudio)
+ {
+ byte[] tmpData = new byte[sectorSize];
+ byte[] data = new byte[sectorSize * blocksToRead];
- _resume.NextBlock = firstTrack.StartSector;
+ for(int b = 0; b < blocksToRead; b++)
+ {
+ Array.Copy(cmdBuf, (int)(b * sectorSize), tmpData, 0, sectorSize);
+ tmpData = Sector.Scramble(tmpData);
+ Array.Copy(tmpData, 0, data, sectorSize * b, sectorSize);
+ }
- break;
+ outputOptical.WriteSectorsLong(data, i, blocksToRead);
+ }
+ else
+ outputOptical.WriteSectorsLong(cmdBuf, i, blocksToRead);
}
- sectorSpeedStart += blocksToRead;
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+ }
+ else
+ {
+ _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf);
- _resume.NextBlock = i + blocksToRead;
+ _resume.NextBlock = firstTrack.StartSector;
- elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
-
- if(elapsed <= 0)
- continue;
-
- currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
- sectorSpeedStart = 0;
- timeSpeedStart = DateTime.UtcNow;
+ break;
}
- EndProgress?.Invoke();
+ sectorSpeedStart += blocksToRead;
+
+ _resume.NextBlock = i + blocksToRead;
+
+ elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
+
+ if(elapsed <= 0)
+ continue;
+
+ currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
+ sectorSpeedStart = 0;
+ timeSpeedStart = DateTime.UtcNow;
}
+
+ EndProgress?.Invoke();
}
}
\ No newline at end of file
diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs
index e6f678193..18ac308d5 100644
--- a/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs
+++ b/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs
@@ -49,727 +49,726 @@ using Schemas;
// ReSharper disable InlineOutVariableDeclaration
// ReSharper disable TooWideLocalVariableScope
-namespace Aaru.Core.Devices.Dumping
+namespace Aaru.Core.Devices.Dumping;
+
+partial class Dump
{
- partial class Dump
+ /// Reads all CD user data
+ /// Extents with audio sectors
+ /// 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
+ /// Last sector number
+ /// Lead-out extents
+ /// Maximum speed
+ /// MHDD log
+ /// Minimum speed
+ /// Is trim a new one?
+ /// Next cluster of sectors is all data
+ /// Read offset
+ /// Device supports READ(6)
+ /// Device supports READ(10)
+ /// Device supports READ(12)
+ /// Device supports READ(16)
+ /// Device supports READ CD
+ /// Sectors needed to fix offset
+ /// Subchannel size in bytes
+ /// Drive's maximum supported subchannel
+ /// Supports reading EDC and ECC
+ /// Total commands duration
+ /// Disc tracks
+ /// Subchannel log
+ /// Subchannel desired to save
+ /// List of disc ISRCs
+ /// Disc media catalogue number
+ /// List of subchannels not yet dumped correctly
+ /// List of smallest pregap relative address per track
+ void ReadCdData(ExtentsULong audioExtents, ulong blocks, uint blockSize, ref double currentSpeed,
+ DumpHardwareType currentTry, ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration,
+ long lastSector, ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog,
+ ref double minSpeed, out bool newTrim, bool nextData, int offsetBytes, bool read6, bool read10,
+ bool read12, bool read16, bool readcd, int sectorsForOffset, uint subSize,
+ MmcSubchannel supportedSubchannel, bool supportsLongSectors, ref double totalDuration,
+ Track[] tracks, SubchannelLog subLog, MmcSubchannel desiredSubchannel,
+ Dictionary isrcs, ref string mcn, HashSet subchannelExtents,
+ Dictionary smallestPregapLbaPerTrack)
{
- /// Reads all CD user data
- /// Extents with audio sectors
- /// 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
- /// Last sector number
- /// Lead-out extents
- /// Maximum speed
- /// MHDD log
- /// Minimum speed
- /// Is trim a new one?
- /// Next cluster of sectors is all data
- /// Read offset
- /// Device supports READ(6)
- /// Device supports READ(10)
- /// Device supports READ(12)
- /// Device supports READ(16)
- /// Device supports READ CD
- /// Sectors needed to fix offset
- /// Subchannel size in bytes
- /// Drive's maximum supported subchannel
- /// Supports reading EDC and ECC
- /// Total commands duration
- /// Disc tracks
- /// Subchannel log
- /// Subchannel desired to save
- /// List of disc ISRCs
- /// Disc media catalogue number
- /// List of subchannels not yet dumped correctly
- /// List of smallest pregap relative address per track
- void ReadCdData(ExtentsULong audioExtents, ulong blocks, uint blockSize, ref double currentSpeed,
- DumpHardwareType currentTry, ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration,
- long lastSector, ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog,
- ref double minSpeed, out bool newTrim, bool nextData, int offsetBytes, bool read6, bool read10,
- bool read12, bool read16, bool readcd, int sectorsForOffset, uint subSize,
- MmcSubchannel supportedSubchannel, bool supportsLongSectors, ref double totalDuration,
- Track[] tracks, SubchannelLog subLog, MmcSubchannel desiredSubchannel,
- Dictionary isrcs, ref string mcn, HashSet subchannelExtents,
- Dictionary smallestPregapLbaPerTrack)
+ ulong sectorSpeedStart = 0; // Used to calculate correct speed
+ DateTime timeSpeedStart = DateTime.UtcNow; // Time of start for speed calculation
+ uint blocksToRead; // How many sectors to read at once
+ bool sense = true; // Sense indicator
+ byte[] cmdBuf = null; // Data buffer
+ byte[] senseBuf = null; // Sense buffer
+ double cmdDuration = 0; // Command execution time
+ const uint sectorSize = 2352; // Full sector size
+ newTrim = false;
+ PlextorSubchannel supportedPlextorSubchannel;
+ var outputFormat = _outputPlugin as IWritableImage;
+
+ switch(supportedSubchannel)
{
- ulong sectorSpeedStart = 0; // Used to calculate correct speed
- DateTime timeSpeedStart = DateTime.UtcNow; // Time of start for speed calculation
- uint blocksToRead; // How many sectors to read at once
- bool sense = true; // Sense indicator
- byte[] cmdBuf = null; // Data buffer
- byte[] senseBuf = null; // Sense buffer
- double cmdDuration = 0; // Command execution time
- const uint sectorSize = 2352; // Full sector size
- newTrim = false;
- PlextorSubchannel supportedPlextorSubchannel;
- var outputFormat = _outputPlugin as IWritableImage;
+ case MmcSubchannel.None:
+ supportedPlextorSubchannel = PlextorSubchannel.None;
- switch(supportedSubchannel)
+ break;
+ case MmcSubchannel.Raw:
+ supportedPlextorSubchannel = PlextorSubchannel.Pack;
+
+ break;
+ case MmcSubchannel.Q16:
+ supportedPlextorSubchannel = PlextorSubchannel.Q16;
+
+ break;
+ default:
+ supportedPlextorSubchannel = PlextorSubchannel.None;
+
+ break;
+ }
+
+ InitProgress?.Invoke();
+
+ int currentReadSpeed = _speed;
+ bool crossingLeadOut = false;
+ bool failedCrossingLeadOut = false;
+ bool skippingLead = false;
+
+ for(ulong i = _resume.NextBlock; (long)i <= lastSector; i += blocksToRead)
+ {
+ if(_aborted)
{
- case MmcSubchannel.None:
- supportedPlextorSubchannel = PlextorSubchannel.None;
+ currentTry.Extents = ExtentsConverter.ToMetadata(extents);
+ UpdateStatus?.Invoke("Aborted!");
+ _dumpLog.WriteLine("Aborted!");
- break;
- case MmcSubchannel.Raw:
- supportedPlextorSubchannel = PlextorSubchannel.Pack;
-
- break;
- case MmcSubchannel.Q16:
- supportedPlextorSubchannel = PlextorSubchannel.Q16;
-
- break;
- default:
- supportedPlextorSubchannel = PlextorSubchannel.None;
-
- break;
+ break;
}
- InitProgress?.Invoke();
-
- int currentReadSpeed = _speed;
- bool crossingLeadOut = false;
- bool failedCrossingLeadOut = false;
- bool skippingLead = false;
-
- for(ulong i = _resume.NextBlock; (long)i <= lastSector; i += blocksToRead)
+ while(leadOutExtents.Contains(i))
{
- if(_aborted)
+ skippingLead = true;
+ i++;
+ }
+
+ if((long)i > lastSector)
+ break;
+
+ uint firstSectorToRead = (uint)i;
+
+ Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => i >= t.StartSector);
+
+ blocksToRead = 0;
+ bool inData = nextData;
+
+ for(ulong j = i; j < i + _maximumReadable; j++)
+ {
+ if(j > (ulong)lastSector)
{
- currentTry.Extents = ExtentsConverter.ToMetadata(extents);
- UpdateStatus?.Invoke("Aborted!");
- _dumpLog.WriteLine("Aborted!");
+ if(!failedCrossingLeadOut &&
+ !inData)
+ blocksToRead += (uint)sectorsForOffset;
+
+ if(sectorsForOffset > 0 &&
+ !inData)
+ crossingLeadOut = true;
break;
}
- while(leadOutExtents.Contains(i))
+ if(nextData)
{
- skippingLead = true;
- i++;
- }
-
- if((long)i > lastSector)
- break;
-
- uint firstSectorToRead = (uint)i;
-
- Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => i >= t.StartSector);
-
- blocksToRead = 0;
- bool inData = nextData;
-
- for(ulong j = i; j < i + _maximumReadable; j++)
- {
- if(j > (ulong)lastSector)
+ if(audioExtents.Contains(j))
{
- if(!failedCrossingLeadOut &&
- !inData)
- blocksToRead += (uint)sectorsForOffset;
-
- if(sectorsForOffset > 0 &&
- !inData)
- crossingLeadOut = true;
+ nextData = false;
break;
}
- if(nextData)
+ blocksToRead++;
+ }
+ else
+ {
+ if(!audioExtents.Contains(j))
{
- if(audioExtents.Contains(j))
- {
- nextData = false;
+ nextData = true;
- break;
- }
-
- blocksToRead++;
+ break;
}
+
+ blocksToRead++;
+ }
+ }
+
+ if(track.Sequence != 0 &&
+ i + blocksToRead - (ulong)sectorsForOffset > track.EndSector + 1)
+ blocksToRead = (uint)(track.EndSector + 1 - i + (ulong)sectorsForOffset);
+
+ if(blocksToRead == 1 &&
+ !inData)
+ blocksToRead += (uint)sectorsForOffset;
+
+ if(blocksToRead == 0)
+ {
+ if(!skippingLead)
+ i += (ulong)sectorsForOffset;
+
+ skippingLead = false;
+
+ continue;
+ }
+
+ if(_fixOffset && !inData)
+ {
+ if(offsetBytes < 0)
+ {
+ if(i == 0)
+ firstSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1
else
+ firstSectorToRead -= (uint)sectorsForOffset;
+
+ if(blocksToRead <= sectorsForOffset)
+ blocksToRead += (uint)sectorsForOffset;
+ }
+ }
+
+ if(!inData &&
+ currentReadSpeed == 0xFFFF)
+ {
+ _dumpLog.WriteLine("Setting speed to 8x for audio reading.");
+ UpdateStatus?.Invoke("Setting speed to 8x for audio reading.");
+
+ _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _);
+
+ currentReadSpeed = 1200;
+ }
+
+ if(inData && currentReadSpeed != _speed)
+ {
+ _dumpLog.WriteLine($"Setting speed to {(_speed == 0xFFFF ? "MAX for data reading" : $"{_speed}x")}.");
+
+ UpdateStatus?.
+ Invoke($"Setting speed to {(_speed == 0xFFFF ? "MAX for data reading" : $"{_speed}x")}.");
+
+ _speed *= _speedMultiplier;
+
+ if(_speed == 0 ||
+ _speed > 0xFFFF)
+ _speed = 0xFFFF;
+
+ currentReadSpeed = _speed;
+
+ _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _);
+ }
+
+ if(inData && crossingLeadOut)
+ {
+ firstSectorToRead = (uint)i;
+ blocksToRead = (uint)(lastSector - firstSectorToRead) + 1;
+ crossingLeadOut = false;
+ }
+
+ if(currentSpeed > maxSpeed &&
+ currentSpeed > 0)
+ maxSpeed = currentSpeed;
+
+ if(currentSpeed < minSpeed &&
+ currentSpeed > 0)
+ minSpeed = currentSpeed;
+
+ UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
+ (long)blocks);
+
+ if(crossingLeadOut &&
+ failedCrossingLeadOut &&
+ blocksToRead > 1)
+ blocksToRead--;
+
+ if(_supportsPlextorD8 && !inData)
+ {
+ sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, firstSectorToRead, blockSize,
+ blocksToRead, supportedPlextorSubchannel, out cmdDuration);
+
+ totalDuration += cmdDuration;
+ }
+ else if(readcd)
+ {
+ if(inData)
+ {
+ sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
+ MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
+ true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout,
+ out cmdDuration);
+
+ if(sense)
{
- if(!audioExtents.Contains(j))
+ DecodedSense? decSense = Sense.Decode(senseBuf);
+
+ // Try to workaround firmware
+ if(decSense?.ASC == 0x64)
{
- nextData = true;
+ bool goBackTrackTypeChange = false;
- break;
- }
-
- blocksToRead++;
- }
- }
-
- if(track.Sequence != 0 &&
- i + blocksToRead - (ulong)sectorsForOffset > track.EndSector + 1)
- blocksToRead = (uint)(track.EndSector + 1 - i + (ulong)sectorsForOffset);
-
- if(blocksToRead == 1 &&
- !inData)
- blocksToRead += (uint)sectorsForOffset;
-
- if(blocksToRead == 0)
- {
- if(!skippingLead)
- i += (ulong)sectorsForOffset;
-
- skippingLead = false;
-
- continue;
- }
-
- if(_fixOffset && !inData)
- {
- if(offsetBytes < 0)
- {
- if(i == 0)
- firstSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1
- else
- firstSectorToRead -= (uint)sectorsForOffset;
-
- if(blocksToRead <= sectorsForOffset)
- blocksToRead += (uint)sectorsForOffset;
- }
- }
-
- if(!inData &&
- currentReadSpeed == 0xFFFF)
- {
- _dumpLog.WriteLine("Setting speed to 8x for audio reading.");
- UpdateStatus?.Invoke("Setting speed to 8x for audio reading.");
-
- _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _);
-
- currentReadSpeed = 1200;
- }
-
- if(inData && currentReadSpeed != _speed)
- {
- _dumpLog.WriteLine($"Setting speed to {(_speed == 0xFFFF ? "MAX for data reading" : $"{_speed}x")}.");
-
- UpdateStatus?.
- Invoke($"Setting speed to {(_speed == 0xFFFF ? "MAX for data reading" : $"{_speed}x")}.");
-
- _speed *= _speedMultiplier;
-
- if(_speed == 0 ||
- _speed > 0xFFFF)
- _speed = 0xFFFF;
-
- currentReadSpeed = _speed;
-
- _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _);
- }
-
- if(inData && crossingLeadOut)
- {
- firstSectorToRead = (uint)i;
- blocksToRead = (uint)(lastSector - firstSectorToRead) + 1;
- crossingLeadOut = false;
- }
-
- if(currentSpeed > maxSpeed &&
- currentSpeed > 0)
- maxSpeed = currentSpeed;
-
- if(currentSpeed < minSpeed &&
- currentSpeed > 0)
- minSpeed = currentSpeed;
-
- UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
- (long)blocks);
-
- if(crossingLeadOut &&
- failedCrossingLeadOut &&
- blocksToRead > 1)
- blocksToRead--;
-
- if(_supportsPlextorD8 && !inData)
- {
- sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, firstSectorToRead, blockSize,
- blocksToRead, supportedPlextorSubchannel, out cmdDuration);
-
- totalDuration += cmdDuration;
- }
- else if(readcd)
- {
- if(inData)
- {
- sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
- MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
- true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout,
- out cmdDuration);
-
- if(sense)
- {
- DecodedSense? decSense = Sense.Decode(senseBuf);
-
- // Try to workaround firmware
- if(decSense?.ASC == 0x64)
+ // Go one for one as the drive does not tell us which one failed
+ for(int bi = 0; bi < blocksToRead; bi++)
{
- bool goBackTrackTypeChange = false;
-
- // Go one for one as the drive does not tell us which one failed
- for(int bi = 0; bi < blocksToRead; bi++)
- {
- sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(firstSectorToRead + bi),
- blockSize, 1, MmcSectorTypes.AllTypes, false, false, true,
- MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
- supportedSubchannel, _dev.Timeout, out double cmdDuration2);
-
- cmdDuration += cmdDuration2;
-
- if(!sense &&
- cmdBuf[0] == 0x00 &&
- cmdBuf[1] == 0xFF &&
- cmdBuf[2] == 0xFF &&
- cmdBuf[3] == 0xFF &&
- cmdBuf[4] == 0xFF &&
- cmdBuf[5] == 0xFF &&
- cmdBuf[6] == 0xFF &&
- cmdBuf[7] == 0xFF &&
- cmdBuf[8] == 0xFF &&
- cmdBuf[9] == 0xFF &&
- cmdBuf[10] == 0xFF &&
- cmdBuf[11] == 0x00)
- continue;
-
- // Set those sectors as audio
- for(int bip = bi; bip < blocksToRead; bip++)
- audioExtents.Add((ulong)(firstSectorToRead + bip));
-
- goBackTrackTypeChange = true;
-
- break;
- }
-
- // Go back to read again
- if(goBackTrackTypeChange)
- {
- blocksToRead = 0;
- nextData = true;
-
- continue;
- }
- }
- }
- }
- else
- {
- sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
- MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false,
- MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration);
-
- if(sense)
- {
- DecodedSense? decSense = Sense.Decode(senseBuf);
-
- // Try to workaround firmware
- if((decSense?.ASC == 0x11 && decSense?.ASCQ == 0x05) ||
- decSense?.ASC == 0x64)
- {
- sense = _dev.ReadCd(out cmdBuf, out _, firstSectorToRead, blockSize, blocksToRead,
- MmcSectorTypes.AllTypes, false, false, true,
+ sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(firstSectorToRead + bi),
+ blockSize, 1, MmcSectorTypes.AllTypes, false, false, true,
MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
supportedSubchannel, _dev.Timeout, out double cmdDuration2);
cmdDuration += cmdDuration2;
- }
- }
- }
-
- totalDuration += cmdDuration;
- }
- else if(read16)
- {
- sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, false, false, firstSectorToRead, blockSize,
- 0, blocksToRead, false, _dev.Timeout, out cmdDuration);
- }
- else if(read12)
- {
- sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, false, false, false, firstSectorToRead,
- blockSize, 0, blocksToRead, false, _dev.Timeout, out cmdDuration);
- }
- else if(read10)
- {
- sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, false, false, false, firstSectorToRead,
- blockSize, 0, (ushort)blocksToRead, _dev.Timeout, out cmdDuration);
- }
- else if(read6)
- {
- sense = _dev.Read6(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, (byte)blocksToRead,
- _dev.Timeout, out cmdDuration);
- }
-
- double elapsed;
-
- // Overcome the track mode change drive error
- if(inData &&
- !nextData &&
- sense)
- {
- for(uint r = 0; r < blocksToRead; r++)
- {
- UpdateProgress?.Invoke($"Reading sector {i + r} of {blocks} ({currentSpeed:F3} MiB/sec.)",
- (long)i + r, (long)blocks);
-
- if(_supportsPlextorD8)
- {
- int adjustment = 0;
-
- if(offsetBytes < 0)
- adjustment = -sectorsForOffset;
-
- sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf,
- (uint)(firstSectorToRead + r + adjustment), blockSize,
- (uint)sectorsForOffset + 1, supportedPlextorSubchannel,
- out cmdDuration);
-
- totalDuration += cmdDuration;
-
- if(!sense)
- {
- uint sectorsForFix = (uint)(1 + sectorsForOffset);
-
- FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
- ref sectorsForFix, subSize, ref cmdBuf, blockSize, false);
-
- // TODO: Implement sector validity
- cmdBuf = Sector.Scramble(cmdBuf);
- }
- }
- else if(readcd)
- {
- sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(i + r), 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 + r, 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 + r),
- 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 + r),
- blockSize, 0, 1, _dev.Timeout, out cmdDuration);
- }
- else if(read6)
- {
- sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)(i + r), blockSize, 1, _dev.Timeout,
- out cmdDuration);
- }
-
- if(!sense &&
- !_dev.Error)
- {
- mhddLog.Write(i + r, cmdDuration);
- ibgLog.Write(i + r, currentSpeed * 1024);
- extents.Add(i + r, 1, true);
- DateTime writeStart = DateTime.Now;
-
- if(supportedSubchannel != MmcSubchannel.None)
- {
- byte[] data = new byte[sectorSize];
- byte[] sub = new byte[subSize];
-
- Array.Copy(cmdBuf, 0, data, 0, sectorSize);
-
- Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
-
- if(supportsLongSectors)
- outputFormat.WriteSectorsLong(data, i + r, 1);
- else
- {
- var cooked = new MemoryStream();
- byte[] sector = new byte[sectorSize];
-
- for(int b = 0; b < blocksToRead; b++)
- {
- Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), sector, 0, sectorSize);
- byte[] cookedSector = Sector.GetUserData(sector);
- cooked.Write(cookedSector, 0, cookedSector.Length);
- }
-
- outputFormat.WriteSectors(cooked.ToArray(), i, blocksToRead);
- }
-
- bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
- desiredSubchannel, sub, i + r, 1, subLog, isrcs, (byte)track.Sequence,
- ref mcn, tracks, subchannelExtents, _fixSubchannelPosition, outputFormat as IWritableOpticalImage,
- _fixSubchannel, _fixSubchannelCrc, _dumpLog, UpdateStatus,
- smallestPregapLbaPerTrack, true);
-
- // Set tracks and go back
- if(indexesChanged)
- {
- (outputFormat as IWritableOpticalImage).SetTracks(tracks.ToList());
- i -= blocksToRead;
+ if(!sense &&
+ cmdBuf[0] == 0x00 &&
+ cmdBuf[1] == 0xFF &&
+ cmdBuf[2] == 0xFF &&
+ cmdBuf[3] == 0xFF &&
+ cmdBuf[4] == 0xFF &&
+ cmdBuf[5] == 0xFF &&
+ cmdBuf[6] == 0xFF &&
+ cmdBuf[7] == 0xFF &&
+ cmdBuf[8] == 0xFF &&
+ cmdBuf[9] == 0xFF &&
+ cmdBuf[10] == 0xFF &&
+ cmdBuf[11] == 0x00)
continue;
- }
+
+ // Set those sectors as audio
+ for(int bip = bi; bip < blocksToRead; bip++)
+ audioExtents.Add((ulong)(firstSectorToRead + bip));
+
+ goBackTrackTypeChange = true;
+
+ break;
}
- else
+
+ // Go back to read again
+ if(goBackTrackTypeChange)
{
- if(supportsLongSectors)
- outputFormat.WriteSectorsLong(cmdBuf, i + r, 1);
- else
- {
- var cooked = new MemoryStream();
- byte[] sector = new byte[sectorSize];
+ blocksToRead = 0;
+ nextData = true;
- for(int b = 0; b < blocksToRead; b++)
- {
- Array.Copy(cmdBuf, (int)(b * sectorSize), sector, 0, sectorSize);
- byte[] cookedSector = Sector.GetUserData(sector);
- cooked.Write(cookedSector, 0, cookedSector.Length);
- }
-
- outputFormat.WriteSectors(cooked.ToArray(), i, blocksToRead);
- }
+ continue;
}
-
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
- }
- else
- {
- _errorLog?.WriteLine(i + r, _dev.Error, _dev.LastError, senseBuf);
-
- // Write empty data
- DateTime writeStart = DateTime.Now;
-
- if(supportedSubchannel != MmcSubchannel.None)
- {
- outputFormat.WriteSectorsLong(new byte[sectorSize], i + r, 1);
-
- if(desiredSubchannel != MmcSubchannel.None)
- outputFormat.WriteSectorsTag(new byte[subSize], i + r, 1,
- SectorTagType.CdSectorSubchannel);
- }
- else
- {
- if(supportsLongSectors)
- outputFormat.WriteSectorsLong(new byte[blockSize], i + r, 1);
- else
- {
- if(cmdBuf.Length % sectorSize == 0)
- outputFormat.WriteSectors(new byte[2048], i + r, 1);
- else
- outputFormat.WriteSectorsLong(new byte[blockSize], i + r, 1);
- }
- }
-
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
-
- _resume.BadBlocks.Add(i + r);
-
- AaruConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
- mhddLog.Write(i + r, cmdDuration < 500 ? 65535 : cmdDuration);
-
- ibgLog.Write(i + r, 0);
- _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", 1, i + r);
- newTrim = true;
- }
-
- sectorSpeedStart += r;
-
- _resume.NextBlock = i + r;
-
- elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
-
- if(elapsed <= 0)
- continue;
-
- currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
- sectorSpeedStart = 0;
- timeSpeedStart = DateTime.UtcNow;
- }
-
- continue;
- }
-
- if(!sense &&
- !_dev.Error)
- {
- if(crossingLeadOut && failedCrossingLeadOut)
- {
- byte[] tmp = new byte[cmdBuf.Length + blockSize];
- Array.Copy(cmdBuf, 0, tmp, 0, cmdBuf.Length);
- }
-
- // Because one block has been partially used to fix the offset
- if(_fixOffset &&
- !inData &&
- offsetBytes != 0)
- FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead,
- subSize, ref cmdBuf, blockSize, failedCrossingLeadOut);
-
- mhddLog.Write(i, cmdDuration);
- ibgLog.Write(i, currentSpeed * 1024);
- extents.Add(i, blocksToRead, true);
- DateTime writeStart = DateTime.Now;
-
- if(supportedSubchannel != MmcSubchannel.None)
- {
- byte[] data = new byte[sectorSize * blocksToRead];
- byte[] sub = new byte[subSize * blocksToRead];
-
- for(int b = 0; b < blocksToRead; b++)
- {
- Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
-
- Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
- }
-
- if(supportsLongSectors)
- outputFormat.WriteSectorsLong(data, i, blocksToRead);
- else
- {
- var cooked = new MemoryStream();
- byte[] sector = new byte[sectorSize];
-
- for(int b = 0; b < blocksToRead; b++)
- {
- Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), sector, 0, sectorSize);
- byte[] cookedSector = Sector.GetUserData(sector);
- cooked.Write(cookedSector, 0, cookedSector.Length);
- }
-
- outputFormat.WriteSectors(cooked.ToArray(), i, blocksToRead);
- }
-
- bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
- desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, (byte)track.Sequence,
- ref mcn, tracks, subchannelExtents, _fixSubchannelPosition, outputFormat as IWritableOpticalImage,
- _fixSubchannel, _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack,
- true);
-
- // Set tracks and go back
- if(indexesChanged)
- {
- (outputFormat as IWritableOpticalImage).SetTracks(tracks.ToList());
- i -= blocksToRead;
-
- continue;
}
}
- else
- {
- if(supportsLongSectors)
- outputFormat.WriteSectorsLong(cmdBuf, i, blocksToRead);
- else
- {
- var cooked = new MemoryStream();
- byte[] sector = new byte[sectorSize];
-
- for(int b = 0; b < blocksToRead; b++)
- {
- Array.Copy(cmdBuf, (int)(b * sectorSize), sector, 0, sectorSize);
- byte[] cookedSector = Sector.GetUserData(sector);
- cooked.Write(cookedSector, 0, cookedSector.Length);
- }
-
- outputFormat.WriteSectors(cooked.ToArray(), i, blocksToRead);
- }
- }
-
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
}
else
{
- if(crossingLeadOut && Sense.Decode(senseBuf)?.ASC == 0x21)
+ sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
+ MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false,
+ MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration);
+
+ if(sense)
{
- if(failedCrossingLeadOut)
- break;
+ DecodedSense? decSense = Sense.Decode(senseBuf);
- failedCrossingLeadOut = true;
- blocksToRead = 0;
-
- continue;
- }
-
- _errorLog?.WriteLine(firstSectorToRead, _dev.Error, _dev.LastError, senseBuf);
-
- // TODO: Reset device after X errors
- if(_stopOnError)
- return; // TODO: Return more cleanly
-
- if(i + _skip > blocks)
- _skip = (uint)(blocks - i);
-
- // Write empty data
- DateTime writeStart = DateTime.Now;
-
- if(supportedSubchannel != MmcSubchannel.None)
- {
- outputFormat.WriteSectorsLong(new byte[sectorSize * _skip], i, _skip);
-
- if(desiredSubchannel != MmcSubchannel.None)
- outputFormat.WriteSectorsTag(new byte[subSize * _skip], i, _skip,
- SectorTagType.CdSectorSubchannel);
- }
- else
- {
- if(supportsLongSectors)
+ // Try to workaround firmware
+ if((decSense?.ASC == 0x11 && decSense?.ASCQ == 0x05) ||
+ decSense?.ASC == 0x64)
{
- outputFormat.WriteSectorsLong(new byte[blockSize * _skip], i, _skip);
+ sense = _dev.ReadCd(out cmdBuf, out _, firstSectorToRead, blockSize, blocksToRead,
+ MmcSectorTypes.AllTypes, false, false, true,
+ MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
+ supportedSubchannel, _dev.Timeout, out double cmdDuration2);
+
+ cmdDuration += cmdDuration2;
+ }
+ }
+ }
+
+ totalDuration += cmdDuration;
+ }
+ else if(read16)
+ {
+ sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, false, false, firstSectorToRead, blockSize,
+ 0, blocksToRead, false, _dev.Timeout, out cmdDuration);
+ }
+ else if(read12)
+ {
+ sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, false, false, false, firstSectorToRead,
+ blockSize, 0, blocksToRead, false, _dev.Timeout, out cmdDuration);
+ }
+ else if(read10)
+ {
+ sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, false, false, false, firstSectorToRead,
+ blockSize, 0, (ushort)blocksToRead, _dev.Timeout, out cmdDuration);
+ }
+ else if(read6)
+ {
+ sense = _dev.Read6(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, (byte)blocksToRead,
+ _dev.Timeout, out cmdDuration);
+ }
+
+ double elapsed;
+
+ // Overcome the track mode change drive error
+ if(inData &&
+ !nextData &&
+ sense)
+ {
+ for(uint r = 0; r < blocksToRead; r++)
+ {
+ UpdateProgress?.Invoke($"Reading sector {i + r} of {blocks} ({currentSpeed:F3} MiB/sec.)",
+ (long)i + r, (long)blocks);
+
+ if(_supportsPlextorD8)
+ {
+ int adjustment = 0;
+
+ if(offsetBytes < 0)
+ adjustment = -sectorsForOffset;
+
+ sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf,
+ (uint)(firstSectorToRead + r + adjustment), blockSize,
+ (uint)sectorsForOffset + 1, supportedPlextorSubchannel,
+ out cmdDuration);
+
+ totalDuration += cmdDuration;
+
+ if(!sense)
+ {
+ uint sectorsForFix = (uint)(1 + sectorsForOffset);
+
+ FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
+ ref sectorsForFix, subSize, ref cmdBuf, blockSize, false);
+
+ // TODO: Implement sector validity
+ cmdBuf = Sector.Scramble(cmdBuf);
+ }
+ }
+ else if(readcd)
+ {
+ sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(i + r), 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 + r, 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 + r),
+ 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 + r),
+ blockSize, 0, 1, _dev.Timeout, out cmdDuration);
+ }
+ else if(read6)
+ {
+ sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)(i + r), blockSize, 1, _dev.Timeout,
+ out cmdDuration);
+ }
+
+ if(!sense &&
+ !_dev.Error)
+ {
+ mhddLog.Write(i + r, cmdDuration);
+ ibgLog.Write(i + r, currentSpeed * 1024);
+ extents.Add(i + r, 1, true);
+ DateTime writeStart = DateTime.Now;
+
+ if(supportedSubchannel != MmcSubchannel.None)
+ {
+ byte[] data = new byte[sectorSize];
+ byte[] sub = new byte[subSize];
+
+ Array.Copy(cmdBuf, 0, data, 0, sectorSize);
+
+ Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
+
+ if(supportsLongSectors)
+ outputFormat.WriteSectorsLong(data, i + r, 1);
+ else
+ {
+ var cooked = new MemoryStream();
+ byte[] sector = new byte[sectorSize];
+
+ for(int b = 0; b < blocksToRead; b++)
+ {
+ Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), sector, 0, sectorSize);
+ byte[] cookedSector = Sector.GetUserData(sector);
+ cooked.Write(cookedSector, 0, cookedSector.Length);
+ }
+
+ outputFormat.WriteSectors(cooked.ToArray(), i, blocksToRead);
+ }
+
+ bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
+ desiredSubchannel, sub, i + r, 1, subLog, isrcs, (byte)track.Sequence,
+ ref mcn, tracks, subchannelExtents, _fixSubchannelPosition, outputFormat as IWritableOpticalImage,
+ _fixSubchannel, _fixSubchannelCrc, _dumpLog, UpdateStatus,
+ smallestPregapLbaPerTrack, true);
+
+ // Set tracks and go back
+ if(indexesChanged)
+ {
+ (outputFormat as IWritableOpticalImage).SetTracks(tracks.ToList());
+ i -= blocksToRead;
+
+ continue;
+ }
}
else
{
- if(cmdBuf.Length % sectorSize == 0)
- outputFormat.WriteSectors(new byte[2048 * _skip], i, _skip);
+ if(supportsLongSectors)
+ outputFormat.WriteSectorsLong(cmdBuf, i + r, 1);
else
- outputFormat.WriteSectorsLong(new byte[blockSize * _skip], i, _skip);
+ {
+ var cooked = new MemoryStream();
+ byte[] sector = new byte[sectorSize];
+
+ for(int b = 0; b < blocksToRead; b++)
+ {
+ Array.Copy(cmdBuf, (int)(b * sectorSize), sector, 0, sectorSize);
+ byte[] cookedSector = Sector.GetUserData(sector);
+ cooked.Write(cookedSector, 0, cookedSector.Length);
+ }
+
+ outputFormat.WriteSectors(cooked.ToArray(), i, blocksToRead);
+ }
}
+
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+ }
+ else
+ {
+ _errorLog?.WriteLine(i + r, _dev.Error, _dev.LastError, senseBuf);
+
+ // Write empty data
+ DateTime writeStart = DateTime.Now;
+
+ if(supportedSubchannel != MmcSubchannel.None)
+ {
+ outputFormat.WriteSectorsLong(new byte[sectorSize], i + r, 1);
+
+ if(desiredSubchannel != MmcSubchannel.None)
+ outputFormat.WriteSectorsTag(new byte[subSize], i + r, 1,
+ SectorTagType.CdSectorSubchannel);
+ }
+ else
+ {
+ if(supportsLongSectors)
+ outputFormat.WriteSectorsLong(new byte[blockSize], i + r, 1);
+ else
+ {
+ if(cmdBuf.Length % sectorSize == 0)
+ outputFormat.WriteSectors(new byte[2048], i + r, 1);
+ else
+ outputFormat.WriteSectorsLong(new byte[blockSize], i + r, 1);
+ }
+ }
+
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+
+ _resume.BadBlocks.Add(i + r);
+
+ AaruConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
+ mhddLog.Write(i + r, cmdDuration < 500 ? 65535 : cmdDuration);
+
+ ibgLog.Write(i + r, 0);
+ _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", 1, i + r);
+ newTrim = true;
}
- imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+ sectorSpeedStart += r;
- for(ulong b = i; b < i + _skip; b++)
- _resume.BadBlocks.Add(b);
+ _resume.NextBlock = i + r;
- AaruConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
- mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
+ elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
- ibgLog.Write(i, 0);
- _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
- i += _skip - blocksToRead;
- newTrim = true;
+ if(elapsed <= 0)
+ continue;
+
+ currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
+ sectorSpeedStart = 0;
+ timeSpeedStart = DateTime.UtcNow;
}
- sectorSpeedStart += blocksToRead;
-
- _resume.NextBlock = i + blocksToRead;
-
- elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
-
- if(elapsed <= 0)
- continue;
-
- currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
- sectorSpeedStart = 0;
- timeSpeedStart = DateTime.UtcNow;
+ continue;
}
- EndProgress?.Invoke();
+ if(!sense &&
+ !_dev.Error)
+ {
+ if(crossingLeadOut && failedCrossingLeadOut)
+ {
+ byte[] tmp = new byte[cmdBuf.Length + blockSize];
+ Array.Copy(cmdBuf, 0, tmp, 0, cmdBuf.Length);
+ }
- _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();
+ // Because one block has been partially used to fix the offset
+ if(_fixOffset &&
+ !inData &&
+ offsetBytes != 0)
+ FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead,
+ subSize, ref cmdBuf, blockSize, failedCrossingLeadOut);
- if(!failedCrossingLeadOut)
- return;
+ mhddLog.Write(i, cmdDuration);
+ ibgLog.Write(i, currentSpeed * 1024);
+ extents.Add(i, blocksToRead, true);
+ DateTime writeStart = DateTime.Now;
- _dumpLog.WriteLine("Failed crossing into Lead-Out, dump may not be correct.");
- UpdateStatus?.Invoke("Failed crossing into Lead-Out, dump may not be correct.");
+ if(supportedSubchannel != MmcSubchannel.None)
+ {
+ byte[] data = new byte[sectorSize * blocksToRead];
+ byte[] sub = new byte[subSize * blocksToRead];
+
+ for(int b = 0; b < blocksToRead; b++)
+ {
+ Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
+
+ Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
+ }
+
+ if(supportsLongSectors)
+ outputFormat.WriteSectorsLong(data, i, blocksToRead);
+ else
+ {
+ var cooked = new MemoryStream();
+ byte[] sector = new byte[sectorSize];
+
+ for(int b = 0; b < blocksToRead; b++)
+ {
+ Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), sector, 0, sectorSize);
+ byte[] cookedSector = Sector.GetUserData(sector);
+ cooked.Write(cookedSector, 0, cookedSector.Length);
+ }
+
+ outputFormat.WriteSectors(cooked.ToArray(), i, blocksToRead);
+ }
+
+ bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
+ desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, (byte)track.Sequence,
+ ref mcn, tracks, subchannelExtents, _fixSubchannelPosition, outputFormat as IWritableOpticalImage,
+ _fixSubchannel, _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack,
+ true);
+
+ // Set tracks and go back
+ if(indexesChanged)
+ {
+ (outputFormat as IWritableOpticalImage).SetTracks(tracks.ToList());
+ i -= blocksToRead;
+
+ continue;
+ }
+ }
+ else
+ {
+ if(supportsLongSectors)
+ outputFormat.WriteSectorsLong(cmdBuf, i, blocksToRead);
+ else
+ {
+ var cooked = new MemoryStream();
+ byte[] sector = new byte[sectorSize];
+
+ for(int b = 0; b < blocksToRead; b++)
+ {
+ Array.Copy(cmdBuf, (int)(b * sectorSize), sector, 0, sectorSize);
+ byte[] cookedSector = Sector.GetUserData(sector);
+ cooked.Write(cookedSector, 0, cookedSector.Length);
+ }
+
+ outputFormat.WriteSectors(cooked.ToArray(), i, blocksToRead);
+ }
+ }
+
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+ }
+ else
+ {
+ if(crossingLeadOut && Sense.Decode(senseBuf)?.ASC == 0x21)
+ {
+ if(failedCrossingLeadOut)
+ break;
+
+ failedCrossingLeadOut = true;
+ blocksToRead = 0;
+
+ continue;
+ }
+
+ _errorLog?.WriteLine(firstSectorToRead, _dev.Error, _dev.LastError, senseBuf);
+
+ // TODO: Reset device after X errors
+ if(_stopOnError)
+ return; // TODO: Return more cleanly
+
+ if(i + _skip > blocks)
+ _skip = (uint)(blocks - i);
+
+ // Write empty data
+ DateTime writeStart = DateTime.Now;
+
+ if(supportedSubchannel != MmcSubchannel.None)
+ {
+ outputFormat.WriteSectorsLong(new byte[sectorSize * _skip], i, _skip);
+
+ if(desiredSubchannel != MmcSubchannel.None)
+ outputFormat.WriteSectorsTag(new byte[subSize * _skip], i, _skip,
+ SectorTagType.CdSectorSubchannel);
+ }
+ else
+ {
+ if(supportsLongSectors)
+ {
+ outputFormat.WriteSectorsLong(new byte[blockSize * _skip], i, _skip);
+ }
+ else
+ {
+ if(cmdBuf.Length % sectorSize == 0)
+ outputFormat.WriteSectors(new byte[2048 * _skip], i, _skip);
+ else
+ outputFormat.WriteSectorsLong(new byte[blockSize * _skip], i, _skip);
+ }
+ }
+
+ imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
+
+ for(ulong b = i; b < i + _skip; b++)
+ _resume.BadBlocks.Add(b);
+
+ AaruConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
+ mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
+
+ ibgLog.Write(i, 0);
+ _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
+ i += _skip - blocksToRead;
+ newTrim = true;
+ }
+
+ sectorSpeedStart += blocksToRead;
+
+ _resume.NextBlock = i + blocksToRead;
+
+ elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
+
+ if(elapsed <= 0)
+ continue;
+
+ currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
+ sectorSpeedStart = 0;
+ timeSpeedStart = DateTime.UtcNow;
}
+
+ EndProgress?.Invoke();
+
+ _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();
+
+ if(!failedCrossingLeadOut)
+ return;
+
+ _dumpLog.WriteLine("Failed crossing into Lead-Out, dump may not be correct.");
+ UpdateStatus?.Invoke("Failed crossing into Lead-Out, dump may not be correct.");
}
}
\ No newline at end of file
diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs
index eb931d17a..5039351b6 100644
--- a/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs
+++ b/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs
@@ -53,1006 +53,994 @@ using Version = Aaru.CommonTypes.Interop.Version;
// ReSharper disable InlineOutVariableDeclaration
// ReSharper disable TooWideLocalVariableScope
-namespace Aaru.Core.Devices.Dumping
+namespace Aaru.Core.Devices.Dumping;
+
+/// Implement dumping Compact Discs
+
+// TODO: Barcode
+sealed partial class Dump
{
- /// Implement dumping Compact Discs
-
- // TODO: Barcode
- sealed partial class Dump
+ /// Dumps a compact disc
+ void CompactDisc()
{
- /// Dumps a compact disc
- void CompactDisc()
+ ExtentsULong audioExtents; // Extents with audio sectors
+ ulong blocks; // Total number of positive sectors
+ uint blockSize; // Size of the read sector in bytes
+ CdOffset cdOffset; // Read offset from database
+ byte[] cmdBuf; // Data buffer
+ DumpHardwareType currentTry = null; // Current dump hardware try
+ double currentSpeed = 0; // Current read speed
+ int? discOffset = null; // Disc write offset
+ DateTime dumpStart = DateTime.UtcNow; // Time of dump start
+ DateTime end; // Time of operation end
+ ExtentsULong extents = null; // Extents
+ bool hiddenData; // Hidden track is data
+ IbgLog ibgLog; // IMGBurn log
+ double imageWriteDuration = 0; // Duration of image write
+ long lastSector; // Last sector number
+ var leadOutExtents = new ExtentsULong(); // Lead-out extents
+ Dictionary leadOutStarts = new(); // Lead-out starts
+ double maxSpeed = double.MinValue; // Maximum speed
+ MhddLog mhddLog; // MHDD log
+ double minSpeed = double.MaxValue; // Minimum speed
+ bool newTrim; // Is trim a new one?
+ int offsetBytes = 0; // Read offset
+ bool read6 = false; // Device supports READ(6)
+ bool read10 = false; // Device supports READ(10)
+ bool read12 = false; // Device supports READ(12)
+ bool read16 = false; // Device supports READ(16)
+ bool readcd; // Device supports READ CD
+ bool ret; // Image writing return status
+ const uint sectorSize = 2352; // Full sector size
+ int sectorsForOffset = 0; // Sectors needed to fix offset
+ bool sense = true; // Sense indicator
+ int sessions; // Number of sessions in disc
+ DateTime start; // Start of operation
+ SubchannelLog subLog = null; // Subchannel log
+ uint subSize; // Subchannel size in bytes
+ TrackSubchannelType subType; // Track subchannel type
+ bool supportsLongSectors = true; // Supports reading EDC and ECC
+ bool supportsPqSubchannel; // Supports reading PQ subchannel
+ bool supportsRwSubchannel; // Supports reading RW subchannel
+ byte[] tmpBuf; // Temporary buffer
+ FullTOC.CDFullTOC? toc; // Full CD TOC
+ double totalDuration = 0; // Total commands duration
+ Dictionary trackFlags = new(); // Track flags
+ Track[] tracks; // Tracks in disc
+ int firstTrackLastSession; // Number of first track in last session
+ bool hiddenTrack; // Disc has a hidden track before track 1
+ MmcSubchannel supportedSubchannel; // Drive's maximum supported subchannel
+ MmcSubchannel desiredSubchannel; // User requested subchannel
+ bool bcdSubchannel = false; // Subchannel positioning is in BCD
+ Dictionary isrcs = new();
+ string mcn = null;
+ HashSet subchannelExtents = new();
+ bool cdiReadyReadAsAudio = false;
+ uint firstLba;
+ var outputOptical = _outputPlugin as IWritableOpticalImage;
+
+ Dictionary mediaTags = new(); // Media tags
+ Dictionary smallestPregapLbaPerTrack = new();
+
+ MediaType dskType = MediaType.CD;
+
+ if(_dumpRaw)
{
- ExtentsULong audioExtents; // Extents with audio sectors
- ulong blocks; // Total number of positive sectors
- uint blockSize; // Size of the read sector in bytes
- CdOffset cdOffset; // Read offset from database
- byte[] cmdBuf; // Data buffer
- DumpHardwareType currentTry = null; // Current dump hardware try
- double currentSpeed = 0; // Current read speed
- int? discOffset = null; // Disc write offset
- DateTime dumpStart = DateTime.UtcNow; // Time of dump start
- DateTime end; // Time of operation end
- ExtentsULong extents = null; // Extents
- bool hiddenData; // Hidden track is data
- IbgLog ibgLog; // IMGBurn log
- double imageWriteDuration = 0; // Duration of image write
- long lastSector; // Last sector number
- var leadOutExtents = new ExtentsULong(); // Lead-out extents
- Dictionary leadOutStarts = new(); // Lead-out starts
- double maxSpeed = double.MinValue; // Maximum speed
- MhddLog mhddLog; // MHDD log
- double minSpeed = double.MaxValue; // Minimum speed
- bool newTrim; // Is trim a new one?
- int offsetBytes = 0; // Read offset
- bool read6 = false; // Device supports READ(6)
- bool read10 = false; // Device supports READ(10)
- bool read12 = false; // Device supports READ(12)
- bool read16 = false; // Device supports READ(16)
- bool readcd; // Device supports READ CD
- bool ret; // Image writing return status
- const uint sectorSize = 2352; // Full sector size
- int sectorsForOffset = 0; // Sectors needed to fix offset
- bool sense = true; // Sense indicator
- int sessions; // Number of sessions in disc
- DateTime start; // Start of operation
- SubchannelLog subLog = null; // Subchannel log
- uint subSize; // Subchannel size in bytes
- TrackSubchannelType subType; // Track subchannel type
- bool supportsLongSectors = true; // Supports reading EDC and ECC
- bool supportsPqSubchannel; // Supports reading PQ subchannel
- bool supportsRwSubchannel; // Supports reading RW subchannel
- byte[] tmpBuf; // Temporary buffer
- FullTOC.CDFullTOC? toc; // Full CD TOC
- double totalDuration = 0; // Total commands duration
- Dictionary trackFlags = new(); // Track flags
- Track[] tracks; // Tracks in disc
- int firstTrackLastSession; // Number of first track in last session
- bool hiddenTrack; // Disc has a hidden track before track 1
- MmcSubchannel supportedSubchannel; // Drive's maximum supported subchannel
- MmcSubchannel desiredSubchannel; // User requested subchannel
- bool bcdSubchannel = false; // Subchannel positioning is in BCD
- Dictionary isrcs = new();
- string mcn = null;
- HashSet subchannelExtents = new();
- bool cdiReadyReadAsAudio = false;
- uint firstLba;
- var outputOptical = _outputPlugin as IWritableOpticalImage;
+ _dumpLog.WriteLine("Raw CD dumping not yet implemented");
+ StoppingErrorMessage?.Invoke("Raw CD dumping not yet implemented");
- Dictionary mediaTags = new(); // Media tags
- Dictionary smallestPregapLbaPerTrack = new();
+ return;
+ }
- MediaType dskType = MediaType.CD;
+ tracks = GetCdTracks(_dev, _dumpLog, _force, out lastSector, leadOutStarts, mediaTags, StoppingErrorMessage,
+ out toc, trackFlags, UpdateStatus);
- if(_dumpRaw)
- {
- _dumpLog.WriteLine("Raw CD dumping not yet implemented");
- StoppingErrorMessage?.Invoke("Raw CD dumping not yet implemented");
+ if(tracks is null)
+ {
+ _dumpLog.WriteLine("Could not get tracks!");
+ StoppingErrorMessage?.Invoke("Could not get tracks!");
- return;
- }
+ return;
+ }
- tracks = GetCdTracks(_dev, _dumpLog, _force, out lastSector, leadOutStarts, mediaTags, StoppingErrorMessage,
- out toc, trackFlags, UpdateStatus);
+ firstLba = (uint)tracks.Min(t => t.StartSector);
- if(tracks is null)
- {
- _dumpLog.WriteLine("Could not get tracks!");
- StoppingErrorMessage?.Invoke("Could not get tracks!");
+ // Check subchannels support
+ supportsPqSubchannel = SupportsPqSubchannel(_dev, _dumpLog, UpdateStatus, firstLba);
+ supportsRwSubchannel = SupportsRwSubchannel(_dev, _dumpLog, UpdateStatus, firstLba);
- return;
- }
+ if(supportsRwSubchannel)
+ supportedSubchannel = MmcSubchannel.Raw;
+ else if(supportsPqSubchannel)
+ supportedSubchannel = MmcSubchannel.Q16;
+ else
+ supportedSubchannel = MmcSubchannel.None;
- firstLba = (uint)tracks.Min(t => t.StartSector);
-
- // Check subchannels support
- supportsPqSubchannel = SupportsPqSubchannel(_dev, _dumpLog, UpdateStatus, firstLba);
- supportsRwSubchannel = SupportsRwSubchannel(_dev, _dumpLog, UpdateStatus, firstLba);
-
- if(supportsRwSubchannel)
- supportedSubchannel = MmcSubchannel.Raw;
- else if(supportsPqSubchannel)
- supportedSubchannel = MmcSubchannel.Q16;
- else
- supportedSubchannel = MmcSubchannel.None;
-
- switch(_subchannel)
- {
- case DumpSubchannel.Any:
- if(supportsRwSubchannel)
- desiredSubchannel = MmcSubchannel.Raw;
- else if(supportsPqSubchannel)
- desiredSubchannel = MmcSubchannel.Q16;
- else
- desiredSubchannel = MmcSubchannel.None;
-
- break;
- case DumpSubchannel.Rw:
- if(supportsRwSubchannel)
- desiredSubchannel = MmcSubchannel.Raw;
- else
- {
- _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing...");
-
- StoppingErrorMessage?.
- Invoke("Drive does not support the requested subchannel format, not continuing...");
-
- return;
- }
-
- break;
- case DumpSubchannel.RwOrPq:
- if(supportsRwSubchannel)
- desiredSubchannel = MmcSubchannel.Raw;
- else if(supportsPqSubchannel)
- desiredSubchannel = MmcSubchannel.Q16;
- else
- {
- _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing...");
-
- StoppingErrorMessage?.
- Invoke("Drive does not support the requested subchannel format, not continuing...");
-
- return;
- }
-
- break;
- case DumpSubchannel.Pq:
- if(supportsPqSubchannel)
- desiredSubchannel = MmcSubchannel.Q16;
- else
- {
- _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing...");
-
- StoppingErrorMessage?.
- Invoke("Drive does not support the requested subchannel format, not continuing...");
-
- return;
- }
-
- break;
- case DumpSubchannel.None:
+ switch(_subchannel)
+ {
+ case DumpSubchannel.Any:
+ if(supportsRwSubchannel)
+ desiredSubchannel = MmcSubchannel.Raw;
+ else if(supportsPqSubchannel)
+ desiredSubchannel = MmcSubchannel.Q16;
+ else
desiredSubchannel = MmcSubchannel.None;
- break;
- default: throw new ArgumentOutOfRangeException();
- }
-
- if(desiredSubchannel == MmcSubchannel.Q16 && supportsPqSubchannel)
- supportedSubchannel = MmcSubchannel.Q16;
-
- // Check if output format supports subchannels
- if(!outputOptical.SupportedSectorTags.Contains(SectorTagType.CdSectorSubchannel) &&
- desiredSubchannel != MmcSubchannel.None)
- {
- if(_force || _subchannel == DumpSubchannel.None)
- {
- _dumpLog.WriteLine("Output format does not support subchannels, continuing...");
- UpdateStatus?.Invoke("Output format does not support subchannels, continuing...");
- }
+ break;
+ case DumpSubchannel.Rw:
+ if(supportsRwSubchannel)
+ desiredSubchannel = MmcSubchannel.Raw;
else
{
- _dumpLog.WriteLine("Output format does not support subchannels, not continuing...");
- StoppingErrorMessage?.Invoke("Output format does not support subchannels, not continuing...");
+ _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing...");
+
+ StoppingErrorMessage?.
+ Invoke("Drive does not support the requested subchannel format, not continuing...");
return;
}
+ break;
+ case DumpSubchannel.RwOrPq:
+ if(supportsRwSubchannel)
+ desiredSubchannel = MmcSubchannel.Raw;
+ else if(supportsPqSubchannel)
+ desiredSubchannel = MmcSubchannel.Q16;
+ else
+ {
+ _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing...");
+
+ StoppingErrorMessage?.
+ Invoke("Drive does not support the requested subchannel format, not continuing...");
+
+ return;
+ }
+
+ break;
+ case DumpSubchannel.Pq:
+ if(supportsPqSubchannel)
+ desiredSubchannel = MmcSubchannel.Q16;
+ else
+ {
+ _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing...");
+
+ StoppingErrorMessage?.
+ Invoke("Drive does not support the requested subchannel format, not continuing...");
+
+ return;
+ }
+
+ break;
+ case DumpSubchannel.None:
desiredSubchannel = MmcSubchannel.None;
- }
- switch(supportedSubchannel)
+ break;
+ default: throw new ArgumentOutOfRangeException();
+ }
+
+ if(desiredSubchannel == MmcSubchannel.Q16 && supportsPqSubchannel)
+ supportedSubchannel = MmcSubchannel.Q16;
+
+ // Check if output format supports subchannels
+ if(!outputOptical.SupportedSectorTags.Contains(SectorTagType.CdSectorSubchannel) &&
+ desiredSubchannel != MmcSubchannel.None)
+ {
+ if(_force || _subchannel == DumpSubchannel.None)
{
- case MmcSubchannel.None:
- _dumpLog.WriteLine("Checking if drive supports reading without subchannel...");
- UpdateStatus?.Invoke("Checking if drive supports reading without subchannel...");
-
- readcd = !_dev.ReadCd(out cmdBuf, out _, firstLba, sectorSize, 1, MmcSectorTypes.AllTypes, false,
- false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
- supportedSubchannel, _dev.Timeout, out _);
-
- if(!readcd)
- {
- _dumpLog.WriteLine("Drive does not support READ CD, trying SCSI READ commands...");
- ErrorMessage?.Invoke("Drive does not support READ CD, trying SCSI READ commands...");
-
- _dumpLog.WriteLine("Checking if drive supports READ(6)...");
- UpdateStatus?.Invoke("Checking if drive supports READ(6)...");
- read6 = !_dev.Read6(out cmdBuf, out _, firstLba, 2048, 1, _dev.Timeout, out _);
- _dumpLog.WriteLine("Checking if drive supports READ(10)...");
- UpdateStatus?.Invoke("Checking if drive supports READ(10)...");
-
- read10 = !_dev.Read10(out cmdBuf, out _, 0, false, true, false, false, firstLba, 2048, 0, 1,
- _dev.Timeout, out _);
-
- _dumpLog.WriteLine("Checking if drive supports READ(12)...");
- UpdateStatus?.Invoke("Checking if drive supports READ(12)...");
-
- read12 = !_dev.Read12(out cmdBuf, out _, 0, false, true, false, false, firstLba, 2048, 0, 1,
- false, _dev.Timeout, out _);
-
- _dumpLog.WriteLine("Checking if drive supports READ(16)...");
- UpdateStatus?.Invoke("Checking if drive supports READ(16)...");
-
- read16 = !_dev.Read16(out cmdBuf, out _, 0, false, true, false, firstLba, 2048, 0, 1, false,
- _dev.Timeout, out _);
-
- if(!read6 &&
- !read10 &&
- !read12 &&
- !read16)
- {
- _dumpLog.WriteLine("Cannot read from disc, not continuing...");
- StoppingErrorMessage?.Invoke("Cannot read from disc, not continuing...");
-
- return;
- }
-
- if(read6)
- {
- _dumpLog.WriteLine("Drive supports READ(6)...");
- UpdateStatus?.Invoke("Drive supports READ(6)...");
- }
-
- if(read10)
- {
- _dumpLog.WriteLine("Drive supports READ(10)...");
- UpdateStatus?.Invoke("Drive supports READ(10)...");
- }
-
- if(read12)
- {
- _dumpLog.WriteLine("Drive supports READ(12)...");
- UpdateStatus?.Invoke("Drive supports READ(12)...");
- }
-
- if(read16)
- {
- _dumpLog.WriteLine("Drive supports READ(16)...");
- UpdateStatus?.Invoke("Drive supports READ(16)...");
- }
- }
-
- _dumpLog.WriteLine("Drive can read without subchannel...");
- UpdateStatus?.Invoke("Drive can read without subchannel...");
-
- subSize = 0;
- subType = TrackSubchannelType.None;
-
- break;
- case MmcSubchannel.Raw:
- _dumpLog.WriteLine("Full raw subchannel reading supported...");
- UpdateStatus?.Invoke("Full raw subchannel reading supported...");
- subType = TrackSubchannelType.Raw;
- subSize = 96;
- readcd = true;
-
- break;
- case MmcSubchannel.Q16:
- _dumpLog.WriteLine("PQ subchannel reading supported...");
- _dumpLog.WriteLine("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!");
- UpdateStatus?.Invoke("PQ subchannel reading supported...");
-
- UpdateStatus?.
- Invoke("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!");
-
- subType = TrackSubchannelType.Q16;
- subSize = 16;
- readcd = true;
-
- break;
- default:
- _dumpLog.WriteLine("Handling subchannel type {0} not supported, exiting...", supportedSubchannel);
-
- StoppingErrorMessage?.
- Invoke($"Handling subchannel type {supportedSubchannel} not supported, exiting...");
-
- return;
+ _dumpLog.WriteLine("Output format does not support subchannels, continuing...");
+ UpdateStatus?.Invoke("Output format does not support subchannels, continuing...");
}
-
- switch(desiredSubchannel)
+ else
{
- case MmcSubchannel.None:
- subType = TrackSubchannelType.None;
-
- break;
- case MmcSubchannel.Raw:
- case MmcSubchannel.Q16:
- subType = TrackSubchannelType.Raw;
-
- break;
- }
-
- blockSize = sectorSize + subSize;
-
- // Check if subchannel is BCD
- if(supportedSubchannel != MmcSubchannel.None)
- {
- sense = _dev.ReadCd(out cmdBuf, out _, (((firstLba / 75) + 1) * 75) + 35, blockSize, 1,
- MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true,
- MmcErrorField.None, supportedSubchannel, _dev.Timeout, out _);
-
- if(!sense)
- {
- tmpBuf = new byte[subSize];
- Array.Copy(cmdBuf, sectorSize, tmpBuf, 0, subSize);
-
- if(supportedSubchannel == MmcSubchannel.Q16)
- tmpBuf = Subchannel.ConvertQToRaw(tmpBuf);
-
- tmpBuf = Subchannel.Deinterleave(tmpBuf);
-
- // 9th Q subchannel is always FRAME when in user data area
- // LBA 35 => MSF 00:02:35 => FRAME 35 (in hexadecimal 0x23)
- // Sometimes drive returns a pregap here but MSF 00:02:3x => FRAME 3x (hexadecimal 0x20 to 0x27)
- bcdSubchannel = (tmpBuf[21] & 0x30) > 0;
-
- if(bcdSubchannel)
- {
- _dumpLog.WriteLine("Drive returns subchannel in BCD...");
- UpdateStatus?.Invoke("Drive returns subchannel in BCD...");
- }
- else
- {
- _dumpLog.WriteLine("Drive does not returns subchannel in BCD...");
- UpdateStatus?.Invoke("Drive does not returns subchannel in BCD...");
- }
- }
- }
-
- foreach(Track trk in tracks)
- trk.SubchannelType = subType;
-
- _dumpLog.WriteLine("Calculating pregaps, can take some time...");
- UpdateStatus?.Invoke("Calculating pregaps, can take some time...");
-
- SolveTrackPregaps(_dev, _dumpLog, UpdateStatus, tracks, supportsPqSubchannel, supportsRwSubchannel, _dbDev,
- out bool inexactPositioning, true);
-
- if(inexactPositioning)
- {
- _dumpLog.WriteLine("WARNING: The drive has returned incorrect Q positioning when calculating pregaps. A best effort has been tried but they may be incorrect.");
-
- UpdateStatus?.
- Invoke("WARNING: The drive has returned incorrect Q positioning when calculating pregaps. A best effort has been tried but they may be incorrect.");
- }
-
- if(!(outputOptical as IWritableOpticalImage).OpticalCapabilities.HasFlag(OpticalImageCapabilities.
- CanStoreRawData))
- {
- if(!_force)
- {
- _dumpLog.WriteLine("Output format does not support storing raw data, this may end in a loss of data, not continuing...");
-
- StoppingErrorMessage?.
- Invoke("Output format does not support storing raw data, this may end in a loss of data, not continuing...");
-
- return;
- }
-
- _dumpLog.WriteLine("Output format does not support storing raw data, this may end in a loss of data, continuing...");
-
- ErrorMessage?.
- Invoke("Output format does not support storing raw data, this may end in a loss of data, continuing...");
- }
-
- if(!(outputOptical as IWritableOpticalImage).OpticalCapabilities.HasFlag(OpticalImageCapabilities.
- CanStoreAudioTracks) &&
- tracks.Any(track => track.Type == TrackType.Audio))
- {
- _dumpLog.WriteLine("Output format does not support audio tracks, cannot continue...");
-
- StoppingErrorMessage?.Invoke("Output format does not support audio tracks, cannot continue...");
+ _dumpLog.WriteLine("Output format does not support subchannels, not continuing...");
+ StoppingErrorMessage?.Invoke("Output format does not support subchannels, not continuing...");
return;
}
- if(!(outputOptical as IWritableOpticalImage).OpticalCapabilities.HasFlag(OpticalImageCapabilities.
- CanStorePregaps) &&
- tracks.Where(track => track.Sequence != tracks.First(t => t.Session == track.Session).Sequence).
- Any(track => track.Pregap > 0))
- {
- if(!_force)
+ desiredSubchannel = MmcSubchannel.None;
+ }
+
+ switch(supportedSubchannel)
+ {
+ case MmcSubchannel.None:
+ _dumpLog.WriteLine("Checking if drive supports reading without subchannel...");
+ UpdateStatus?.Invoke("Checking if drive supports reading without subchannel...");
+
+ readcd = !_dev.ReadCd(out cmdBuf, out _, firstLba, sectorSize, 1, MmcSectorTypes.AllTypes, false,
+ false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
+ supportedSubchannel, _dev.Timeout, out _);
+
+ if(!readcd)
{
- _dumpLog.WriteLine("Output format does not support pregaps, this may end in a loss of data, not continuing...");
+ _dumpLog.WriteLine("Drive does not support READ CD, trying SCSI READ commands...");
+ ErrorMessage?.Invoke("Drive does not support READ CD, trying SCSI READ commands...");
- StoppingErrorMessage?.
- Invoke("Output format does not support pregaps, this may end in a loss of data, not continuing...");
+ _dumpLog.WriteLine("Checking if drive supports READ(6)...");
+ UpdateStatus?.Invoke("Checking if drive supports READ(6)...");
+ read6 = !_dev.Read6(out cmdBuf, out _, firstLba, 2048, 1, _dev.Timeout, out _);
+ _dumpLog.WriteLine("Checking if drive supports READ(10)...");
+ UpdateStatus?.Invoke("Checking if drive supports READ(10)...");
- return;
- }
+ read10 = !_dev.Read10(out cmdBuf, out _, 0, false, true, false, false, firstLba, 2048, 0, 1,
+ _dev.Timeout, out _);
- _dumpLog.WriteLine("Output format does not support pregaps, this may end in a loss of data, continuing...");
+ _dumpLog.WriteLine("Checking if drive supports READ(12)...");
+ UpdateStatus?.Invoke("Checking if drive supports READ(12)...");
- ErrorMessage?.
- Invoke("Output format does not support pregaps, this may end in a loss of data, continuing...");
- }
+ read12 = !_dev.Read12(out cmdBuf, out _, 0, false, true, false, false, firstLba, 2048, 0, 1,
+ false, _dev.Timeout, out _);
- for(int t = 1; t < tracks.Length; t++)
- tracks[t - 1].EndSector = tracks[t].StartSector - 1;
+ _dumpLog.WriteLine("Checking if drive supports READ(16)...");
+ UpdateStatus?.Invoke("Checking if drive supports READ(16)...");
- tracks[^1].EndSector = (ulong)lastSector;
- blocks = (ulong)(lastSector + 1);
+ read16 = !_dev.Read16(out cmdBuf, out _, 0, false, true, false, firstLba, 2048, 0, 1, false,
+ _dev.Timeout, out _);
- if(blocks == 0)
- {
- StoppingErrorMessage?.Invoke("Cannot dump blank media.");
-
- return;
- }
-
- ResumeSupport.Process(true, true, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, _dev.PlatformId,
- ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, _private, _force);
-
- if(currentTry == null ||
- extents == null)
- {
- StoppingErrorMessage?.Invoke("Could not process resume file, not continuing...");
-
- return;
- }
-
- // Read media tags
- ReadCdTags(ref dskType, mediaTags, out sessions, out firstTrackLastSession);
-
- if(!(outputOptical as IWritableOpticalImage).OpticalCapabilities.HasFlag(OpticalImageCapabilities.
- CanStoreSessions) &&
- sessions > 1)
- {
- // TODO: Disabled until 6.0
- /*if(!_force)
- {*/
- _dumpLog.WriteLine("Output format does not support sessions, this will end in a loss of data, not continuing...");
-
- StoppingErrorMessage?.
- Invoke("Output format does not support sessions, this will end in a loss of data, not continuing...");
-
- return;
- /*}
-
- _dumpLog.WriteLine("Output format does not support sessions, this will end in a loss of data, continuing...");
-
- ErrorMessage?.
- Invoke("Output format does not support sessions, this will end in a loss of data, continuing...");*/
- }
-
- // Check if output format supports all disc tags we have retrieved so far
- foreach(MediaTagType tag in mediaTags.Keys.Where(tag => !outputOptical.SupportedMediaTags.Contains(tag)))
- {
- if(_force)
- {
- _dumpLog.WriteLine("Output format does not support {0}, continuing...", tag);
- ErrorMessage?.Invoke($"Output format does not support {tag}, continuing...");
- }
- else
- {
- _dumpLog.WriteLine("Output format does not support {0}, not continuing...", tag);
- StoppingErrorMessage?.Invoke($"Output format does not support {tag}, not continuing...");
-
- return;
- }
- }
-
- if(leadOutStarts.Any())
- {
- UpdateStatus?.Invoke("Solving lead-outs...");
-
- foreach(KeyValuePair leadOuts in leadOutStarts)
- foreach(Track trk in tracks.Where(trk => trk.Session == leadOuts.Key).
- Where(trk => trk.EndSector >= (ulong)leadOuts.Value))
- trk.EndSector = (ulong)leadOuts.Value - 1;
-
- var dataExtents = new ExtentsULong();
-
- foreach(Track trk in tracks)
- dataExtents.Add(trk.StartSector, trk.EndSector);
-
- Tuple[] dataExtentsArray = dataExtents.ToArray();
-
- for(int i = 0; i < dataExtentsArray.Length - 1; i++)
- leadOutExtents.Add(dataExtentsArray[i].Item2 + 1, dataExtentsArray[i + 1].Item1 - 1);
- }
-
- _dumpLog.WriteLine("Detecting disc type...");
- UpdateStatus?.Invoke("Detecting disc type...");
-
- MMC.DetectDiscType(ref dskType, sessions, toc, _dev, out hiddenTrack, out hiddenData, firstTrackLastSession,
- blocks);
-
- if(hiddenTrack || firstLba > 0)
- {
- _dumpLog.WriteLine("Disc contains a hidden track...");
- UpdateStatus?.Invoke("Disc contains a hidden track...");
-
- List