2018-08-17 01:20:00 +00:00
|
|
|
package com.bytezone.diskbrowser.nib;
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2018-06-10 20:45:11 +00:00
|
|
|
class Nibblizer
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
2018-08-11 00:07:50 +00:00
|
|
|
// still used by NibDisk and V2dDisk
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
private static byte[] addressPrologue32 = { (byte) 0xD5, (byte) 0xAA, (byte) 0xB5 };
|
|
|
|
private static byte[] addressPrologue33 = { (byte) 0xD5, (byte) 0xAA, (byte) 0x96 };
|
2018-06-10 20:45:11 +00:00
|
|
|
private static byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
|
|
|
|
private static byte[] epilogue = { (byte) 0xDE, (byte) 0xAA, (byte) 0xEB };
|
|
|
|
|
|
|
|
private static int[] interleave =
|
|
|
|
{ 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
|
|
|
|
|
|
|
|
private static final int BLOCK_SIZE = 256;
|
2018-08-07 08:40:06 +00:00
|
|
|
private static final int RAW_BUFFER_SIZE_DOS_33 = 342;
|
|
|
|
private static final int RAW_BUFFER_SIZE_DOS_32 = 410;
|
|
|
|
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_33 = RAW_BUFFER_SIZE_DOS_33 + 1;
|
|
|
|
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_32 = RAW_BUFFER_SIZE_DOS_32 + 1;
|
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
private final ByteTranslator byteTranslator62 = new ByteTranslator6and2 ();
|
|
|
|
private final ByteTranslator byteTranslator53 = new ByteTranslator5and3 ();
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
private final byte[] decodeDos33a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
|
|
|
|
private final byte[] decodeDos33b = new byte[RAW_BUFFER_SIZE_DOS_33];
|
|
|
|
|
|
|
|
private final byte[] encodeDos33a = new byte[RAW_BUFFER_SIZE_DOS_33];
|
|
|
|
private final byte[] encodeDos33b = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
|
2016-12-04 02:33:21 +00:00
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
private final byte[] decodeDos32a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_32];
|
|
|
|
private final byte[] decodeDos32b = new byte[RAW_BUFFER_SIZE_DOS_32];
|
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
private int sectorsPerTrack;
|
2018-08-07 08:40:06 +00:00
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// processTrack
|
|
|
|
// ---------------------------------------------------------------------------------//
|
2016-11-30 00:37:10 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
boolean processTrack (int trackNo, int maxTracks, byte[] buffer, byte[] diskBuffer)
|
2016-12-03 08:20:01 +00:00
|
|
|
{
|
|
|
|
int ptr = 0;
|
2018-06-08 12:14:19 +00:00
|
|
|
int totalSectors = 0;
|
|
|
|
boolean[] sectorsFound = new boolean[16];
|
2018-08-11 00:07:50 +00:00
|
|
|
sectorsPerTrack = maxTracks;
|
2016-12-03 08:20:01 +00:00
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
try
|
2016-12-03 08:20:01 +00:00
|
|
|
{
|
2018-08-07 08:40:06 +00:00
|
|
|
while (ptr < buffer.length)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
2018-08-11 00:07:50 +00:00
|
|
|
if (sectorsPerTrack == 13)
|
|
|
|
ptr = findBytes (buffer, ptr, addressPrologue32);
|
2018-08-07 08:40:06 +00:00
|
|
|
else
|
2018-08-11 00:07:50 +00:00
|
|
|
ptr = findBytes (buffer, ptr, addressPrologue33);
|
|
|
|
|
|
|
|
if (ptr < 0)
|
2018-08-07 08:40:06 +00:00
|
|
|
{
|
2018-08-11 00:07:50 +00:00
|
|
|
System.out.printf ("Track: %02X - Address prologue not found%n", trackNo);
|
|
|
|
return false;
|
2018-08-07 08:40:06 +00:00
|
|
|
}
|
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
AddressField addressField = new AddressField (buffer, ptr);
|
2018-08-07 08:40:06 +00:00
|
|
|
if (!addressField.isValid ())
|
|
|
|
{
|
|
|
|
System.out.printf ("Track: %02X - Invalid address field%n", trackNo);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addressField.track != trackNo)
|
|
|
|
{
|
|
|
|
System.out.printf ("Track: %02X - Wrong track found (%02X)%n", trackNo,
|
|
|
|
addressField.track);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sectorsFound[addressField.sector])
|
|
|
|
{
|
|
|
|
System.out.printf ("Track: %02X - Sector already processes (%02X)%n", trackNo,
|
|
|
|
addressField.sector);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
sectorsFound[addressField.sector] = true;
|
|
|
|
|
|
|
|
assert addressField.track == trackNo;
|
|
|
|
|
|
|
|
ptr += addressField.size ();
|
|
|
|
ptr = findBytes (buffer, ptr, dataPrologue);
|
|
|
|
if (ptr < 0)
|
|
|
|
{
|
|
|
|
System.out.printf ("Track: %02X - Data prologue not found%n", trackNo);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
DataField dataField = new DataField (buffer, ptr);
|
2018-08-07 08:40:06 +00:00
|
|
|
if (!dataField.isValid ())
|
|
|
|
{
|
|
|
|
System.out.printf ("Track: %02X - Invalid data field%n", trackNo);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
int offset;
|
|
|
|
if (sectorsPerTrack == 13)
|
|
|
|
offset = addressField.track * 0x0D00 + addressField.sector * BLOCK_SIZE;
|
2018-08-07 08:40:06 +00:00
|
|
|
else
|
2018-08-11 00:07:50 +00:00
|
|
|
offset =
|
|
|
|
addressField.track * 0x1000 + interleave[addressField.sector] * BLOCK_SIZE;
|
2018-08-07 08:40:06 +00:00
|
|
|
|
|
|
|
System.arraycopy (dataField.dataBuffer, 0, diskBuffer, offset, BLOCK_SIZE);
|
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
if (++totalSectors == sectorsPerTrack)
|
2018-08-07 08:40:06 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
ptr += dataField.size ();
|
2018-06-08 12:14:19 +00:00
|
|
|
}
|
2018-08-07 08:40:06 +00:00
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
e.printStackTrace ();
|
|
|
|
}
|
2018-06-08 12:14:19 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
if (totalSectors != sectorsPerTrack)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
|
|
|
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
|
|
|
|
return false;
|
2016-12-03 08:20:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// decode4and4
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2016-12-01 13:25:41 +00:00
|
|
|
private int decode4and4 (byte[] buffer, int offset)
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
|
|
|
int odds = ((buffer[offset] & 0xFF) << 1) + 1;
|
|
|
|
int evens = buffer[offset + 1] & 0xFF;
|
|
|
|
return odds & evens;
|
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// decode5and3
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
private byte[] decode5and3 (byte[] buffer, int offset)
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
2018-08-07 08:40:06 +00:00
|
|
|
// rearrange 410 bytes into 256
|
2018-08-07 09:22:31 +00:00
|
|
|
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
|
2018-08-07 08:40:06 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
try
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
2018-08-11 00:07:50 +00:00
|
|
|
// convert legal disk values to actual 5 bit values
|
|
|
|
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_32; i++) // 411 bytes
|
|
|
|
{
|
|
|
|
// System.out.printf ("%,5d %02X%n", i, buffer[offset]);
|
2018-08-11 04:12:21 +00:00
|
|
|
decodeDos32a[i] = (byte) (byteTranslator53.decode (buffer[offset++]) << 3);
|
2018-08-11 00:07:50 +00:00
|
|
|
}
|
2018-08-07 08:40:06 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
// reconstruct 410 bytes each with 5 bits
|
|
|
|
byte chk = 0;
|
|
|
|
int ptr = 0;
|
|
|
|
for (int i = 409; i >= 256; i--) // 154 bytes
|
|
|
|
chk = decodeDos32b[i] = (byte) (decodeDos32a[ptr++] ^ chk);
|
|
|
|
for (int i = 0; i < 256; i++) // 256 bytes
|
|
|
|
chk = decodeDos32b[i] = (byte) (decodeDos32a[ptr++] ^ chk);
|
|
|
|
assert (chk ^ decodeDos32a[ptr]) == 0;
|
|
|
|
|
|
|
|
byte[] k = new byte[8];
|
|
|
|
ptr = 0;
|
|
|
|
final int[] lines = { 0, 51, 102, 153, 204, 256, 307, 358 }; // 255 is skipped
|
|
|
|
|
|
|
|
// process 8 disk bytes at a time, giving 5 valid bytes
|
|
|
|
// do this 51 times, giving 255 bytes
|
|
|
|
for (int i = 50; i >= 0; i--)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < 8; j++)
|
|
|
|
k[j] = decodeDos32b[i + lines[j]];
|
2018-08-07 08:40:06 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
k[0] |= (k[5] & 0xE0) >>> 5;
|
|
|
|
k[1] |= (k[6] & 0xE0) >>> 5;
|
|
|
|
k[2] |= (k[7] & 0xE0) >>> 5;
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
k[3] |= (k[5] & 0x10) >>> 2;
|
|
|
|
k[3] |= (k[6] & 0x10) >>> 3;
|
|
|
|
k[3] |= (k[7] & 0x10) >>> 4;
|
2018-08-07 08:40:06 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
k[4] |= (k[5] & 0x08) >>> 1;
|
|
|
|
k[4] |= (k[6] & 0x08) >>> 2;
|
|
|
|
k[4] |= (k[7] & 0x08) >>> 3;
|
2018-08-07 08:40:06 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
for (int j = 0; j < 5; j++)
|
|
|
|
decodedBuffer[ptr++] = k[j];
|
|
|
|
}
|
2018-08-07 09:22:31 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
// add last byte
|
|
|
|
decodedBuffer[255] = (byte) (decodeDos32b[255] | (decodeDos32b[409] >>> 3));
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
2018-08-07 09:22:31 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
}
|
2018-08-07 09:22:31 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
return decodedBuffer;
|
2018-08-07 08:40:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// decode6and2
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
private byte[] decode6and2 (byte[] buffer, int offset)
|
|
|
|
{
|
|
|
|
// rearrange 342 bytes into 256
|
|
|
|
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
try
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
2018-08-11 00:07:50 +00:00
|
|
|
// convert legal disk values to actual 6 bit values
|
|
|
|
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++) // 343 bytes
|
2018-08-11 04:12:21 +00:00
|
|
|
decodeDos33a[i] = (byte) (byteTranslator62.decode (buffer[offset++]) << 2);
|
2018-08-11 00:07:50 +00:00
|
|
|
|
|
|
|
// reconstruct 342 bytes each with 6 bits
|
|
|
|
byte chk = 0;
|
|
|
|
for (int i = decodeDos33b.length - 1; i >= 0; i--) // 342 bytes
|
|
|
|
chk = decodeDos33b[i] = (byte) (decodeDos33a[i + 1] ^ chk);
|
|
|
|
assert (chk ^ decodeDos33a[0]) == 0;
|
|
|
|
|
|
|
|
// move 6 bits into place
|
|
|
|
for (int i = 0; i < BLOCK_SIZE; i++)
|
|
|
|
decodedBuffer[i] = decodeDos33b[i + 86];
|
|
|
|
|
|
|
|
// reattach each byte's last 2 bits
|
|
|
|
for (int i = 0, j = 86, k = 172; i < 86; i++, j++, k++)
|
|
|
|
{
|
|
|
|
byte val = decodeDos33b[i];
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2018-08-11 00:07:50 +00:00
|
|
|
decodedBuffer[i] |= reverse ((val & 0x0C) >> 2);
|
|
|
|
decodedBuffer[j] |= reverse ((val & 0x30) >> 4);
|
|
|
|
|
|
|
|
if (k < BLOCK_SIZE)
|
|
|
|
decodedBuffer[k] |= reverse ((val & 0xC0) >> 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
2016-11-28 04:25:52 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return decodedBuffer;
|
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// encode6and2
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2016-12-04 02:33:21 +00:00
|
|
|
// convert 256 data bytes into 342 translated bytes plus a checksum
|
2016-12-01 13:25:41 +00:00
|
|
|
private byte[] encode6and2 (byte[] buffer)
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
2018-08-07 08:40:06 +00:00
|
|
|
byte[] encodedBuffer = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2016-12-04 02:33:21 +00:00
|
|
|
// move data buffer down to make room for the 86 extra bytes
|
|
|
|
for (int i = 0; i < BLOCK_SIZE; i++)
|
2018-08-07 08:40:06 +00:00
|
|
|
encodeDos33a[i + 86] = buffer[i];
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2016-12-04 02:33:21 +00:00
|
|
|
// build extra 86 bytes from the bits stripped from the data bytes
|
|
|
|
for (int i = 0; i < 86; i++)
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
|
|
|
int b1 = reverse (buffer[i] & 0x03) << 2;
|
|
|
|
int b2 = reverse (buffer[i + 86] & 0x03) << 4;
|
|
|
|
|
2016-12-04 02:33:21 +00:00
|
|
|
if (i < 84)
|
|
|
|
{
|
|
|
|
int b3 = reverse (buffer[i + 172] & 0x03) << 6;
|
2018-08-07 08:40:06 +00:00
|
|
|
encodeDos33a[i] = (byte) (b1 | b2 | b3);
|
2016-12-04 02:33:21 +00:00
|
|
|
}
|
|
|
|
else
|
2018-08-07 08:40:06 +00:00
|
|
|
encodeDos33a[i] = (byte) (b1 | b2);
|
2016-11-28 04:25:52 +00:00
|
|
|
}
|
|
|
|
|
2016-12-04 02:33:21 +00:00
|
|
|
// convert into checksum bytes
|
|
|
|
byte checksum = 0;
|
2018-08-07 08:40:06 +00:00
|
|
|
for (int i = 0; i < RAW_BUFFER_SIZE_DOS_33; i++)
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
2018-08-07 08:40:06 +00:00
|
|
|
encodeDos33b[i] = (byte) (checksum ^ encodeDos33a[i]);
|
|
|
|
checksum = encodeDos33a[i];
|
2016-11-28 04:25:52 +00:00
|
|
|
}
|
2018-08-07 08:40:06 +00:00
|
|
|
encodeDos33b[RAW_BUFFER_SIZE_DOS_33] = checksum; // add checksum to the end
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2016-12-04 02:33:21 +00:00
|
|
|
// remove two bits and convert to translated bytes
|
2018-08-07 08:40:06 +00:00
|
|
|
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++)
|
2018-08-11 00:07:50 +00:00
|
|
|
// encodedBuffer[i] = writeTranslateTable6and2[(encodeDos33b[i] & 0xFC) / 4];
|
|
|
|
encodedBuffer[i] = byteTranslator62.encode (encodeDos33b[i]);
|
2016-11-28 04:25:52 +00:00
|
|
|
|
2016-11-30 00:37:10 +00:00
|
|
|
return encodedBuffer;
|
2016-11-28 04:25:52 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// reverse
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2016-11-30 00:37:10 +00:00
|
|
|
// reverse 2 bits - 0 <= bits <= 3
|
|
|
|
private static int reverse (int bits)
|
2016-11-28 04:25:52 +00:00
|
|
|
{
|
2016-11-30 00:37:10 +00:00
|
|
|
return bits == 1 ? 2 : bits == 2 ? 1 : bits;
|
2016-11-28 04:25:52 +00:00
|
|
|
}
|
2016-11-28 09:11:11 +00:00
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// listBytes
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2016-12-01 13:25:41 +00:00
|
|
|
private String listBytes (byte[] buffer, int offset, int length)
|
2016-11-28 09:11:11 +00:00
|
|
|
{
|
2016-12-01 13:25:41 +00:00
|
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
|
|
|
|
int max = Math.min (length + offset, buffer.length);
|
|
|
|
while (offset < max)
|
|
|
|
text.append (String.format ("%02X ", buffer[offset++]));
|
|
|
|
|
|
|
|
return text.toString ();
|
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// findBytes
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2016-12-04 02:33:21 +00:00
|
|
|
static int findBytes (byte[] buffer, int offset, byte[] valueBuffer)
|
2016-12-01 13:25:41 +00:00
|
|
|
{
|
2018-08-07 08:40:06 +00:00
|
|
|
while (offset + valueBuffer.length <= buffer.length)
|
2016-11-28 09:11:11 +00:00
|
|
|
{
|
2016-12-04 02:33:21 +00:00
|
|
|
if (matchBytes (buffer, offset, valueBuffer))
|
|
|
|
return offset;
|
|
|
|
++offset;
|
2016-11-28 09:11:11 +00:00
|
|
|
}
|
2016-11-30 00:37:10 +00:00
|
|
|
|
2016-12-01 13:25:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// matchBytes
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2016-12-04 02:33:21 +00:00
|
|
|
private static boolean matchBytes (byte[] buffer, int offset, byte[] valueBuffer)
|
2016-12-01 13:25:41 +00:00
|
|
|
{
|
2018-08-07 08:40:06 +00:00
|
|
|
if ((buffer.length - offset) < valueBuffer.length)
|
2016-12-04 02:33:21 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
int ptr = 0;
|
2018-08-07 08:40:06 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
while (ptr < valueBuffer.length)
|
|
|
|
if (buffer[offset++] != valueBuffer[ptr++])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
catch (ArrayIndexOutOfBoundsException e)
|
|
|
|
{
|
|
|
|
System.out.println ("Error in matchBytes");
|
|
|
|
e.printStackTrace ();
|
|
|
|
return false;
|
|
|
|
}
|
2016-12-04 02:33:21 +00:00
|
|
|
|
2016-12-01 13:25:41 +00:00
|
|
|
return true;
|
2016-11-28 09:11:11 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// Field
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-10 20:45:11 +00:00
|
|
|
private abstract class Field
|
2016-11-28 09:11:11 +00:00
|
|
|
{
|
2016-11-30 00:37:10 +00:00
|
|
|
protected boolean valid;
|
|
|
|
protected byte[] buffer;
|
|
|
|
protected int offset;
|
|
|
|
protected int length;
|
2016-11-28 09:11:11 +00:00
|
|
|
|
|
|
|
public Field (byte[] buffer, int offset)
|
|
|
|
{
|
|
|
|
this.buffer = buffer;
|
|
|
|
this.offset = offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isValid ()
|
|
|
|
{
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
2016-11-30 00:37:10 +00:00
|
|
|
public int size ()
|
|
|
|
{
|
|
|
|
assert length > 0;
|
|
|
|
return length;
|
|
|
|
}
|
2018-06-08 12:14:19 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString ()
|
|
|
|
{
|
|
|
|
return String.format ("[Offset: %04X, Length: %04X]", offset, length);
|
|
|
|
}
|
2016-11-28 09:11:11 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// AddressField
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-10 20:45:11 +00:00
|
|
|
private class AddressField extends Field
|
2016-11-28 09:11:11 +00:00
|
|
|
{
|
|
|
|
int track, sector, volume, checksum;
|
|
|
|
|
|
|
|
public AddressField (byte[] buffer, int offset)
|
|
|
|
{
|
|
|
|
super (buffer, offset);
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
volume = decode4and4 (buffer, offset + 3);
|
|
|
|
track = decode4and4 (buffer, offset + 5);
|
|
|
|
sector = decode4and4 (buffer, offset + 7);
|
|
|
|
checksum = decode4and4 (buffer, offset + 9);
|
|
|
|
valid = true;
|
2016-11-28 09:11:11 +00:00
|
|
|
|
2016-11-30 00:37:10 +00:00
|
|
|
length = 14;
|
2016-11-28 09:11:11 +00:00
|
|
|
}
|
2018-06-08 12:14:19 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString ()
|
|
|
|
{
|
|
|
|
return String.format ("[volume: %02X, track: %02X, sector: %02X, checksum: %02X]",
|
|
|
|
volume, track, sector, checksum);
|
|
|
|
}
|
2016-11-28 09:11:11 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 08:40:06 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// DataField
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-10 20:45:11 +00:00
|
|
|
private class DataField extends Field
|
2016-11-28 09:11:11 +00:00
|
|
|
{
|
2016-12-01 13:25:41 +00:00
|
|
|
byte[] dataBuffer;
|
|
|
|
|
2016-11-28 09:11:11 +00:00
|
|
|
public DataField (byte[] buffer, int offset)
|
|
|
|
{
|
|
|
|
super (buffer, offset);
|
|
|
|
|
2016-11-29 21:27:44 +00:00
|
|
|
if (matchBytes (buffer, offset, dataPrologue))
|
2016-11-28 09:11:11 +00:00
|
|
|
{
|
|
|
|
valid = true;
|
2018-08-11 00:07:50 +00:00
|
|
|
if (sectorsPerTrack == 13)
|
2018-08-07 08:40:06 +00:00
|
|
|
dataBuffer = decode5and3 (buffer, offset + 3);
|
2018-08-11 00:07:50 +00:00
|
|
|
else
|
|
|
|
dataBuffer = decode6and2 (buffer, offset + 3);
|
2016-11-29 21:27:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
System.out.print (" bad data prologue: ");
|
2016-12-01 13:25:41 +00:00
|
|
|
System.out.println (listBytes (buffer, offset, 3));
|
2016-11-28 09:11:11 +00:00
|
|
|
}
|
|
|
|
|
2016-11-30 00:37:10 +00:00
|
|
|
length = 349;
|
2016-11-28 09:11:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|