mirror of
https://github.com/aaru-dps/Aaru.git
synced 2026-07-08 17:56:18 +00:00
Refactor XGD dumping and corrected L1 video dumping, now it generates the correct file size and matches with redump expectations.
Fixes #832
This commit is contained in:
@@ -76,6 +76,8 @@ partial class Dump
|
|||||||
double maxSpeed = double.MinValue;
|
double maxSpeed = double.MinValue;
|
||||||
double minSpeed = double.MaxValue;
|
double minSpeed = double.MaxValue;
|
||||||
|
|
||||||
|
UpdateStatus?.Invoke(string.Format(Localization.Core.Media_identified_as_0, dskType.Humanize()));
|
||||||
|
|
||||||
if(_outputPlugin is not IWritableImage outputFormat)
|
if(_outputPlugin is not IWritableImage outputFormat)
|
||||||
{
|
{
|
||||||
StoppingErrorMessage?.Invoke(Localization.Core.Image_is_not_writable_aborting);
|
StoppingErrorMessage?.Invoke(Localization.Core.Image_is_not_writable_aborting);
|
||||||
@@ -97,9 +99,9 @@ partial class Dump
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mediaTags.ContainsKey(MediaTagType.DVD_PFI)) mediaTags.Remove(MediaTagType.DVD_PFI);
|
mediaTags.Remove(MediaTagType.DVD_PFI);
|
||||||
|
|
||||||
if(mediaTags.ContainsKey(MediaTagType.DVD_DMI)) mediaTags.Remove(MediaTagType.DVD_DMI);
|
mediaTags.Remove(MediaTagType.DVD_DMI);
|
||||||
|
|
||||||
// Drive shall move to lock state when a new disc is inserted. Old kreon versions do not lock correctly so save this
|
// Drive shall move to lock state when a new disc is inserted. Old kreon versions do not lock correctly so save this
|
||||||
sense = _dev.ReadCapacity(out byte[] coldReadCapacity, out ReadOnlySpan<byte> senseBuf, _dev.Timeout, out _);
|
sense = _dev.ReadCapacity(out byte[] coldReadCapacity, out ReadOnlySpan<byte> senseBuf, _dev.Timeout, out _);
|
||||||
@@ -497,14 +499,14 @@ partial class Dump
|
|||||||
|
|
||||||
var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin",
|
var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin",
|
||||||
_dev,
|
_dev,
|
||||||
blocks,
|
totalSize,
|
||||||
blockSize,
|
blockSize,
|
||||||
blocksToRead,
|
blocksToRead,
|
||||||
_private,
|
_private,
|
||||||
_dimensions);
|
_dimensions);
|
||||||
|
|
||||||
var ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0010);
|
var ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0010);
|
||||||
ret = outputFormat.Create(_outputPath, dskType, _formatOptions, blocks, 0, 0, blockSize);
|
ret = outputFormat.Create(_outputPath, dskType, _formatOptions, totalSize, 0, 0, blockSize);
|
||||||
|
|
||||||
// Cannot create image
|
// Cannot create image
|
||||||
if(!ret)
|
if(!ret)
|
||||||
@@ -586,7 +588,14 @@ partial class Dump
|
|||||||
InitProgress?.Invoke();
|
InitProgress?.Invoke();
|
||||||
double elapsed = 0;
|
double elapsed = 0;
|
||||||
|
|
||||||
for(var e = 0; e <= 16; e++)
|
// XGD1 uses 16 protection extents (indices 0-15).
|
||||||
|
// XGD2 and XGD3 only have actual protection zones at indices 0 and 3;
|
||||||
|
// the other entries contain challenge-response authentication data, not unreadable sector ranges.
|
||||||
|
int[] protectionExtentIndices = dskType == MediaType.XGD
|
||||||
|
? [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
||||||
|
: [0, 3];
|
||||||
|
|
||||||
|
for(var ei = 0; ei <= protectionExtentIndices.Length; ei++)
|
||||||
{
|
{
|
||||||
if(_aborted)
|
if(_aborted)
|
||||||
{
|
{
|
||||||
@@ -602,8 +611,10 @@ partial class Dump
|
|||||||
ulong extentStart, extentEnd;
|
ulong extentStart, extentEnd;
|
||||||
|
|
||||||
// Extents
|
// Extents
|
||||||
if(e < 16)
|
if(ei < protectionExtentIndices.Length)
|
||||||
{
|
{
|
||||||
|
int e = protectionExtentIndices[ei];
|
||||||
|
|
||||||
if(xboxSs.Value.Extents[e].StartPSN <= xboxSs.Value.Layer0EndPSN)
|
if(xboxSs.Value.Extents[e].StartPSN <= xboxSs.Value.Layer0EndPSN)
|
||||||
extentStart = xboxSs.Value.Extents[e].StartPSN - 0x30000;
|
extentStart = xboxSs.Value.Extents[e].StartPSN - 0x30000;
|
||||||
else
|
else
|
||||||
@@ -623,11 +634,11 @@ partial class Dump
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// After last extent
|
// After last extent — sentinel: extentEnd < extentStart so the protection write loop does not run
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
extentStart = blocks;
|
extentStart = blocks;
|
||||||
extentEnd = blocks;
|
extentEnd = blocks - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(currentSector > extentEnd) continue;
|
if(currentSector > extentEnd) continue;
|
||||||
@@ -793,11 +804,15 @@ partial class Dump
|
|||||||
|
|
||||||
EndProgress?.Invoke();
|
EndProgress?.Invoke();
|
||||||
|
|
||||||
|
// Ensure middle zone starts right after the locked-capacity boundary regardless of where
|
||||||
|
// the game loop ended (protection zone 3 may push currentSector past blocks)
|
||||||
|
if(!_aborted) currentSector = blocks;
|
||||||
|
|
||||||
// Middle Zone D
|
// Middle Zone D
|
||||||
UpdateStatus?.Invoke(Localization.Core.Writing_Middle_Zone_D_empty);
|
UpdateStatus?.Invoke(Localization.Core.Writing_Middle_Zone_D_empty);
|
||||||
InitProgress?.Invoke();
|
InitProgress?.Invoke();
|
||||||
|
|
||||||
for(ulong middle = currentSector - blocks - 1; middle < middleZone - 1; middle += blocksToRead)
|
for(ulong middle = 0; middle < middleZone; middle += blocksToRead)
|
||||||
{
|
{
|
||||||
if(_aborted)
|
if(_aborted)
|
||||||
{
|
{
|
||||||
@@ -807,29 +822,28 @@ partial class Dump
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(middleZone - 1 - middle < blocksToRead) blocksToRead = (uint)(middleZone - 1 - middle);
|
if(middleZone - middle < blocksToRead) blocksToRead = (uint)(middleZone - middle);
|
||||||
|
|
||||||
UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2,
|
UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2,
|
||||||
middle + currentSector,
|
currentSector,
|
||||||
totalSize,
|
totalSize,
|
||||||
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||||
(long)(middle + currentSector),
|
(long)currentSector,
|
||||||
(long)totalSize);
|
(long)totalSize);
|
||||||
|
|
||||||
mhddLog.Write(middle + currentSector, _speedStopwatch.Elapsed.TotalMilliseconds, blocksToRead);
|
mhddLog.Write(currentSector, _speedStopwatch.Elapsed.TotalMilliseconds, blocksToRead);
|
||||||
ibgLog.Write(middle + currentSector, currentSpeed * 1024);
|
ibgLog.Write(currentSector, currentSpeed * 1024);
|
||||||
|
|
||||||
// Write empty data
|
// Write empty data
|
||||||
_writeStopwatch.Restart();
|
_writeStopwatch.Restart();
|
||||||
|
|
||||||
outputFormat.WriteSectors(new byte[blockSize * blocksToRead],
|
outputFormat.WriteSectors(new byte[blockSize * blocksToRead],
|
||||||
middle + currentSector,
|
currentSector,
|
||||||
false,
|
false,
|
||||||
blocksToRead,
|
blocksToRead,
|
||||||
Enumerable.Repeat(SectorStatus.NotDumped, (int)blocksToRead).ToArray());
|
Enumerable.Repeat(SectorStatus.NotDumped, (int)blocksToRead).ToArray());
|
||||||
|
|
||||||
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
|
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
|
||||||
extents.Add(currentSector, blocksToRead, true);
|
|
||||||
_writeStopwatch.Stop();
|
_writeStopwatch.Stop();
|
||||||
|
|
||||||
currentSector += blocksToRead;
|
currentSector += blocksToRead;
|
||||||
|
|||||||
@@ -51,49 +51,48 @@ public sealed partial class HxCStream
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ErrorNumber Open(IFilter imageFilter)
|
public ErrorNumber Open(IFilter imageFilter)
|
||||||
{
|
{
|
||||||
_trackCaptures = [];
|
_trackCaptures = [];
|
||||||
_trackFilePaths = [];
|
_trackFilePaths = [];
|
||||||
_mediaTags = [];
|
_mediaTags = [];
|
||||||
_imageInfo.Heads = 0;
|
_imageInfo.Heads = 0;
|
||||||
_imageInfo.Cylinders = 0;
|
_imageInfo.Cylinders = 0;
|
||||||
|
|
||||||
string filename = imageFilter.Filename;
|
string filename = imageFilter.Filename;
|
||||||
string parentFolder = imageFilter.ParentFolder;
|
string parentFolder = imageFilter.ParentFolder;
|
||||||
|
|
||||||
// We always open a single file - extract basename to find related track files
|
// We always open a single file - extract basename to find related track files
|
||||||
if(!filename.EndsWith(".hxcstream", StringComparison.OrdinalIgnoreCase))
|
if(!filename.EndsWith(".hxcstream", StringComparison.OrdinalIgnoreCase)) return ErrorNumber.InvalidArgument;
|
||||||
return ErrorNumber.InvalidArgument;
|
|
||||||
|
|
||||||
// Extract basename - remove the track number pattern (e.g., "track00.0.hxcstream" -> "track")
|
// Extract basename - remove the track number pattern (e.g., "track00.0.hxcstream" -> "track")
|
||||||
// The pattern is {basename}{cylinder:D2}.{head:D1}.hxcstream
|
// The pattern is {basename}{cylinder:D2}.{head:D1}.hxcstream
|
||||||
string basename = filename[..^14]; // Remove ".XX.X.hxcstream" (14 chars)
|
string basename = filename[..^14]; // Remove ".XX.X.hxcstream" (14 chars)
|
||||||
string fullBasename = Path.Combine(parentFolder, basename);
|
string fullBasename = Path.Combine(parentFolder, basename);
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Opening HxCStream image from file: {0}", filename);
|
AaruLogging.Debug(MODULE_NAME, "Opening HxCStream image from file: {0}", filename);
|
||||||
AaruLogging.Debug(MODULE_NAME, "Basename: {0}", basename);
|
AaruLogging.Debug(MODULE_NAME, "Basename: {0}", basename);
|
||||||
AaruLogging.Debug(MODULE_NAME, "Full basename path: {0}", fullBasename);
|
AaruLogging.Debug(MODULE_NAME, "Full basename path: {0}", fullBasename);
|
||||||
|
|
||||||
// Discover track files by trying different cylinder/head combinations
|
// Discover track files by trying different cylinder/head combinations
|
||||||
var trackFiles = new Dictionary<(int cylinder, int head), string>();
|
var trackFiles = new Dictionary<(int cylinder, int head), string>();
|
||||||
int minCylinder = int.MaxValue;
|
int minCylinder = int.MaxValue;
|
||||||
int maxCylinder = int.MinValue;
|
int maxCylinder = int.MinValue;
|
||||||
int minHead = int.MaxValue;
|
int minHead = int.MaxValue;
|
||||||
int maxHead = int.MinValue;
|
int maxHead = int.MinValue;
|
||||||
|
|
||||||
// Search for related track files
|
// Search for related track files
|
||||||
for(int cylinder = 0; cylinder < 166; cylinder++)
|
for(var cylinder = 0; cylinder < 166; cylinder++)
|
||||||
{
|
{
|
||||||
for(int head = 0; head < 2; head++)
|
for(var head = 0; head < 2; head++)
|
||||||
{
|
{
|
||||||
string trackfile = $"{fullBasename}{cylinder:D2}.{head:D1}.hxcstream";
|
var trackfile = $"{fullBasename}{cylinder:D2}.{head:D1}.hxcstream";
|
||||||
|
|
||||||
if(File.Exists(trackfile))
|
if(File.Exists(trackfile))
|
||||||
{
|
{
|
||||||
trackFiles[(cylinder, head)] = trackfile;
|
trackFiles[(cylinder, head)] = trackfile;
|
||||||
minCylinder = Math.Min(minCylinder, cylinder);
|
minCylinder = Math.Min(minCylinder, cylinder);
|
||||||
maxCylinder = Math.Max(maxCylinder, cylinder);
|
maxCylinder = Math.Max(maxCylinder, cylinder);
|
||||||
minHead = Math.Min(minHead, head);
|
minHead = Math.Min(minHead, head);
|
||||||
maxHead = Math.Max(maxHead, head);
|
maxHead = Math.Max(maxHead, head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,14 +100,20 @@ public sealed partial class HxCStream
|
|||||||
if(trackFiles.Count == 0) return ErrorNumber.NoData;
|
if(trackFiles.Count == 0) return ErrorNumber.NoData;
|
||||||
|
|
||||||
_imageInfo.Cylinders = (uint)(maxCylinder - minCylinder + 1);
|
_imageInfo.Cylinders = (uint)(maxCylinder - minCylinder + 1);
|
||||||
_imageInfo.Heads = (uint)(maxHead - minHead + 1);
|
_imageInfo.Heads = (uint)(maxHead - minHead + 1);
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Found {0} track files", trackFiles.Count);
|
AaruLogging.Debug(MODULE_NAME, "Found {0} track files", trackFiles.Count);
|
||||||
AaruLogging.Debug(MODULE_NAME, "Cylinder range: {0} to {1} ({2} cylinders)", minCylinder, maxCylinder, _imageInfo.Cylinders);
|
|
||||||
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
|
"Cylinder range: {0} to {1} ({2} cylinders)",
|
||||||
|
minCylinder,
|
||||||
|
maxCylinder,
|
||||||
|
_imageInfo.Cylinders);
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Head range: {0} to {1} ({2} heads)", minHead, maxHead, _imageInfo.Heads);
|
AaruLogging.Debug(MODULE_NAME, "Head range: {0} to {1} ({2} heads)", minHead, maxHead, _imageInfo.Heads);
|
||||||
|
|
||||||
// Process each track file
|
// Process each track file
|
||||||
int trackIndex = 0;
|
var trackIndex = 0;
|
||||||
int totalTracks = trackFiles.Count;
|
int totalTracks = trackFiles.Count;
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Processing {0} track files...", totalTracks);
|
AaruLogging.Debug(MODULE_NAME, "Processing {0} track files...", totalTracks);
|
||||||
@@ -119,8 +124,12 @@ public sealed partial class HxCStream
|
|||||||
string trackfile = trackFiles[key];
|
string trackfile = trackFiles[key];
|
||||||
_trackFilePaths.Add(trackfile);
|
_trackFilePaths.Add(trackfile);
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Processing track {0}/{1}: cylinder {2}, head {3}",
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
trackIndex, totalTracks, key.cylinder, key.head);
|
"Processing track {0}/{1}: cylinder {2}, head {3}",
|
||||||
|
trackIndex,
|
||||||
|
totalTracks,
|
||||||
|
key.cylinder,
|
||||||
|
key.head);
|
||||||
|
|
||||||
ErrorNumber error = ProcessTrackFile(trackfile, (uint)key.head, (ushort)key.cylinder);
|
ErrorNumber error = ProcessTrackFile(trackfile, (uint)key.head, (ushort)key.cylinder);
|
||||||
|
|
||||||
@@ -141,15 +150,15 @@ public sealed partial class HxCStream
|
|||||||
AaruLogging.Debug(MODULE_NAME, "Processing track file: {0} (head {1}, track {2})", trackfile, head, track);
|
AaruLogging.Debug(MODULE_NAME, "Processing track file: {0} (head {1}, track {2})", trackfile, head, track);
|
||||||
|
|
||||||
using FileStream fileStream = File.OpenRead(trackfile);
|
using FileStream fileStream = File.OpenRead(trackfile);
|
||||||
byte[] fileData = new byte[fileStream.Length];
|
var fileData = new byte[fileStream.Length];
|
||||||
fileStream.EnsureRead(fileData, 0, (int)fileStream.Length);
|
fileStream.EnsureRead(fileData, 0, (int)fileStream.Length);
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Track file size: {0} bytes", fileData.Length);
|
AaruLogging.Debug(MODULE_NAME, "Track file size: {0} bytes", fileData.Length);
|
||||||
|
|
||||||
uint samplePeriod = DEFAULT_RESOLUTION; // Default 40,000 ns (25 MHz)
|
uint samplePeriod = DEFAULT_RESOLUTION; // Default 40,000 ns (25 MHz)
|
||||||
var fluxPulses = new List<uint>();
|
var fluxPulses = new List<uint>();
|
||||||
var ioStream = new List<ushort>();
|
var ioStream = new List<ushort>();
|
||||||
string metadata = null;
|
string metadata = null;
|
||||||
|
|
||||||
long fileOffset = 0;
|
long fileOffset = 0;
|
||||||
|
|
||||||
@@ -158,10 +167,13 @@ public sealed partial class HxCStream
|
|||||||
if(fileOffset + Marshal.SizeOf<HxCStreamChunkHeader>() > fileData.Length)
|
if(fileOffset + Marshal.SizeOf<HxCStreamChunkHeader>() > fileData.Length)
|
||||||
return ErrorNumber.InvalidArgument;
|
return ErrorNumber.InvalidArgument;
|
||||||
|
|
||||||
HxCStreamChunkHeader chunkHeader = Marshal.ByteArrayToStructureLittleEndian<HxCStreamChunkHeader>(
|
HxCStreamChunkHeader chunkHeader =
|
||||||
fileData, (int)fileOffset, Marshal.SizeOf<HxCStreamChunkHeader>());
|
Marshal.ByteArrayToStructureLittleEndian<HxCStreamChunkHeader>(fileData,
|
||||||
|
(int)fileOffset,
|
||||||
|
Marshal.SizeOf<HxCStreamChunkHeader>());
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Chunk at offset {0}: signature = \"{1}\", size = {2}, packetNumber = {3}",
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
|
"Chunk at offset {0}: signature = \"{1}\", size = {2}, packetNumber = {3}",
|
||||||
fileOffset,
|
fileOffset,
|
||||||
StringHandlers.CToString(chunkHeader.signature),
|
StringHandlers.CToString(chunkHeader.signature),
|
||||||
chunkHeader.size,
|
chunkHeader.size,
|
||||||
@@ -172,27 +184,28 @@ public sealed partial class HxCStream
|
|||||||
if(chunkHeader.size > fileData.Length - fileOffset) return ErrorNumber.InvalidArgument;
|
if(chunkHeader.size > fileData.Length - fileOffset) return ErrorNumber.InvalidArgument;
|
||||||
|
|
||||||
// Verify CRC32 - calculate CRC of chunk data (excluding the CRC itself)
|
// Verify CRC32 - calculate CRC of chunk data (excluding the CRC itself)
|
||||||
byte[] chunkData = new byte[chunkHeader.size - 4];
|
var chunkData = new byte[chunkHeader.size - 4];
|
||||||
Array.Copy(fileData, (int)fileOffset, chunkData, 0, (int)(chunkHeader.size - 4));
|
Array.Copy(fileData, (int)fileOffset, chunkData, 0, (int)(chunkHeader.size - 4));
|
||||||
|
|
||||||
uint storedCrc = BitConverter.ToUInt32(fileData, (int)(fileOffset + chunkHeader.size - 4));
|
var storedCrc = BitConverter.ToUInt32(fileData, (int)(fileOffset + chunkHeader.size - 4));
|
||||||
|
|
||||||
if(!VerifyChunkCrc32(chunkData, storedCrc))
|
if(!VerifyChunkCrc32(chunkData, storedCrc))
|
||||||
{
|
{
|
||||||
AaruLogging.Error(MODULE_NAME, "CRC32 mismatch in chunk at offset {0}", fileOffset);
|
AaruLogging.Error(MODULE_NAME, "CRC32 mismatch in chunk at offset {0}", fileOffset);
|
||||||
|
|
||||||
return ErrorNumber.InvalidArgument;
|
return ErrorNumber.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Chunk CRC32 verified successfully");
|
AaruLogging.Debug(MODULE_NAME, "Chunk CRC32 verified successfully");
|
||||||
|
|
||||||
long packetOffset = fileOffset + Marshal.SizeOf<HxCStreamChunkHeader>();
|
long packetOffset = fileOffset + Marshal.SizeOf<HxCStreamChunkHeader>();
|
||||||
long chunkEnd = fileOffset + chunkHeader.size - 4;
|
long chunkEnd = fileOffset + chunkHeader.size - 4;
|
||||||
|
|
||||||
while(packetOffset < chunkEnd)
|
while(packetOffset < chunkEnd)
|
||||||
{
|
{
|
||||||
if(packetOffset + 4 > fileData.Length) break;
|
if(packetOffset + 4 > fileData.Length) break;
|
||||||
|
|
||||||
uint type = BitConverter.ToUInt32(fileData, (int)packetOffset);
|
var type = BitConverter.ToUInt32(fileData, (int)packetOffset);
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Packet at offset {0}: type = 0x{1:X8}", packetOffset, type);
|
AaruLogging.Debug(MODULE_NAME, "Packet at offset {0}: type = 0x{1:X8}", packetOffset, type);
|
||||||
|
|
||||||
@@ -205,17 +218,20 @@ public sealed partial class HxCStream
|
|||||||
|
|
||||||
HxCStreamMetadataHeader metadataHeader =
|
HxCStreamMetadataHeader metadataHeader =
|
||||||
Marshal.ByteArrayToStructureLittleEndian<HxCStreamMetadataHeader>(fileData,
|
Marshal.ByteArrayToStructureLittleEndian<HxCStreamMetadataHeader>(fileData,
|
||||||
(int)packetOffset,
|
(int)packetOffset,
|
||||||
Marshal.SizeOf<HxCStreamMetadataHeader>());
|
Marshal.SizeOf<HxCStreamMetadataHeader>());
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Metadata packet: type = 0x{0:X8}, payloadSize = {1}",
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
metadataHeader.type, metadataHeader.payloadSize);
|
"Metadata packet: type = 0x{0:X8}, payloadSize = {1}",
|
||||||
|
metadataHeader.type,
|
||||||
|
metadataHeader.payloadSize);
|
||||||
|
|
||||||
if(packetOffset + Marshal.SizeOf<HxCStreamMetadataHeader>() + metadataHeader.payloadSize >
|
if(packetOffset + Marshal.SizeOf<HxCStreamMetadataHeader>() + metadataHeader.payloadSize >
|
||||||
fileData.Length)
|
fileData.Length)
|
||||||
return ErrorNumber.InvalidArgument;
|
return ErrorNumber.InvalidArgument;
|
||||||
|
|
||||||
byte[] metadataBytes = new byte[metadataHeader.payloadSize];
|
var metadataBytes = new byte[metadataHeader.payloadSize];
|
||||||
|
|
||||||
Array.Copy(fileData,
|
Array.Copy(fileData,
|
||||||
(int)packetOffset + Marshal.SizeOf<HxCStreamMetadataHeader>(),
|
(int)packetOffset + Marshal.SizeOf<HxCStreamMetadataHeader>(),
|
||||||
metadataBytes,
|
metadataBytes,
|
||||||
@@ -227,8 +243,7 @@ public sealed partial class HxCStream
|
|||||||
AaruLogging.Debug(MODULE_NAME, "Metadata content: {0}", metadata);
|
AaruLogging.Debug(MODULE_NAME, "Metadata content: {0}", metadata);
|
||||||
|
|
||||||
// Parse metadata and populate ImageInfo (only parse once, from first chunk)
|
// Parse metadata and populate ImageInfo (only parse once, from first chunk)
|
||||||
if(string.IsNullOrEmpty(_imageInfo.Application))
|
if(string.IsNullOrEmpty(_imageInfo.Application)) ParseMetadata(metadata, _imageInfo);
|
||||||
ParseMetadata(metadata, _imageInfo);
|
|
||||||
|
|
||||||
// Check for sample rate in metadata
|
// Check for sample rate in metadata
|
||||||
if(metadata.Contains("sample_rate_hz 25000000"))
|
if(metadata.Contains("sample_rate_hz 25000000"))
|
||||||
@@ -258,38 +273,43 @@ public sealed partial class HxCStream
|
|||||||
|
|
||||||
HxCStreamPackedIoHeader ioHeader =
|
HxCStreamPackedIoHeader ioHeader =
|
||||||
Marshal.ByteArrayToStructureLittleEndian<HxCStreamPackedIoHeader>(fileData,
|
Marshal.ByteArrayToStructureLittleEndian<HxCStreamPackedIoHeader>(fileData,
|
||||||
(int)packetOffset,
|
(int)packetOffset,
|
||||||
Marshal.SizeOf<HxCStreamPackedIoHeader>());
|
Marshal.SizeOf<HxCStreamPackedIoHeader>());
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME,
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
"Packed IO stream packet: type = 0x{0:X8}, payloadSize = {1}, packedSize = {2}, unpackedSize = {3}",
|
"Packed IO stream packet: type = 0x{0:X8}, payloadSize = {1}, packedSize = {2}, unpackedSize = {3}",
|
||||||
ioHeader.type, ioHeader.payloadSize, ioHeader.packedSize, ioHeader.unpackedSize);
|
ioHeader.type,
|
||||||
|
ioHeader.payloadSize,
|
||||||
|
ioHeader.packedSize,
|
||||||
|
ioHeader.unpackedSize);
|
||||||
|
|
||||||
if(packetOffset + Marshal.SizeOf<HxCStreamPackedIoHeader>() + ioHeader.packedSize >
|
if(packetOffset + Marshal.SizeOf<HxCStreamPackedIoHeader>() + ioHeader.packedSize >
|
||||||
fileData.Length)
|
fileData.Length)
|
||||||
return ErrorNumber.InvalidArgument;
|
return ErrorNumber.InvalidArgument;
|
||||||
|
|
||||||
byte[] packedData = new byte[ioHeader.packedSize];
|
var packedData = new byte[ioHeader.packedSize];
|
||||||
|
|
||||||
Array.Copy(fileData,
|
Array.Copy(fileData,
|
||||||
(int)packetOffset + Marshal.SizeOf<HxCStreamPackedIoHeader>(),
|
(int)packetOffset + Marshal.SizeOf<HxCStreamPackedIoHeader>(),
|
||||||
packedData,
|
packedData,
|
||||||
0,
|
0,
|
||||||
(int)ioHeader.packedSize);
|
(int)ioHeader.packedSize);
|
||||||
|
|
||||||
byte[] unpackedData = new byte[ioHeader.unpackedSize];
|
var unpackedData = new byte[ioHeader.unpackedSize];
|
||||||
int decoded = LZ4.DecodeBuffer(packedData, unpackedData);
|
int decoded = LZ4.DecodeBuffer(packedData, unpackedData);
|
||||||
|
|
||||||
if(decoded != ioHeader.unpackedSize) return ErrorNumber.InvalidArgument;
|
if(decoded != ioHeader.unpackedSize) return ErrorNumber.InvalidArgument;
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Decompressed IO stream: {0} bytes -> {1} bytes ({2} 16-bit values)",
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
ioHeader.packedSize, decoded, decoded / 2);
|
"Decompressed IO stream: {0} bytes -> {1} bytes ({2} 16-bit values)",
|
||||||
|
ioHeader.packedSize,
|
||||||
|
decoded,
|
||||||
|
decoded / 2);
|
||||||
|
|
||||||
// Convert to ushort array
|
// Convert to ushort array
|
||||||
for(int i = 0; i < unpackedData.Length; i += 2)
|
for(var i = 0; i < unpackedData.Length; i += 2)
|
||||||
{
|
|
||||||
if(i + 1 < unpackedData.Length)
|
if(i + 1 < unpackedData.Length)
|
||||||
ioStream.Add(BitConverter.ToUInt16(unpackedData, i));
|
ioStream.Add(BitConverter.ToUInt16(unpackedData, i));
|
||||||
}
|
|
||||||
|
|
||||||
packetOffset += Marshal.SizeOf<HxCStreamPackedIoHeader>() + ioHeader.packedSize;
|
packetOffset += Marshal.SizeOf<HxCStreamPackedIoHeader>() + ioHeader.packedSize;
|
||||||
|
|
||||||
@@ -305,40 +325,50 @@ public sealed partial class HxCStream
|
|||||||
|
|
||||||
HxCStreamPackedStreamHeader streamHeader =
|
HxCStreamPackedStreamHeader streamHeader =
|
||||||
Marshal.ByteArrayToStructureLittleEndian<HxCStreamPackedStreamHeader>(fileData,
|
Marshal.ByteArrayToStructureLittleEndian<HxCStreamPackedStreamHeader>(fileData,
|
||||||
(int)packetOffset,
|
(int)packetOffset,
|
||||||
Marshal.SizeOf<HxCStreamPackedStreamHeader>());
|
Marshal.SizeOf<HxCStreamPackedStreamHeader>());
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME,
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
"Packed flux stream packet: type = 0x{0:X8}, payloadSize = {1}, packedSize = {2}, unpackedSize = {3}, numberOfPulses = {4}",
|
"Packed flux stream packet: type = 0x{0:X8}, payloadSize = {1}, packedSize = {2}, unpackedSize = {3}, numberOfPulses = {4}",
|
||||||
streamHeader.type, streamHeader.payloadSize, streamHeader.packedSize,
|
streamHeader.type,
|
||||||
streamHeader.unpackedSize, streamHeader.numberOfPulses);
|
streamHeader.payloadSize,
|
||||||
|
streamHeader.packedSize,
|
||||||
|
streamHeader.unpackedSize,
|
||||||
|
streamHeader.numberOfPulses);
|
||||||
|
|
||||||
if(packetOffset + Marshal.SizeOf<HxCStreamPackedStreamHeader>() + streamHeader.packedSize >
|
if(packetOffset + Marshal.SizeOf<HxCStreamPackedStreamHeader>() + streamHeader.packedSize >
|
||||||
fileData.Length)
|
fileData.Length)
|
||||||
return ErrorNumber.InvalidArgument;
|
return ErrorNumber.InvalidArgument;
|
||||||
|
|
||||||
byte[] packedData = new byte[streamHeader.packedSize];
|
var packedData = new byte[streamHeader.packedSize];
|
||||||
|
|
||||||
Array.Copy(fileData,
|
Array.Copy(fileData,
|
||||||
(int)packetOffset + Marshal.SizeOf<HxCStreamPackedStreamHeader>(),
|
(int)packetOffset + Marshal.SizeOf<HxCStreamPackedStreamHeader>(),
|
||||||
packedData,
|
packedData,
|
||||||
0,
|
0,
|
||||||
(int)streamHeader.packedSize);
|
(int)streamHeader.packedSize);
|
||||||
|
|
||||||
byte[] unpackedData = new byte[streamHeader.unpackedSize];
|
var unpackedData = new byte[streamHeader.unpackedSize];
|
||||||
int decoded = LZ4.DecodeBuffer(packedData, unpackedData);
|
int decoded = LZ4.DecodeBuffer(packedData, unpackedData);
|
||||||
|
|
||||||
if(decoded != streamHeader.unpackedSize) return ErrorNumber.InvalidArgument;
|
if(decoded != streamHeader.unpackedSize) return ErrorNumber.InvalidArgument;
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Decompressed flux stream: {0} bytes -> {1} bytes",
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
streamHeader.packedSize, decoded);
|
"Decompressed flux stream: {0} bytes -> {1} bytes",
|
||||||
|
streamHeader.packedSize,
|
||||||
|
decoded);
|
||||||
|
|
||||||
// Decode variable-length pulses
|
// Decode variable-length pulses
|
||||||
uint numberOfPulses = streamHeader.numberOfPulses;
|
uint numberOfPulses = streamHeader.numberOfPulses;
|
||||||
|
|
||||||
uint[] pulses = DecodeVariableLengthPulses(unpackedData,
|
uint[] pulses = DecodeVariableLengthPulses(unpackedData,
|
||||||
streamHeader.unpackedSize,
|
streamHeader.unpackedSize,
|
||||||
ref numberOfPulses);
|
ref numberOfPulses);
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Decoded {0} flux pulses (expected {1})", pulses.Length, numberOfPulses);
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
|
"Decoded {0} flux pulses (expected {1})",
|
||||||
|
pulses.Length,
|
||||||
|
numberOfPulses);
|
||||||
|
|
||||||
if(pulses.Length != numberOfPulses) return ErrorNumber.InvalidArgument;
|
if(pulses.Length != numberOfPulses) return ErrorNumber.InvalidArgument;
|
||||||
|
|
||||||
@@ -353,6 +383,7 @@ public sealed partial class HxCStream
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
AaruLogging.Error(MODULE_NAME, "Unknown packet type: 0x{0:X8}", type);
|
AaruLogging.Error(MODULE_NAME, "Unknown packet type: 0x{0:X8}", type);
|
||||||
|
|
||||||
return ErrorNumber.InvalidArgument;
|
return ErrorNumber.InvalidArgument;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,20 +391,24 @@ public sealed partial class HxCStream
|
|||||||
fileOffset += chunkHeader.size;
|
fileOffset += chunkHeader.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Finished processing chunks. Total flux pulses: {0}, IO stream values: {1}",
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
fluxPulses.Count, ioStream.Count);
|
"Finished processing chunks. Total flux pulses: {0}, IO stream values: {1}",
|
||||||
|
fluxPulses.Count,
|
||||||
|
ioStream.Count);
|
||||||
|
|
||||||
// Extract write protect status from IO stream
|
// Extract write protect status from IO stream
|
||||||
// The write protect flag should be constant for a capture, so we only need to check the first value
|
// The write protect flag should be constant for a capture, so we only need to check the first value
|
||||||
if(ioStream.Count > 0 && !_mediaTags.ContainsKey(MediaTagType.Floppy_WriteProtection))
|
if(ioStream.Count > 0 && !_mediaTags.ContainsKey(MediaTagType.Floppy_WriteProtection))
|
||||||
{
|
{
|
||||||
IoStreamState firstState = DecodeIoStreamValue(ioStream[0]);
|
IoStreamState firstState = DecodeIoStreamValue(ioStream[0]);
|
||||||
bool writeProtected = firstState.WriteProtect;
|
bool writeProtected = firstState.WriteProtect;
|
||||||
|
|
||||||
// Store as boolean: 1 byte where 0 = false (not write protected), 1 = true (write protected)
|
// Store as boolean: 1 byte where 0 = false (not write protected), 1 = true (write protected)
|
||||||
_mediaTags[MediaTagType.Floppy_WriteProtection] = writeProtected ? [1] : [0];
|
_mediaTags[MediaTagType.Floppy_WriteProtection] = writeProtected ? [1] : [0];
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Write protect status from IO stream: {0}", writeProtected ? "write protected" : "not write protected");
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
|
"Write protect status from IO stream: {0}",
|
||||||
|
writeProtected ? "write protected" : "not write protected");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract index signals from IO stream
|
// Extract index signals from IO stream
|
||||||
@@ -382,26 +417,23 @@ public sealed partial class HxCStream
|
|||||||
if(ioStream.Count > 0)
|
if(ioStream.Count > 0)
|
||||||
{
|
{
|
||||||
IoStreamState previousState = DecodeIoStreamValue(ioStream[0]);
|
IoStreamState previousState = DecodeIoStreamValue(ioStream[0]);
|
||||||
bool oldIndex = previousState.IndexSignal;
|
bool oldIndex = previousState.IndexSignal;
|
||||||
bool startsAtIndex = previousState.IndexSignal;
|
bool startsAtIndex = previousState.IndexSignal;
|
||||||
if(startsAtIndex)
|
if(startsAtIndex) indexPositions.Add(0);
|
||||||
{
|
|
||||||
indexPositions.Add(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint totalTicks = 0;
|
uint totalTicks = 0;
|
||||||
int pulseIndex = 0;
|
var pulseIndex = 0;
|
||||||
|
|
||||||
for(int i = 0; i < ioStream.Count; i++)
|
for(var i = 0; i < ioStream.Count; i++)
|
||||||
{
|
{
|
||||||
IoStreamState currentState = DecodeIoStreamValue(ioStream[i]);
|
IoStreamState currentState = DecodeIoStreamValue(ioStream[i]);
|
||||||
bool currentIndex = currentState.IndexSignal;
|
bool currentIndex = currentState.IndexSignal;
|
||||||
|
|
||||||
if(currentIndex != oldIndex && currentIndex)
|
if(currentIndex != oldIndex && currentIndex)
|
||||||
{
|
{
|
||||||
// Index signal transition to high
|
// Index signal transition to high
|
||||||
// Map to flux stream position
|
// Map to flux stream position
|
||||||
uint targetTicks = (uint)(i * 16);
|
var targetTicks = (uint)(i * 16);
|
||||||
|
|
||||||
while(pulseIndex < fluxPulses.Count && totalTicks < targetTicks)
|
while(pulseIndex < fluxPulses.Count && totalTicks < targetTicks)
|
||||||
{
|
{
|
||||||
@@ -431,8 +463,13 @@ public sealed partial class HxCStream
|
|||||||
indexPositions = indexPositions.ToArray()
|
indexPositions = indexPositions.ToArray()
|
||||||
};
|
};
|
||||||
|
|
||||||
AaruLogging.Debug(MODULE_NAME, "Created track capture: head = {0}, track = {1}, resolution = {2} ns, fluxPulses = {3}, indexPositions = {4}",
|
AaruLogging.Debug(MODULE_NAME,
|
||||||
capture.head, capture.track, capture.resolution, capture.fluxPulses.Length, capture.indexPositions.Length);
|
"Created track capture: head = {0}, track = {1}, resolution = {2} ns, fluxPulses = {3}, indexPositions = {4}",
|
||||||
|
capture.head,
|
||||||
|
capture.track,
|
||||||
|
capture.resolution,
|
||||||
|
capture.fluxPulses.Length,
|
||||||
|
capture.indexPositions.Length);
|
||||||
|
|
||||||
_trackCaptures.Add(capture);
|
_trackCaptures.Add(capture);
|
||||||
|
|
||||||
@@ -526,7 +563,7 @@ public sealed partial class HxCStream
|
|||||||
out ulong indexResolution, out ulong dataResolution, out byte[] indexBuffer,
|
out ulong indexResolution, out ulong dataResolution, out byte[] indexBuffer,
|
||||||
out byte[] dataBuffer)
|
out byte[] dataBuffer)
|
||||||
{
|
{
|
||||||
indexBuffer = dataBuffer = null;
|
indexBuffer = dataBuffer = null;
|
||||||
indexResolution = dataResolution = 0;
|
indexResolution = dataResolution = 0;
|
||||||
|
|
||||||
// HxCStream doesn't support subtracks - only subTrack 0 is valid
|
// HxCStream doesn't support subtracks - only subTrack 0 is valid
|
||||||
@@ -535,8 +572,8 @@ public sealed partial class HxCStream
|
|||||||
// HxCStream has one file per track/head, which results in exactly one capture (captureIndex 0)
|
// HxCStream has one file per track/head, which results in exactly one capture (captureIndex 0)
|
||||||
if(captureIndex != 0) return ErrorNumber.OutOfRange;
|
if(captureIndex != 0) return ErrorNumber.OutOfRange;
|
||||||
|
|
||||||
ErrorNumber error = ReadFluxResolution(head, track, subTrack, captureIndex, out indexResolution,
|
ErrorNumber error =
|
||||||
out dataResolution);
|
ReadFluxResolution(head, track, subTrack, captureIndex, out indexResolution, out dataResolution);
|
||||||
|
|
||||||
if(error != ErrorNumber.NoError) return error;
|
if(error != ErrorNumber.NoError) return error;
|
||||||
|
|
||||||
@@ -565,15 +602,14 @@ public sealed partial class HxCStream
|
|||||||
|
|
||||||
if(capture == null) return ErrorNumber.OutOfRange;
|
if(capture == null) return ErrorNumber.OutOfRange;
|
||||||
|
|
||||||
var tmpBuffer = new List<byte>();
|
var tmpBuffer = new List<byte>();
|
||||||
uint previousTicks = 0;
|
uint previousTicks = 0;
|
||||||
|
|
||||||
foreach(uint indexPos in capture.indexPositions)
|
foreach(uint indexPos in capture.indexPositions)
|
||||||
{
|
{
|
||||||
// Convert index position to ticks
|
// Convert index position to ticks
|
||||||
uint ticks = 0;
|
uint ticks = 0;
|
||||||
for(uint i = 0; i < indexPos && i < capture.fluxPulses.Length; i++)
|
for(uint i = 0; i < indexPos && i < capture.fluxPulses.Length; i++) ticks += capture.fluxPulses[i];
|
||||||
ticks += capture.fluxPulses[i];
|
|
||||||
|
|
||||||
uint deltaTicks = ticks - previousTicks;
|
uint deltaTicks = ticks - previousTicks;
|
||||||
tmpBuffer.AddRange(UInt32ToFluxRepresentation(deltaTicks));
|
tmpBuffer.AddRange(UInt32ToFluxRepresentation(deltaTicks));
|
||||||
@@ -586,8 +622,7 @@ public sealed partial class HxCStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ErrorNumber
|
public ErrorNumber ReadFluxDataCapture(uint head, ushort track, byte subTrack, uint captureIndex, out byte[] buffer)
|
||||||
ReadFluxDataCapture(uint head, ushort track, byte subTrack, uint captureIndex, out byte[] buffer)
|
|
||||||
{
|
{
|
||||||
buffer = null;
|
buffer = null;
|
||||||
|
|
||||||
@@ -638,8 +673,12 @@ public sealed partial class HxCStream
|
|||||||
{
|
{
|
||||||
// Group captures by head/track to assign capture indices
|
// Group captures by head/track to assign capture indices
|
||||||
// Note: HxCStream doesn't support subtracks, so subTrack is always 0
|
// Note: HxCStream doesn't support subtracks, so subTrack is always 0
|
||||||
var grouped = _trackCaptures.GroupBy(c => new { c.head, c.track })
|
var grouped = _trackCaptures.GroupBy(c => new
|
||||||
.ToList();
|
{
|
||||||
|
c.head,
|
||||||
|
c.track
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
foreach(var group in grouped)
|
foreach(var group in grouped)
|
||||||
{
|
{
|
||||||
@@ -678,6 +717,7 @@ public sealed partial class HxCStream
|
|||||||
{
|
{
|
||||||
buffer = new byte[tagData.Length];
|
buffer = new byte[tagData.Length];
|
||||||
Array.Copy(tagData, buffer, tagData.Length);
|
Array.Copy(tagData, buffer, tagData.Length);
|
||||||
|
|
||||||
return ErrorNumber.NoError;
|
return ErrorNumber.NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,8 +727,9 @@ public sealed partial class HxCStream
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ErrorNumber ReadSector(ulong sectorAddress, bool negative, out byte[] buffer, out SectorStatus sectorStatus)
|
public ErrorNumber ReadSector(ulong sectorAddress, bool negative, out byte[] buffer, out SectorStatus sectorStatus)
|
||||||
{
|
{
|
||||||
buffer = null;
|
buffer = null;
|
||||||
sectorStatus = SectorStatus.NotDumped;
|
sectorStatus = SectorStatus.NotDumped;
|
||||||
|
|
||||||
return ErrorNumber.NotImplemented;
|
return ErrorNumber.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,8 +737,9 @@ public sealed partial class HxCStream
|
|||||||
public ErrorNumber ReadSectorLong(ulong sectorAddress, bool negative, out byte[] buffer,
|
public ErrorNumber ReadSectorLong(ulong sectorAddress, bool negative, out byte[] buffer,
|
||||||
out SectorStatus sectorStatus)
|
out SectorStatus sectorStatus)
|
||||||
{
|
{
|
||||||
buffer = null;
|
buffer = null;
|
||||||
sectorStatus = SectorStatus.NotDumped;
|
sectorStatus = SectorStatus.NotDumped;
|
||||||
|
|
||||||
return ErrorNumber.NotImplemented;
|
return ErrorNumber.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,8 +747,9 @@ public sealed partial class HxCStream
|
|||||||
public ErrorNumber ReadSectors(ulong sectorAddress, bool negative, uint length, out byte[] buffer,
|
public ErrorNumber ReadSectors(ulong sectorAddress, bool negative, uint length, out byte[] buffer,
|
||||||
out SectorStatus[] sectorStatus)
|
out SectorStatus[] sectorStatus)
|
||||||
{
|
{
|
||||||
buffer = null;
|
buffer = null;
|
||||||
sectorStatus = null;
|
sectorStatus = null;
|
||||||
|
|
||||||
return ErrorNumber.NotImplemented;
|
return ErrorNumber.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,8 +757,9 @@ public sealed partial class HxCStream
|
|||||||
public ErrorNumber ReadSectorsLong(ulong sectorAddress, bool negative, uint length, out byte[] buffer,
|
public ErrorNumber ReadSectorsLong(ulong sectorAddress, bool negative, uint length, out byte[] buffer,
|
||||||
out SectorStatus[] sectorStatus)
|
out SectorStatus[] sectorStatus)
|
||||||
{
|
{
|
||||||
buffer = null;
|
buffer = null;
|
||||||
sectorStatus = null;
|
sectorStatus = null;
|
||||||
|
|
||||||
return ErrorNumber.NotImplemented;
|
return ErrorNumber.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,6 +768,7 @@ public sealed partial class HxCStream
|
|||||||
out byte[] buffer)
|
out byte[] buffer)
|
||||||
{
|
{
|
||||||
buffer = null;
|
buffer = null;
|
||||||
|
|
||||||
return ErrorNumber.NotImplemented;
|
return ErrorNumber.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,8 +776,9 @@ public sealed partial class HxCStream
|
|||||||
public ErrorNumber ReadSectorTag(ulong sectorAddress, bool negative, SectorTagType tag, out byte[] buffer)
|
public ErrorNumber ReadSectorTag(ulong sectorAddress, bool negative, SectorTagType tag, out byte[] buffer)
|
||||||
{
|
{
|
||||||
buffer = null;
|
buffer = null;
|
||||||
|
|
||||||
return ErrorNumber.NotImplemented;
|
return ErrorNumber.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -1524,7 +1524,7 @@
|
|||||||
<value>[fuchsiaLOCATE[/] [slateblue1]funciona.[/]</value>
|
<value>[fuchsiaLOCATE[/] [slateblue1]funciona.[/]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Locking_drive" xml:space="preserve">
|
<data name="Locking_drive" xml:space="preserve">
|
||||||
<value>Bloqueando la unidad.</value>
|
<value>[slateblue1]Bloqueando la unidad.[/]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Log_section_separator" xml:space="preserve">
|
<data name="Log_section_separator" xml:space="preserve">
|
||||||
<value>####################################################################</value>
|
<value>####################################################################</value>
|
||||||
|
|||||||
@@ -1734,7 +1734,7 @@
|
|||||||
<value>[slateblue1]Getting video partition size[/]</value>
|
<value>[slateblue1]Getting video partition size[/]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Locking_drive" xml:space="preserve">
|
<data name="Locking_drive" xml:space="preserve">
|
||||||
<value>Locking drive.</value>
|
<value>[slateblue1]Locking drive.[/]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Cannot_lock_drive_not_continuing" xml:space="preserve">
|
<data name="Cannot_lock_drive_not_continuing" xml:space="preserve">
|
||||||
<value>[red]Cannot lock drive, not continuing.[/]</value>
|
<value>[red]Cannot lock drive, not continuing.[/]</value>
|
||||||
@@ -1779,7 +1779,7 @@
|
|||||||
<value>[red]Cannot decode PFI.[/]</value>
|
<value>[red]Cannot decode PFI.[/]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WxRipper_PFI_Data_Area_Start_PSN_0_sectors" xml:space="preserve">
|
<data name="WxRipper_PFI_Data_Area_Start_PSN_0_sectors" xml:space="preserve">
|
||||||
<value>[slateblue1][italic]WxRipper[/] PFI's Data Area Start PSN: [lime]{0}[/lime] sectors[/]</value>
|
<value>[slateblue1][italic]WxRipper[/] PFI's Data Area Start PSN: [lime]{0}[/] sectors[/]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WxRipper_PFI_Layer_0_End_PSN_0_sectors" xml:space="preserve">
|
<data name="WxRipper_PFI_Layer_0_End_PSN_0_sectors" xml:space="preserve">
|
||||||
<value>[slateblue1][italic]WxRipper[/] PFI's Layer [teal]0[/] End PSN: [lime]{0}[/] sectors[/]</value>
|
<value>[slateblue1][italic]WxRipper[/] PFI's Layer [teal]0[/] End PSN: [lime]{0}[/] sectors[/]</value>
|
||||||
|
|||||||
Reference in New Issue
Block a user