Added support for 'Dos Order' (.do) disk images.
Added support for 'ProDos Order' (.po) disk images.
This commit is contained in:
parent
7aacc26962
commit
c149a7260c
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
|
@ -20,22 +21,19 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
throw new ArgumentNullException("name");
|
||||
}
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
if (name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase))
|
||||
if (name.EndsWith(".do", StringComparison.OrdinalIgnoreCase) ||
|
||||
name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase)) // assumes dos sector skew
|
||||
{
|
||||
var data = new byte[TrackCount * SectorCount * SectorSize];
|
||||
stream.ReadBlock(data);
|
||||
return new DiskDsk(name, data, isWriteProtected);
|
||||
return new DiskDsk(name, stream, isWriteProtected, SectorSkew.Dos);
|
||||
}
|
||||
else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var data = new byte[TrackCount * TrackSize];
|
||||
stream.ReadBlock(data);
|
||||
return new DiskNib(name, data, isWriteProtected);
|
||||
return new DiskNib(name, stream, isWriteProtected);
|
||||
}
|
||||
else if (name.EndsWith(".po", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new DiskDsk(name, stream, isWriteProtected, SectorSkew.ProDos);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -50,17 +48,22 @@ namespace Jellyfish.Virtu
|
|||
}
|
||||
|
||||
string name = reader.ReadString();
|
||||
bool isWriteProtected = reader.ReadBoolean();
|
||||
var data = reader.ReadBytes(reader.ReadInt32());
|
||||
bool isWriteProtected = reader.ReadBoolean();
|
||||
|
||||
if (name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase))
|
||||
if (name.EndsWith(".do", StringComparison.OrdinalIgnoreCase) ||
|
||||
name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase)) // assumes dos sector skew
|
||||
{
|
||||
return new DiskDsk(name, data, isWriteProtected);
|
||||
return new DiskDsk(name, data, isWriteProtected, SectorSkew.Dos);
|
||||
}
|
||||
else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new DiskNib(name, data, isWriteProtected);
|
||||
}
|
||||
else if (name.EndsWith(".po", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new DiskDsk(name, data, isWriteProtected, SectorSkew.ProDos);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -73,19 +76,18 @@ namespace Jellyfish.Virtu
|
|||
}
|
||||
|
||||
writer.Write(Name);
|
||||
writer.Write(IsWriteProtected);
|
||||
writer.Write(Data.Length);
|
||||
writer.Write(Data);
|
||||
writer.Write(IsWriteProtected);
|
||||
}
|
||||
|
||||
public abstract void ReadTrack(int number, int fraction, byte[] buffer);
|
||||
public abstract void WriteTrack(int number, int fraction, byte[] buffer);
|
||||
|
||||
public string Name { get; private set; }
|
||||
public bool IsWriteProtected { get; private set; }
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
protected byte[] Data { get; private set; }
|
||||
public byte[] Data { get; protected set; }
|
||||
public bool IsWriteProtected { get; private set; }
|
||||
|
||||
public const int SectorCount = 16;
|
||||
public const int SectorSize = 0x100;
|
||||
|
|
|
@ -1,12 +1,29 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskDsk : Disk525
|
||||
public enum SectorSkew { None = 0, Dos, ProDos };
|
||||
|
||||
public class DiskDsk : Disk525
|
||||
{
|
||||
public DiskDsk(string name, byte[] data, bool isWriteProtected) :
|
||||
public DiskDsk(string name, byte[] data, bool isWriteProtected, SectorSkew sectorSkew) :
|
||||
base(name, data, isWriteProtected)
|
||||
{
|
||||
_sectorSkew = SectorSkewMode[(int)sectorSkew];
|
||||
}
|
||||
|
||||
public DiskDsk(string name, Stream stream, bool isWriteProtected, SectorSkew sectorSkew) :
|
||||
base(name, new byte[TrackCount * SectorCount * SectorSize], isWriteProtected)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
stream.ReadBlock(Data);
|
||||
_sectorSkew = SectorSkewMode[(int)sectorSkew];
|
||||
}
|
||||
|
||||
public override void ReadTrack(int number, int fraction, byte[] buffer)
|
||||
|
@ -38,7 +55,7 @@ namespace Jellyfish.Virtu
|
|||
WriteNibble(0xAA);
|
||||
WriteNibble(0xAD);
|
||||
|
||||
WriteDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize);
|
||||
WriteDataNibbles((track * SectorCount + _sectorSkew[sector]) * SectorSize);
|
||||
|
||||
WriteNibble(0xDE); // data epilogue
|
||||
WriteNibble(0xAA);
|
||||
|
@ -84,7 +101,7 @@ namespace Jellyfish.Virtu
|
|||
if (!Read3Nibbles(0xD5, 0xAA, 0xAD, 0x20))
|
||||
break; // no data prologue
|
||||
|
||||
if (!ReadDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize))
|
||||
if (!ReadDataNibbles((track * SectorCount + _sectorSkew[sector]) * SectorSize))
|
||||
break; // bad data checksum
|
||||
|
||||
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
|
||||
|
@ -245,15 +262,33 @@ namespace Jellyfish.Virtu
|
|||
private byte[] _primaryBuffer = new byte[0x100];
|
||||
private const int SecondaryBufferLength = 0x56;
|
||||
private byte[] _secondaryBuffer = new byte[SecondaryBufferLength + 1];
|
||||
private int[] _sectorSkew;
|
||||
private const int Volume = 0xFE;
|
||||
|
||||
private static readonly byte[] SwapBits = { 0, 2, 1, 3 };
|
||||
|
||||
private static readonly int[] DosOrderToLogicalSector = new int[]
|
||||
private static readonly int[] SectorSkewNone = new int[SectorCount]
|
||||
{
|
||||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
|
||||
};
|
||||
|
||||
private static readonly int[] SectorSkewDos = new int[SectorCount]
|
||||
{
|
||||
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF
|
||||
};
|
||||
|
||||
private static readonly int[] SectorSkewProDos = new int[SectorCount]
|
||||
{
|
||||
0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF
|
||||
};
|
||||
|
||||
private const int SectorSkewCount = 3;
|
||||
|
||||
private static readonly int[][] SectorSkewMode = new int[SectorSkewCount][]
|
||||
{
|
||||
SectorSkewNone, SectorSkewDos, SectorSkewProDos
|
||||
};
|
||||
|
||||
private static readonly byte[] ByteToNibble = new byte[]
|
||||
{
|
||||
0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
|
@ -9,6 +11,17 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
}
|
||||
|
||||
public DiskNib(string name, Stream stream, bool isWriteProtected) :
|
||||
base(name, new byte[TrackCount * TrackSize], isWriteProtected)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
stream.ReadBlock(Data);
|
||||
}
|
||||
|
||||
public override void ReadTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
Buffer.BlockCopy(Data, (number / 2) * TrackSize, buffer, 0, TrackSize);
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.ObjectModel;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
|
@ -140,7 +139,7 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
loader(name, stream => Memory.LoadXex(stream));
|
||||
}
|
||||
else if (Regex.IsMatch(name, @"\.(dsk|nib)$", RegexOptions.IgnoreCase))
|
||||
else
|
||||
{
|
||||
loader(name, stream => BootDiskII.BootDrive.InsertDisk(name, stream, false));
|
||||
}
|
||||
|
@ -231,7 +230,7 @@ namespace Jellyfish.Virtu
|
|||
Uninitialize();
|
||||
}
|
||||
|
||||
public const string Version = "0.9.2.0";
|
||||
public const string Version = "0.9.3.0";
|
||||
|
||||
public MachineEvents Events { get; private set; }
|
||||
public MachineServices Services { get; private set; }
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace Jellyfish.Virtu
|
|||
|
||||
private void OnDiskButtonClick(int drive)
|
||||
{
|
||||
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.do;*.dsk;*.nib;*.po)|*.do;*.dsk;*.nib;*.po|All Files (*.*)|*.*" };
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace Jellyfish.Virtu
|
|||
|
||||
//private void OnDiskButtonClick(int drive) // TODO
|
||||
//{
|
||||
// var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
// var dialog = new OpenFileDialog() { Filter = "Disk Files (*.do;*.dsk;*.nib;*.po)|*.do;*.dsk;*.nib;*.po|All Files (*.*)|*.*" };
|
||||
// bool? result = dialog.ShowDialog();
|
||||
// if (result.HasValue && result.Value)
|
||||
// {
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace Jellyfish.Virtu
|
|||
|
||||
private void OnDiskButtonClick(int drive)
|
||||
{
|
||||
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.do;*.dsk;*.nib;*.po)|*.do;*.dsk;*.nib;*.po|All Files (*.*)|*.*" };
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue