2018-07-23 23:25:43 +01:00
|
|
|
|
// /***************************************************************************
|
2020-02-27 12:31:25 +00:00
|
|
|
|
// Aaru Data Preservation Suite
|
2016-07-28 18:13:49 +01:00
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
//
|
2018-07-23 23:25:43 +01:00
|
|
|
|
// Filename : Read.cs
|
2016-07-28 18:13:49 +01:00
|
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
|
|
|
|
//
|
2017-12-19 03:50:57 +00:00
|
|
|
|
// Component : Disk image plugins.
|
2016-07-28 18:13:49 +01:00
|
|
|
|
//
|
|
|
|
|
|
// --[ Description ] ----------------------------------------------------------
|
|
|
|
|
|
//
|
2018-07-23 23:25:43 +01:00
|
|
|
|
// Reads Sydex TeleDisk disk images.
|
2016-07-28 18:13:49 +01:00
|
|
|
|
//
|
|
|
|
|
|
// --[ License ] --------------------------------------------------------------
|
|
|
|
|
|
//
|
|
|
|
|
|
// This library is free software; you can redistribute it and/or modify
|
|
|
|
|
|
// it under the terms of the GNU Lesser General Public License as
|
|
|
|
|
|
// published by the Free Software Foundation; either version 2.1 of the
|
|
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
|
//
|
|
|
|
|
|
// This library is distributed in the hope that it will be useful, but
|
|
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
|
|
//
|
|
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
|
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
//
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2020-12-31 23:08:23 +00:00
|
|
|
|
// Copyright © 2011-2021 Natalia Portillo
|
2016-07-28 18:13:49 +01:00
|
|
|
|
// ****************************************************************************/
|
2014-04-19 21:21:08 +01:00
|
|
|
|
|
|
|
|
|
|
using System;
|
2017-12-19 19:33:46 +00:00
|
|
|
|
using System.IO;
|
2017-12-21 14:30:38 +00:00
|
|
|
|
using System.Text;
|
2020-02-27 00:33:26 +00:00
|
|
|
|
using Aaru.CommonTypes.Enums;
|
|
|
|
|
|
using Aaru.CommonTypes.Interfaces;
|
|
|
|
|
|
using Aaru.Compression;
|
|
|
|
|
|
using Aaru.Console;
|
2015-10-18 22:04:03 +01:00
|
|
|
|
|
2020-02-27 00:33:26 +00:00
|
|
|
|
namespace Aaru.DiscImages
|
2014-04-19 21:21:08 +01:00
|
|
|
|
{
|
2020-07-22 13:20:25 +01:00
|
|
|
|
public sealed partial class TeleDisk
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2021-08-17 13:56:05 +01:00
|
|
|
|
/// <inheritdoc />
|
2021-09-16 19:10:39 +01:00
|
|
|
|
public ErrorNumber Open(IFilter imageFilter)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2020-11-11 04:19:18 +00:00
|
|
|
|
_header = new Header();
|
2018-06-22 08:08:38 +01:00
|
|
|
|
byte[] headerBytes = new byte[12];
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_inStream = imageFilter.GetDataForkStream();
|
2020-02-29 18:03:35 +00:00
|
|
|
|
var stream = new MemoryStream();
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_inStream.Seek(0, SeekOrigin.Begin);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_inStream.Read(headerBytes, 0, 12);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
stream.Write(headerBytes, 0, 12);
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_header.Signature = BitConverter.ToUInt16(headerBytes, 0);
|
2017-12-20 17:15:26 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_header.Signature != TD_MAGIC &&
|
|
|
|
|
|
_header.Signature != TD_ADV_COMP_MAGIC)
|
2021-09-16 19:10:39 +01:00
|
|
|
|
return ErrorNumber.InvalidArgument;
|
2017-12-20 17:15:26 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_header.Sequence = headerBytes[2];
|
|
|
|
|
|
_header.DiskSet = headerBytes[3];
|
|
|
|
|
|
_header.Version = headerBytes[4];
|
|
|
|
|
|
_header.DataRate = headerBytes[5];
|
|
|
|
|
|
_header.DriveType = headerBytes[6];
|
|
|
|
|
|
_header.Stepping = headerBytes[7];
|
|
|
|
|
|
_header.DosAllocation = headerBytes[8];
|
|
|
|
|
|
_header.Sides = headerBytes[9];
|
|
|
|
|
|
_header.Crc = BitConverter.ToUInt16(headerBytes, 10);
|
2017-12-20 17:15:26 +00:00
|
|
|
|
|
2021-09-15 11:25:26 +01:00
|
|
|
|
_imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.Filename);
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.Version = $"{(_header.Version & 0xF0) >> 4}.{_header.Version & 0x0F}";
|
|
|
|
|
|
_imageInfo.Application = _imageInfo.Version;
|
2017-12-20 17:15:26 +00:00
|
|
|
|
|
|
|
|
|
|
byte[] headerBytesForCrc = new byte[10];
|
|
|
|
|
|
Array.Copy(headerBytes, headerBytesForCrc, 10);
|
|
|
|
|
|
ushort calculatedHeaderCrc = TeleDiskCrc(0x0000, headerBytesForCrc);
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.signature = 0x{0:X4}", _header.Signature);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.sequence = 0x{0:X2}", _header.Sequence);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.diskSet = 0x{0:X2}", _header.DiskSet);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.version = 0x{0:X2}", _header.Version);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.dataRate = 0x{0:X2}", _header.DataRate);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.driveType = 0x{0:X2}", _header.DriveType);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.stepping = 0x{0:X2}", _header.Stepping);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.dosAllocation = 0x{0:X2}", _header.DosAllocation);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.sides = 0x{0:X2}", _header.Sides);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "header.crc = 0x{0:X4}", _header.Crc);
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "calculated header crc = 0x{0:X4}", calculatedHeaderCrc);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
// We need more checks as the magic is too simply.
|
|
|
|
|
|
// This may deny legal images
|
|
|
|
|
|
|
|
|
|
|
|
// That would be much of a coincidence
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_header.Crc != calculatedHeaderCrc)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_aDiskCrcHasFailed = true;
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "Calculated CRC does not coincide with stored one.");
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_header.Sequence != 0x00)
|
2021-09-16 19:10:39 +01:00
|
|
|
|
return ErrorNumber.InvalidArgument;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2021-08-17 16:27:42 +01:00
|
|
|
|
if(_header.DataRate != DATA_RATE_250_KBPS &&
|
|
|
|
|
|
_header.DataRate != DATA_RATE_300_KBPS &&
|
|
|
|
|
|
_header.DataRate != DATA_RATE_500_KBPS)
|
2021-09-16 19:10:39 +01:00
|
|
|
|
return ErrorNumber.NotSupported;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_header.DriveType != DRIVE_TYPE_35_DD &&
|
|
|
|
|
|
_header.DriveType != DRIVE_TYPE_35_ED &&
|
|
|
|
|
|
_header.DriveType != DRIVE_TYPE_35_HD &&
|
|
|
|
|
|
_header.DriveType != DRIVE_TYPE_525_DD &&
|
|
|
|
|
|
_header.DriveType != DRIVE_TYPE_525_HD &&
|
|
|
|
|
|
_header.DriveType != DRIVE_TYPE_525_HD_DD_DISK &&
|
|
|
|
|
|
_header.DriveType != DRIVE_TYPE_8_INCH)
|
2021-09-16 19:10:39 +01:00
|
|
|
|
return ErrorNumber.NotSupported;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_header.Signature == TD_ADV_COMP_MAGIC)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
int rd;
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_inStream.Seek(12, SeekOrigin.Begin);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
stream.Seek(12, SeekOrigin.Begin);
|
2020-07-20 21:11:32 +01:00
|
|
|
|
var lzh = new TeleDiskLzh(_inStream);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2018-01-28 20:29:46 +00:00
|
|
|
|
do
|
|
|
|
|
|
if((rd = lzh.Decode(out byte[] obuf, BUFSZ)) > 0)
|
|
|
|
|
|
stream.Write(obuf, 0, rd);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
while(rd == BUFSZ);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// Not using Stream.CopyTo() because it's failing with LZIP
|
2020-07-20 21:11:32 +01:00
|
|
|
|
byte[] copybuf = new byte[_inStream.Length];
|
|
|
|
|
|
_inStream.Seek(0, SeekOrigin.Begin);
|
|
|
|
|
|
_inStream.Read(copybuf, 0, copybuf.Length);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
|
|
|
|
stream.Write(copybuf, 0, copybuf.Length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
stream.Seek(12, SeekOrigin.Begin);
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.CreationTime = DateTime.MinValue;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if((_header.Stepping & COMMENT_BLOCK_PRESENT) == COMMENT_BLOCK_PRESENT)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2020-11-11 04:19:18 +00:00
|
|
|
|
_commentHeader = new CommentBlockHeader();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
byte[] commentHeaderBytes = new byte[10];
|
|
|
|
|
|
|
|
|
|
|
|
stream.Read(commentHeaderBytes, 0, 10);
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_commentHeader.Crc = BitConverter.ToUInt16(commentHeaderBytes, 0);
|
|
|
|
|
|
_commentHeader.Length = BitConverter.ToUInt16(commentHeaderBytes, 2);
|
|
|
|
|
|
_commentHeader.Year = commentHeaderBytes[4];
|
|
|
|
|
|
_commentHeader.Month = commentHeaderBytes[5];
|
|
|
|
|
|
_commentHeader.Day = commentHeaderBytes[6];
|
|
|
|
|
|
_commentHeader.Hour = commentHeaderBytes[7];
|
|
|
|
|
|
_commentHeader.Minute = commentHeaderBytes[8];
|
|
|
|
|
|
_commentHeader.Second = commentHeaderBytes[9];
|
|
|
|
|
|
|
|
|
|
|
|
_commentBlock = new byte[_commentHeader.Length];
|
|
|
|
|
|
stream.Read(_commentBlock, 0, _commentHeader.Length);
|
|
|
|
|
|
|
|
|
|
|
|
byte[] commentBlockForCrc = new byte[_commentHeader.Length + 8];
|
2017-12-20 17:15:26 +00:00
|
|
|
|
Array.Copy(commentHeaderBytes, 2, commentBlockForCrc, 0, 8);
|
2020-07-20 21:11:32 +01:00
|
|
|
|
Array.Copy(_commentBlock, 0, commentBlockForCrc, 8, _commentHeader.Length);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
ushort cmtcrc = TeleDiskCrc(0, commentBlockForCrc);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "Comment header");
|
2020-07-20 21:11:32 +01:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.crc = 0x{0:X4}", _commentHeader.Crc);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tCalculated CRC = 0x{0:X4}", cmtcrc);
|
|
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.length = {0} bytes",
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_commentHeader.Length);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.year = {0}", _commentHeader.Year);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.month = {0}", _commentHeader.Month);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.day = {0}", _commentHeader.Day);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.hour = {0}", _commentHeader.Hour);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.minute = {0}", _commentHeader.Minute);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.second = {0}", _commentHeader.Second);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_aDiskCrcHasFailed |= cmtcrc != _commentHeader.Crc;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
for(int i = 0; i < _commentBlock.Length; i++)
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2017-12-24 00:12:31 +00:00
|
|
|
|
// Replace NULLs, used by TeleDisk as newline markers, with UNIX newline marker
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_commentBlock[i] == 0x00)
|
|
|
|
|
|
_commentBlock[i] = 0x0A;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.Comments = Encoding.ASCII.GetString(_commentBlock);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "Comment");
|
2020-07-20 21:11:32 +01:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "{0}", _imageInfo.Comments);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.CreationTime = new DateTime(_commentHeader.Year + 1900, _commentHeader.Month + 1,
|
|
|
|
|
|
_commentHeader.Day, _commentHeader.Hour, _commentHeader.Minute,
|
|
|
|
|
|
_commentHeader.Second, DateTimeKind.Unspecified);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_imageInfo.CreationTime == DateTime.MinValue)
|
2021-09-15 11:25:26 +01:00
|
|
|
|
_imageInfo.CreationTime = imageFilter.CreationTime;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2021-09-15 11:25:26 +01:00
|
|
|
|
_imageInfo.LastModificationTime = imageFilter.LastWriteTime;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "Image created on {0}", _imageInfo.CreationTime);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "Image modified on {0}", _imageInfo.LastModificationTime);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "Parsing image");
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_totalDiskSize = 0;
|
|
|
|
|
|
_imageInfo.ImageSize = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2018-06-22 08:08:38 +01:00
|
|
|
|
int totalCylinders = -1;
|
|
|
|
|
|
int totalHeads = -1;
|
|
|
|
|
|
int maxSector = -1;
|
|
|
|
|
|
int totalSectors = 0;
|
|
|
|
|
|
long currentPos = stream.Position;
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.SectorSize = uint.MaxValue;
|
|
|
|
|
|
_imageInfo.SectorsPerTrack = uint.MaxValue;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
// Count cylinders
|
|
|
|
|
|
while(true)
|
|
|
|
|
|
{
|
2020-11-11 04:19:18 +00:00
|
|
|
|
var teleDiskTrack = new TrackHeader
|
2017-12-22 06:55:04 +00:00
|
|
|
|
{
|
2020-07-20 04:34:16 +01:00
|
|
|
|
Sectors = (byte)stream.ReadByte(),
|
|
|
|
|
|
Cylinder = (byte)stream.ReadByte(),
|
|
|
|
|
|
Head = (byte)stream.ReadByte(),
|
|
|
|
|
|
Crc = (byte)stream.ReadByte()
|
2017-12-22 06:55:04 +00:00
|
|
|
|
};
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
|
if(teleDiskTrack.Cylinder > totalCylinders)
|
|
|
|
|
|
totalCylinders = teleDiskTrack.Cylinder;
|
|
|
|
|
|
|
|
|
|
|
|
if(teleDiskTrack.Head > totalHeads)
|
|
|
|
|
|
totalHeads = teleDiskTrack.Head;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
if(teleDiskTrack.Sectors == 0xFF) // End of disk image
|
2017-12-19 20:33:03 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
for(byte processedSectors = 0; processedSectors < teleDiskTrack.Sectors; processedSectors++)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2020-11-11 04:19:18 +00:00
|
|
|
|
var teleDiskSector = new SectorHeader();
|
|
|
|
|
|
var teleDiskData = new DataHeader();
|
2020-02-29 18:03:35 +00:00
|
|
|
|
byte[] dataSizeBytes = new byte[2];
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskSector.Cylinder = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Head = (byte)stream.ReadByte();
|
2017-12-20 17:15:26 +00:00
|
|
|
|
teleDiskSector.SectorNumber = (byte)stream.ReadByte();
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskSector.SectorSize = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Flags = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Crc = (byte)stream.ReadByte();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
|
if(teleDiskSector.SectorNumber > maxSector)
|
|
|
|
|
|
maxSector = teleDiskSector.SectorNumber;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
if((teleDiskSector.Flags & FLAGS_SECTOR_DATALESS) != FLAGS_SECTOR_DATALESS &&
|
2018-01-28 20:29:46 +00:00
|
|
|
|
(teleDiskSector.Flags & FLAGS_SECTOR_SKIPPED) != FLAGS_SECTOR_SKIPPED)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
stream.Read(dataSizeBytes, 0, 2);
|
2017-12-20 17:15:26 +00:00
|
|
|
|
teleDiskData.DataSize = BitConverter.ToUInt16(dataSizeBytes, 0);
|
|
|
|
|
|
teleDiskData.DataSize--; // Sydex decided to including dataEncoding byte as part of it
|
|
|
|
|
|
teleDiskData.DataEncoding = (byte)stream.ReadByte();
|
2018-06-22 08:08:38 +01:00
|
|
|
|
byte[] data = new byte[teleDiskData.DataSize];
|
2017-12-20 17:15:26 +00:00
|
|
|
|
stream.Read(data, 0, teleDiskData.DataSize);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(128 << teleDiskSector.SectorSize < _imageInfo.SectorSize)
|
|
|
|
|
|
_imageInfo.SectorSize = (uint)(128 << teleDiskSector.SectorSize);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
totalSectors++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
totalCylinders++;
|
|
|
|
|
|
totalHeads++;
|
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
|
if(totalCylinders <= 0 ||
|
|
|
|
|
|
totalHeads <= 0)
|
2021-09-21 04:55:28 +01:00
|
|
|
|
{
|
|
|
|
|
|
AaruConsole.ErrorWriteLine("No cylinders or heads found");
|
|
|
|
|
|
|
|
|
|
|
|
return ErrorNumber.InvalidArgument;
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
bool hasLeadOutOnHead0 = false;
|
|
|
|
|
|
bool hasLeadOutOnHead1 = false;
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.Cylinders = (ushort)totalCylinders;
|
|
|
|
|
|
_imageInfo.Heads = (byte)totalHeads;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
// Count sectors per track
|
|
|
|
|
|
stream.Seek(currentPos, SeekOrigin.Begin);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
|
while(true)
|
|
|
|
|
|
{
|
2020-11-11 04:19:18 +00:00
|
|
|
|
var teleDiskTrack = new TrackHeader
|
2017-12-22 06:55:04 +00:00
|
|
|
|
{
|
2020-07-20 04:34:16 +01:00
|
|
|
|
Sectors = (byte)stream.ReadByte(),
|
|
|
|
|
|
Cylinder = (byte)stream.ReadByte(),
|
|
|
|
|
|
Head = (byte)stream.ReadByte(),
|
|
|
|
|
|
Crc = (byte)stream.ReadByte()
|
2017-12-22 06:55:04 +00:00
|
|
|
|
};
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
if(teleDiskTrack.Sectors == 0xFF) // End of disk image
|
2017-12-19 20:33:03 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(teleDiskTrack.Sectors < _imageInfo.SectorsPerTrack)
|
2017-12-20 17:15:26 +00:00
|
|
|
|
if(teleDiskTrack.Cylinder + 1 == totalCylinders)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
|
hasLeadOutOnHead0 |= teleDiskTrack.Head == 0;
|
|
|
|
|
|
hasLeadOutOnHead1 |= teleDiskTrack.Head == 1;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_imageInfo.Cylinders == totalCylinders)
|
|
|
|
|
|
_imageInfo.Cylinders--;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
2018-01-28 20:29:46 +00:00
|
|
|
|
else
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.SectorsPerTrack = teleDiskTrack.Sectors;
|
2018-01-28 20:29:46 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
for(byte processedSectors = 0; processedSectors < teleDiskTrack.Sectors; processedSectors++)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2020-11-11 04:19:18 +00:00
|
|
|
|
var teleDiskSector = new SectorHeader();
|
|
|
|
|
|
var teleDiskData = new DataHeader();
|
2020-02-29 18:03:35 +00:00
|
|
|
|
byte[] dataSizeBytes = new byte[2];
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskSector.Cylinder = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Head = (byte)stream.ReadByte();
|
2017-12-20 17:15:26 +00:00
|
|
|
|
teleDiskSector.SectorNumber = (byte)stream.ReadByte();
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskSector.SectorSize = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Flags = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Crc = (byte)stream.ReadByte();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-21 06:06:19 +00:00
|
|
|
|
if((teleDiskSector.Flags & FLAGS_SECTOR_DATALESS) == FLAGS_SECTOR_DATALESS ||
|
2020-02-29 18:03:35 +00:00
|
|
|
|
(teleDiskSector.Flags & FLAGS_SECTOR_SKIPPED) == FLAGS_SECTOR_SKIPPED)
|
|
|
|
|
|
continue;
|
2017-12-21 06:06:19 +00:00
|
|
|
|
|
|
|
|
|
|
stream.Read(dataSizeBytes, 0, 2);
|
|
|
|
|
|
teleDiskData.DataSize = BitConverter.ToUInt16(dataSizeBytes, 0);
|
|
|
|
|
|
teleDiskData.DataSize--; // Sydex decided to including dataEncoding byte as part of it
|
|
|
|
|
|
teleDiskData.DataEncoding = (byte)stream.ReadByte();
|
2018-06-22 08:08:38 +01:00
|
|
|
|
byte[] data = new byte[teleDiskData.DataSize];
|
2017-12-21 06:06:19 +00:00
|
|
|
|
stream.Read(data, 0, teleDiskData.DataSize);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_sectorsData = new byte[totalCylinders][][][];
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
|
// Total sectors per track
|
|
|
|
|
|
uint[][] spts = new uint[totalCylinders][];
|
|
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
"Found {0} cylinders and {1} heads with a maximum sector number of {2}",
|
|
|
|
|
|
totalCylinders, totalHeads, maxSector);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
// Create heads
|
|
|
|
|
|
for(int i = 0; i < totalCylinders; i++)
|
|
|
|
|
|
{
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_sectorsData[i] = new byte[totalHeads][][];
|
|
|
|
|
|
spts[i] = new uint[totalHeads];
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
|
for(int j = 0; j < totalHeads; j++)
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_sectorsData[i][j] = new byte[maxSector + 1][];
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Decode the image
|
|
|
|
|
|
stream.Seek(currentPos, SeekOrigin.Begin);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
|
while(true)
|
|
|
|
|
|
{
|
2020-11-11 04:19:18 +00:00
|
|
|
|
var teleDiskTrack = new TrackHeader();
|
2020-02-29 18:03:35 +00:00
|
|
|
|
byte[] tdTrackForCrc = new byte[3];
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskTrack.Sectors = (byte)stream.ReadByte();
|
2017-12-20 17:15:26 +00:00
|
|
|
|
teleDiskTrack.Cylinder = (byte)stream.ReadByte();
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskTrack.Head = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskTrack.Crc = (byte)stream.ReadByte();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
tdTrackForCrc[0] = teleDiskTrack.Sectors;
|
|
|
|
|
|
tdTrackForCrc[1] = teleDiskTrack.Cylinder;
|
|
|
|
|
|
tdTrackForCrc[2] = teleDiskTrack.Head;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2018-01-28 20:29:46 +00:00
|
|
|
|
byte tdTrackCalculatedCrc = (byte)(TeleDiskCrc(0, tdTrackForCrc) & 0xFF);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "Track follows");
|
2020-02-29 18:03:35 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tTrack cylinder: {0}\t", teleDiskTrack.Cylinder);
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tTrack head: {0}\t", teleDiskTrack.Head);
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tSectors in track: {0}\t", teleDiskTrack.Sectors);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tTrack header CRC: 0x{0:X2} (calculated 0x{1:X2})\t",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
teleDiskTrack.Crc, tdTrackCalculatedCrc);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_aDiskCrcHasFailed |= tdTrackCalculatedCrc != teleDiskTrack.Crc;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
if(teleDiskTrack.Sectors == 0xFF) // End of disk image
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "End of disk image arrived");
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "Total of {0} data sectors, for {1} bytes",
|
2020-07-20 21:11:32 +01:00
|
|
|
|
totalSectors, _totalDiskSize);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
for(byte processedSectors = 0; processedSectors < teleDiskTrack.Sectors; processedSectors++)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2020-11-11 04:19:18 +00:00
|
|
|
|
var teleDiskSector = new SectorHeader();
|
|
|
|
|
|
var teleDiskData = new DataHeader();
|
2020-02-29 18:03:35 +00:00
|
|
|
|
byte[] dataSizeBytes = new byte[2];
|
|
|
|
|
|
byte[] decodedData;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskSector.Cylinder = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Head = (byte)stream.ReadByte();
|
2017-12-20 17:15:26 +00:00
|
|
|
|
teleDiskSector.SectorNumber = (byte)stream.ReadByte();
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskSector.SectorSize = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Flags = (byte)stream.ReadByte();
|
|
|
|
|
|
teleDiskSector.Crc = (byte)stream.ReadByte();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\tSector follows");
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark cylinder: {0}",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
teleDiskSector.Cylinder);
|
|
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark head: {0}", teleDiskSector.Head);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark sector number: {0}",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
teleDiskSector.SectorNumber);
|
|
|
|
|
|
|
|
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tSector size: {0}", teleDiskSector.SectorSize);
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tSector flags: 0x{0:X2}", teleDiskSector.Flags);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tSector CRC (plus headers): 0x{0:X2}",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
teleDiskSector.Crc);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
uint lba = (uint)((teleDiskSector.Cylinder * _header.Sides * _imageInfo.SectorsPerTrack) +
|
2020-11-11 04:19:18 +00:00
|
|
|
|
(teleDiskSector.Head * _imageInfo.SectorsPerTrack) +
|
2018-06-22 08:08:38 +01:00
|
|
|
|
(teleDiskSector.SectorNumber - 1));
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
if((teleDiskSector.Flags & FLAGS_SECTOR_DATALESS) != FLAGS_SECTOR_DATALESS &&
|
2018-01-28 20:29:46 +00:00
|
|
|
|
(teleDiskSector.Flags & FLAGS_SECTOR_SKIPPED) != FLAGS_SECTOR_SKIPPED)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
stream.Read(dataSizeBytes, 0, 2);
|
2017-12-20 17:15:26 +00:00
|
|
|
|
teleDiskData.DataSize = BitConverter.ToUInt16(dataSizeBytes, 0);
|
|
|
|
|
|
teleDiskData.DataSize--; // Sydex decided to including dataEncoding byte as part of it
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.ImageSize += teleDiskData.DataSize;
|
2018-01-28 20:29:46 +00:00
|
|
|
|
teleDiskData.DataEncoding = (byte)stream.ReadByte();
|
2018-06-22 08:08:38 +01:00
|
|
|
|
byte[] data = new byte[teleDiskData.DataSize];
|
2017-12-20 17:15:26 +00:00
|
|
|
|
stream.Read(data, 0, teleDiskData.DataSize);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tData size (in-image): {0}",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
teleDiskData.DataSize);
|
|
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tData encoding: 0x{0:X2}",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
teleDiskData.DataEncoding);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2021-09-21 04:55:28 +01:00
|
|
|
|
ErrorNumber errno = DecodeTeleDiskData(teleDiskSector.SectorSize, teleDiskData.DataEncoding,
|
|
|
|
|
|
data, out decodedData);
|
|
|
|
|
|
|
|
|
|
|
|
if(errno != ErrorNumber.NoError)
|
|
|
|
|
|
return errno;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
byte tdSectorCalculatedCrc = (byte)(TeleDiskCrc(0, decodedData) & 0xFF);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
|
if(tdSectorCalculatedCrc != teleDiskSector.Crc)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
"Sector {0}:{3}:{4} calculated CRC 0x{1:X2} differs from stored CRC 0x{2:X2}",
|
|
|
|
|
|
teleDiskTrack.Cylinder, tdSectorCalculatedCrc,
|
|
|
|
|
|
teleDiskSector.Crc, teleDiskTrack.Cylinder,
|
|
|
|
|
|
teleDiskSector.SectorNumber);
|
|
|
|
|
|
|
2017-12-24 00:12:31 +00:00
|
|
|
|
if((teleDiskSector.Flags & FLAGS_SECTOR_NO_ID) != FLAGS_SECTOR_NO_ID)
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_sectorsWhereCrcHasFailed.Add(lba);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-02-29 18:03:35 +00:00
|
|
|
|
else
|
|
|
|
|
|
decodedData = new byte[128 << teleDiskSector.SectorSize];
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tLBA: {0}", lba);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
|
if((teleDiskSector.Flags & FLAGS_SECTOR_NO_ID) == FLAGS_SECTOR_NO_ID)
|
|
|
|
|
|
continue;
|
2017-12-21 06:06:19 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(_sectorsData[teleDiskTrack.Cylinder][teleDiskTrack.Head][teleDiskSector.SectorNumber] != null)
|
2020-02-27 23:48:41 +00:00
|
|
|
|
AaruConsole.DebugWriteLine("TeleDisk plugin",
|
2020-02-29 18:03:35 +00:00
|
|
|
|
(teleDiskSector.Flags & FLAGS_SECTOR_DUPLICATE) ==
|
|
|
|
|
|
FLAGS_SECTOR_DUPLICATE
|
|
|
|
|
|
? "\t\tSector {0} on cylinder {1} head {2} is duplicate, and marked so"
|
|
|
|
|
|
: "\t\tSector {0} on cylinder {1} head {2} is duplicate, but is not marked so",
|
|
|
|
|
|
teleDiskSector.SectorNumber, teleDiskSector.Cylinder,
|
|
|
|
|
|
teleDiskSector.Head);
|
2017-12-21 06:06:19 +00:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_sectorsData[teleDiskTrack.Cylinder][teleDiskTrack.Head][teleDiskSector.SectorNumber] =
|
2017-12-24 00:12:31 +00:00
|
|
|
|
decodedData;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_totalDiskSize += (uint)decodedData.Length;
|
2017-12-21 06:06:19 +00:00
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
|
var leadOutMs = new MemoryStream();
|
|
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
|
if(hasLeadOutOnHead0)
|
2020-07-20 21:11:32 +01:00
|
|
|
|
for(int i = 0; i < _sectorsData[totalCylinders - 1][0].Length; i++)
|
|
|
|
|
|
if(_sectorsData[totalCylinders - 1][0][i] != null)
|
|
|
|
|
|
leadOutMs.Write(_sectorsData[totalCylinders - 1][0][i], 0,
|
|
|
|
|
|
_sectorsData[totalCylinders - 1][0][i].Length);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
|
if(hasLeadOutOnHead1)
|
2020-07-20 21:11:32 +01:00
|
|
|
|
for(int i = 0; i < _sectorsData[totalCylinders - 1][1].Length; i++)
|
|
|
|
|
|
if(_sectorsData[totalCylinders - 1][1][i] != null)
|
|
|
|
|
|
leadOutMs.Write(_sectorsData[totalCylinders - 1][1][i], 0,
|
|
|
|
|
|
_sectorsData[totalCylinders - 1][1][i].Length);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
|
|
if(leadOutMs.Length != 0)
|
|
|
|
|
|
{
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_leadOut = leadOutMs.ToArray();
|
|
|
|
|
|
_imageInfo.ReadableMediaTags.Add(MediaTagType.Floppy_LeadOut);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.Sectors = _imageInfo.Cylinders * _imageInfo.Heads * _imageInfo.SectorsPerTrack;
|
|
|
|
|
|
_imageInfo.MediaType = DecodeTeleDiskDiskType();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
AaruConsole.VerboseWriteLine("TeleDisk image contains a disk of type {0}", _imageInfo.MediaType);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(!string.IsNullOrEmpty(_imageInfo.Comments))
|
|
|
|
|
|
AaruConsole.VerboseWriteLine("TeleDisk comments: {0}", _imageInfo.Comments);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
_inStream.Dispose();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
stream.Dispose();
|
|
|
|
|
|
|
2021-09-16 19:10:39 +01:00
|
|
|
|
return ErrorNumber.NoError;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-17 13:56:05 +01:00
|
|
|
|
/// <inheritdoc />
|
2021-09-19 21:16:47 +01:00
|
|
|
|
public ErrorNumber ReadSector(ulong sectorAddress, out byte[] buffer)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2021-09-19 21:16:47 +01:00
|
|
|
|
buffer = null;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
(ushort cylinder, byte head, byte sector) = LbaToChs(sectorAddress);
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(cylinder >= _sectorsData.Length)
|
2021-09-19 21:16:47 +01:00
|
|
|
|
return ErrorNumber.SectorNotFound;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(head >= _sectorsData[cylinder].Length)
|
2021-09-19 21:16:47 +01:00
|
|
|
|
return ErrorNumber.SectorNotFound;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(sector > _sectorsData[cylinder][head].Length)
|
2021-09-19 21:16:47 +01:00
|
|
|
|
return ErrorNumber.SectorNotFound;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2021-09-19 21:16:47 +01:00
|
|
|
|
buffer = _sectorsData[cylinder][head][sector];
|
|
|
|
|
|
|
|
|
|
|
|
return ErrorNumber.NoError;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-17 13:56:05 +01:00
|
|
|
|
/// <inheritdoc />
|
2021-09-19 21:16:47 +01:00
|
|
|
|
public ErrorNumber ReadSectors(ulong sectorAddress, uint length, out byte[] buffer)
|
2017-12-19 20:33:03 +00:00
|
|
|
|
{
|
2021-09-19 21:16:47 +01:00
|
|
|
|
buffer = null;
|
|
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(sectorAddress > _imageInfo.Sectors - 1)
|
2021-09-19 21:16:47 +01:00
|
|
|
|
return ErrorNumber.OutOfRange;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2020-07-20 21:11:32 +01:00
|
|
|
|
if(sectorAddress + length > _imageInfo.Sectors)
|
2021-09-19 21:16:47 +01:00
|
|
|
|
return ErrorNumber.OutOfRange;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2021-09-19 21:16:47 +01:00
|
|
|
|
var ms = new MemoryStream();
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
|
for(uint i = 0; i < length; i++)
|
|
|
|
|
|
{
|
2021-09-19 21:16:47 +01:00
|
|
|
|
ErrorNumber errno = ReadSector(sectorAddress + i, out byte[] sector);
|
|
|
|
|
|
|
|
|
|
|
|
if(errno != ErrorNumber.NoError)
|
|
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
|
|
|
|
ms.Write(sector, 0, sector.Length);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-09-19 21:16:47 +01:00
|
|
|
|
buffer = ms.ToArray();
|
|
|
|
|
|
|
|
|
|
|
|
return ErrorNumber.NoError;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-17 13:56:05 +01:00
|
|
|
|
/// <inheritdoc />
|
2021-09-20 14:22:22 +01:00
|
|
|
|
public ErrorNumber ReadSectorLong(ulong sectorAddress, out byte[] buffer) =>
|
|
|
|
|
|
ReadSectors(sectorAddress, 1, out buffer);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2021-08-17 13:56:05 +01:00
|
|
|
|
/// <inheritdoc />
|
2021-09-20 14:22:22 +01:00
|
|
|
|
public ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, out byte[] buffer) =>
|
|
|
|
|
|
ReadSectors(sectorAddress, 1, out buffer);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2021-08-17 13:56:05 +01:00
|
|
|
|
/// <inheritdoc />
|
2021-09-18 15:01:31 +01:00
|
|
|
|
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
|
2018-01-28 20:29:46 +00:00
|
|
|
|
{
|
2021-09-18 15:01:31 +01:00
|
|
|
|
buffer = null;
|
|
|
|
|
|
|
2018-01-28 20:29:46 +00:00
|
|
|
|
if(tag != MediaTagType.Floppy_LeadOut)
|
2021-09-18 15:01:31 +01:00
|
|
|
|
return ErrorNumber.NotSupported;
|
2018-01-28 20:29:46 +00:00
|
|
|
|
|
2021-09-18 15:01:31 +01:00
|
|
|
|
buffer = _leadOut?.Clone() as byte[];
|
2018-01-28 20:29:46 +00:00
|
|
|
|
|
2021-09-18 15:01:31 +01:00
|
|
|
|
return buffer != null ? ErrorNumber.NoError : ErrorNumber.NoData;
|
2018-01-28 20:29:46 +00:00
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
2017-09-27 14:54:27 +01:00
|
|
|
|
}
|