mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2025-02-18 05:30:29 +00:00
rewrote the nibble routines
This commit is contained in:
parent
aac34c9095
commit
82600b8d0b
@ -24,6 +24,7 @@ public class CPMDisk extends AbstractFormattedDisk
|
||||
public final SectorType macSector = new SectorType ("MAC", Color.green);
|
||||
|
||||
private int version; // http://www.seasip.info/Cpm/format22.html
|
||||
// // http://www.seasip.info/Cpm/format31.html
|
||||
|
||||
public CPMDisk (Disk disk)
|
||||
{
|
||||
|
@ -231,30 +231,16 @@ public class AppleDisk implements Disk
|
||||
this.tracks = tracks;
|
||||
this.sectors = sectors;
|
||||
file = disk.file;
|
||||
diskBuffer = disk.diskBuffer;
|
||||
|
||||
if (sectors == 13)
|
||||
{
|
||||
trackSize = 0xD00;
|
||||
sectorSize = 256;
|
||||
diskBuffer = new byte[116480];
|
||||
|
||||
int ptr = 0;
|
||||
for (int track = 0; track < 35; track++)
|
||||
{
|
||||
for (int sector = 0; sector < 13; sector++)
|
||||
{
|
||||
int ptr2 = track * 0xD00 + sector * 0x100;
|
||||
System.arraycopy (disk.diskBuffer, ptr, diskBuffer, ptr2, 0x100);
|
||||
// System.out.printf ("Copying %04X -> %04X%n", ptr, ptr2);
|
||||
ptr += 0x100;
|
||||
}
|
||||
ptr += 0x300; // skip 3 sectors
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trackSize = 4096;
|
||||
diskBuffer = disk.diskBuffer;
|
||||
trackSize = 0x1000;
|
||||
sectorSize = trackSize / sectors;
|
||||
}
|
||||
|
||||
|
8
src/com/bytezone/diskbrowser/disk/ByteTranslator.java
Normal file
8
src/com/bytezone/diskbrowser/disk/ByteTranslator.java
Normal file
@ -0,0 +1,8 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
public abstract class ByteTranslator
|
||||
{
|
||||
abstract byte encode (byte b);
|
||||
|
||||
abstract byte decode (byte b) throws DiskNibbleException;
|
||||
}
|
68
src/com/bytezone/diskbrowser/disk/ByteTranslator5and3.java
Normal file
68
src/com/bytezone/diskbrowser/disk/ByteTranslator5and3.java
Normal file
@ -0,0 +1,68 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
public class ByteTranslator5and3 extends ByteTranslator
|
||||
{
|
||||
// 32 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
|
||||
private static byte[] writeTranslateTable5and3 =
|
||||
{ (byte) 0xAB, (byte) 0xAD, (byte) 0xAE, (byte) 0xAF, (byte) 0xB5, (byte) 0xB6,
|
||||
(byte) 0xB7, (byte) 0xBA, (byte) 0xBB, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF,
|
||||
(byte) 0xD6, (byte) 0xD7, (byte) 0xDA, (byte) 0xDB, //
|
||||
(byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xEA, (byte) 0xEB, (byte) 0xED,
|
||||
(byte) 0xEE, (byte) 0xEF, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xFA,
|
||||
(byte) 0xFB, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
|
||||
|
||||
private static byte[] readTranslateTable5and3 = new byte[85]; // skip first 171 blanks
|
||||
private static boolean debug = false;
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < writeTranslateTable5and3.length; i++)
|
||||
{
|
||||
int j = (writeTranslateTable5and3[i] & 0xFF) - 0xAB; // skip first 171 blanks
|
||||
readTranslateTable5and3[j] = (byte) (i + 1); // offset by 1 to avoid zero
|
||||
if (debug)
|
||||
System.out.printf ("%02X %02X %02X%n", i, writeTranslateTable5and3[i], j);
|
||||
}
|
||||
if (debug)
|
||||
for (int j = 0; j < readTranslateTable5and3.length; j++)
|
||||
{
|
||||
int target = readTranslateTable5and3[j] - 1;
|
||||
if (target >= 0)
|
||||
{
|
||||
int value = writeTranslateTable5and3[target] & 0xFF;
|
||||
System.out.printf ("%02X -> %02X%n", j, value);
|
||||
}
|
||||
else
|
||||
System.out.printf ("%02X%n", j);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// encode
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
byte encode (byte b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// decode
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
byte decode (byte b) throws DiskNibbleException
|
||||
{
|
||||
int val = (b & 0xFF) - 0xAB; // 0 - 84
|
||||
// assert val >= 0 && val <= 84 : "Val: " + val;
|
||||
if (val < 0 || val > 84)
|
||||
throw new DiskNibbleException ("Val: " + val);
|
||||
byte trans = (byte) (readTranslateTable5and3[val] - 1); // 0 - 31 (5 bits)
|
||||
// assert trans >= 0 && trans <= 31 : "Trans: " + trans;
|
||||
if (trans < 0 || trans > 31)
|
||||
throw new DiskNibbleException ("Trans: " + trans);
|
||||
return (byte) (trans << 3); // left justify 5 bits
|
||||
}
|
||||
|
||||
}
|
50
src/com/bytezone/diskbrowser/disk/ByteTranslator6and2.java
Normal file
50
src/com/bytezone/diskbrowser/disk/ByteTranslator6and2.java
Normal file
@ -0,0 +1,50 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
public class ByteTranslator6and2 extends ByteTranslator
|
||||
{
|
||||
// 64 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
|
||||
private static byte[] writeTranslateTable6and2 =
|
||||
{ (byte) 0x96, (byte) 0x97, (byte) 0x9A, (byte) 0x9B, (byte) 0x9D, (byte) 0x9E,
|
||||
(byte) 0x9F, (byte) 0xA6, (byte) 0xA7, (byte) 0xAB, (byte) 0xAC, (byte) 0xAD,
|
||||
(byte) 0xAE, (byte) 0xAF, (byte) 0xB2, (byte) 0xB3, //
|
||||
(byte) 0xB4, (byte) 0xB5, (byte) 0xB6, (byte) 0xB7, (byte) 0xB9, (byte) 0xBA,
|
||||
(byte) 0xBB, (byte) 0xBC, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF, (byte) 0xCB,
|
||||
(byte) 0xCD, (byte) 0xCE, (byte) 0xCF, (byte) 0xD3, //
|
||||
(byte) 0xD6, (byte) 0xD7, (byte) 0xD9, (byte) 0xDA, (byte) 0xDB, (byte) 0xDC,
|
||||
(byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xE5, (byte) 0xE6, (byte) 0xE7,
|
||||
(byte) 0xE9, (byte) 0xEA, (byte) 0xEB, (byte) 0xEC, //
|
||||
(byte) 0xED, (byte) 0xEE, (byte) 0xEF, (byte) 0xF2, (byte) 0xF3, (byte) 0xF4,
|
||||
(byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB,
|
||||
(byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
|
||||
|
||||
private static byte[] readTranslateTable6and2 = new byte[106]; // skip first 150 blanks
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < writeTranslateTable6and2.length; i++)
|
||||
{
|
||||
int j = (writeTranslateTable6and2[i] & 0xFF) - 0x96; // skip first 150 blanks
|
||||
readTranslateTable6and2[j] = (byte) (i + 1); // offset by 1 to avoid zero
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
byte encode (byte b)
|
||||
{
|
||||
return writeTranslateTable6and2[(b & 0xFC) / 4];
|
||||
}
|
||||
|
||||
@Override
|
||||
byte decode (byte b) throws DiskNibbleException
|
||||
{
|
||||
int val = (b & 0xFF) - 0x96; // 0 - 105
|
||||
// assert val >= 0 && val <= 105 : "Val: " + val;
|
||||
if (val < 0 || val > 105)
|
||||
throw new DiskNibbleException ("Val: " + val);
|
||||
byte trans = (byte) (readTranslateTable6and2[val] - 1); // 0 - 63 (6 bits)
|
||||
// assert trans >= 0 && trans <= 63 : "Trans: " + trans;
|
||||
if (trans < 0 || trans > 63)
|
||||
throw new DiskNibbleException ("Trans: " + trans);
|
||||
return (byte) (trans << 2); // left justify 6 bits
|
||||
}
|
||||
}
|
40
src/com/bytezone/diskbrowser/disk/DiskAddressField.java
Normal file
40
src/com/bytezone/diskbrowser/disk/DiskAddressField.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
class DiskAddressField
|
||||
{
|
||||
int track, sector, volume, checksum;
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// constructor
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
DiskAddressField (byte[] buffer, int offset)
|
||||
{
|
||||
volume = decode4and4 (buffer, offset);
|
||||
track = decode4and4 (buffer, offset + 2);
|
||||
sector = decode4and4 (buffer, offset + 4);
|
||||
checksum = decode4and4 (buffer, offset + 6);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// decode4and4
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
int decode4and4 (byte[] buffer, int offset)
|
||||
{
|
||||
int odds = ((buffer[offset] & 0xFF) << 1) + 1;
|
||||
int evens = buffer[offset + 1] & 0xFF;
|
||||
return odds & evens;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// toString
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return String.format ("[volume: %02X, track: %02X, sector: %02X, checksum: %02X]",
|
||||
volume, track, sector, checksum);
|
||||
}
|
||||
}
|
@ -232,7 +232,7 @@ public class DiskFactory
|
||||
try
|
||||
{
|
||||
WozDisk wozDisk = new WozDisk (file);
|
||||
if (wozDisk.sectorsPerTrack == 13)
|
||||
if (wozDisk.getSectorsPerTrack () == 13)
|
||||
{
|
||||
AppleDisk appleDisk = new AppleDisk (wozDisk, 35, 13);
|
||||
disk = checkDos (appleDisk);
|
||||
@ -248,7 +248,8 @@ public class DiskFactory
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.out.println (e);
|
||||
// System.out.println (e);
|
||||
e.printStackTrace ();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
17
src/com/bytezone/diskbrowser/disk/DiskNibbleException.java
Normal file
17
src/com/bytezone/diskbrowser/disk/DiskNibbleException.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
public class DiskNibbleException extends Exception
|
||||
{
|
||||
String message;
|
||||
|
||||
public DiskNibbleException (String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
}
|
33
src/com/bytezone/diskbrowser/disk/DiskReader.java
Normal file
33
src/com/bytezone/diskbrowser/disk/DiskReader.java
Normal file
@ -0,0 +1,33 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
import com.bytezone.diskbrowser.disk.MC3470.DiskSector;
|
||||
|
||||
public abstract class DiskReader
|
||||
{
|
||||
static final int BLOCK_SIZE = 256;
|
||||
static final byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
|
||||
|
||||
int sectorsPerTrack;
|
||||
boolean debug = false;
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// constructor
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
DiskReader (int sectorsPerTrack)
|
||||
{
|
||||
this.sectorsPerTrack = sectorsPerTrack;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// abstract functions
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
abstract byte[] decodeSector (byte[] buffer, int ptr);
|
||||
|
||||
abstract byte[] encodeSector (byte[] buffer);
|
||||
|
||||
abstract void storeBuffer (DiskSector diskSector, byte[] diskBuffer);
|
||||
|
||||
abstract int expectedDataSize ();
|
||||
}
|
122
src/com/bytezone/diskbrowser/disk/DiskReader13Sector.java
Normal file
122
src/com/bytezone/diskbrowser/disk/DiskReader13Sector.java
Normal file
@ -0,0 +1,122 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
import com.bytezone.diskbrowser.disk.MC3470.DiskSector;
|
||||
|
||||
public class DiskReader13Sector extends DiskReader
|
||||
{
|
||||
private static final int RAW_BUFFER_SIZE_DOS_32 = 410;
|
||||
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_32 = RAW_BUFFER_SIZE_DOS_32 + 1;
|
||||
|
||||
private final byte[] decodeDos32a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_32];
|
||||
private final byte[] decodeDos32b = new byte[RAW_BUFFER_SIZE_DOS_32];
|
||||
|
||||
private final ByteTranslator byteTranslator53 = new ByteTranslator5and3 ();
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// constructor
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
DiskReader13Sector ()
|
||||
{
|
||||
super (13);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// decodeSector
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
byte[] decodeSector (byte[] buffer, int offset)
|
||||
{
|
||||
byte[] decodedBuffer = new byte[BLOCK_SIZE];
|
||||
|
||||
try
|
||||
{
|
||||
// convert legal disk values to actual 5 bit values
|
||||
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_32; i++) // 411 bytes
|
||||
decodeDos32a[i] = byteTranslator53.decode (buffer[offset++]);
|
||||
|
||||
// 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);
|
||||
if ((chk ^ decodeDos32a[ptr]) != 0)
|
||||
throw new DiskNibbleException ("Checksum failed");
|
||||
|
||||
// rearrange 410 bytes into 256
|
||||
byte[] k = new byte[8];
|
||||
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
|
||||
ptr = 0;
|
||||
for (int i = 50; i >= 0; i--)
|
||||
{
|
||||
for (int j = 0; j < 8; j++)
|
||||
k[j] = decodeDos32b[i + lines[j]];
|
||||
|
||||
k[0] |= (k[5] & 0xE0) >>> 5;
|
||||
k[1] |= (k[6] & 0xE0) >>> 5;
|
||||
k[2] |= (k[7] & 0xE0) >>> 5;
|
||||
|
||||
k[3] |= (k[5] & 0x10) >>> 2;
|
||||
k[3] |= (k[6] & 0x10) >>> 3;
|
||||
k[3] |= (k[7] & 0x10) >>> 4;
|
||||
|
||||
k[4] |= (k[5] & 0x08) >>> 1;
|
||||
k[4] |= (k[6] & 0x08) >>> 2;
|
||||
k[4] |= (k[7] & 0x08) >>> 3;
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
decodedBuffer[ptr++] = k[j];
|
||||
}
|
||||
|
||||
// add last byte
|
||||
decodedBuffer[ptr] =
|
||||
(byte) (decodeDos32b[255] | ((decodeDos32b[409] & 0x3F) >>> 3));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.out.println (e);
|
||||
}
|
||||
|
||||
return decodedBuffer;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// encodeSector
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
byte[] encodeSector (byte[] buffer)
|
||||
{
|
||||
System.out.println ("encodeSector() not written");
|
||||
return null;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// storeBuffer
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
void storeBuffer (DiskSector diskSector, byte[] diskBuffer)
|
||||
{
|
||||
DiskAddressField addressField = diskSector.addressField;
|
||||
byte[] sectorBuffer = diskSector.buffer;
|
||||
int offset = addressField.track * 0x0D00 + addressField.sector * 256;
|
||||
System.arraycopy (sectorBuffer, 0, diskBuffer, offset, 256);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// expectedDataSize
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
int expectedDataSize ()
|
||||
{
|
||||
return 411;
|
||||
}
|
||||
}
|
163
src/com/bytezone/diskbrowser/disk/DiskReader16Sector.java
Normal file
163
src/com/bytezone/diskbrowser/disk/DiskReader16Sector.java
Normal file
@ -0,0 +1,163 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
import com.bytezone.diskbrowser.disk.MC3470.DiskSector;
|
||||
|
||||
public class DiskReader16Sector extends DiskReader
|
||||
{
|
||||
private static final int RAW_BUFFER_SIZE_DOS_33 = 342;
|
||||
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_33 = RAW_BUFFER_SIZE_DOS_33 + 1;
|
||||
|
||||
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];
|
||||
|
||||
private final ByteTranslator byteTranslator62 = new ByteTranslator6and2 ();
|
||||
|
||||
private static int[] interleave =
|
||||
{ 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// constructor
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
DiskReader16Sector ()
|
||||
{
|
||||
super (16);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// decodeSector
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
byte[] decodeSector (byte[] buffer, int offset)
|
||||
{
|
||||
// rearrange 342 bytes into 256
|
||||
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
|
||||
|
||||
try
|
||||
{
|
||||
if (offset + BUFFER_WITH_CHECKSUM_SIZE_DOS_33 >= buffer.length)
|
||||
throw new DiskNibbleException (
|
||||
String.format ("Buffer not long enough (need %d, found %d)",
|
||||
BUFFER_WITH_CHECKSUM_SIZE_DOS_33, buffer.length - offset));
|
||||
|
||||
// convert legal disk values to actual 6 bit values
|
||||
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++) // 343 bytes
|
||||
{
|
||||
if (offset == buffer.length)
|
||||
offset = 0;
|
||||
decodeDos33a[i] = byteTranslator62.decode (buffer[offset++]);
|
||||
}
|
||||
|
||||
// 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);
|
||||
if ((chk ^ decodeDos33a[0]) != 0)
|
||||
throw new DiskNibbleException ("Checksum failed");
|
||||
|
||||
// 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];
|
||||
|
||||
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)
|
||||
{
|
||||
System.out.println (e);
|
||||
}
|
||||
|
||||
return decodedBuffer;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// encodeSector
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
// convert 256 data bytes into 342 translated bytes plus a checksum
|
||||
@Override
|
||||
byte[] encodeSector (byte[] buffer)
|
||||
{
|
||||
byte[] encodedBuffer = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
|
||||
|
||||
// move data buffer down to make room for the 86 extra bytes
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
encodeDos33a[i + 86] = buffer[i];
|
||||
|
||||
// build extra 86 bytes from the bits stripped from the data bytes
|
||||
for (int i = 0; i < 86; i++)
|
||||
{
|
||||
int b1 = reverse (buffer[i] & 0x03) << 2;
|
||||
int b2 = reverse (buffer[i + 86] & 0x03) << 4;
|
||||
|
||||
if (i < 84)
|
||||
{
|
||||
int b3 = reverse (buffer[i + 172] & 0x03) << 6;
|
||||
encodeDos33a[i] = (byte) (b1 | b2 | b3);
|
||||
}
|
||||
else
|
||||
encodeDos33a[i] = (byte) (b1 | b2);
|
||||
}
|
||||
|
||||
// convert into checksum bytes
|
||||
byte checksum = 0;
|
||||
for (int i = 0; i < RAW_BUFFER_SIZE_DOS_33; i++)
|
||||
{
|
||||
encodeDos33b[i] = (byte) (checksum ^ encodeDos33a[i]);
|
||||
checksum = encodeDos33a[i];
|
||||
}
|
||||
encodeDos33b[RAW_BUFFER_SIZE_DOS_33] = checksum; // add checksum to the end
|
||||
|
||||
// remove two bits and convert to translated bytes
|
||||
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++)
|
||||
encodedBuffer[i] = byteTranslator62.encode (encodeDos33b[i]);
|
||||
|
||||
return encodedBuffer;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// reverse
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
// reverse 2 bits - 0 <= bits <= 3
|
||||
private static int reverse (int bits)
|
||||
{
|
||||
return bits == 1 ? 2 : bits == 2 ? 1 : bits;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// storeBuffer
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
void storeBuffer (DiskSector diskSector, byte[] diskBuffer)
|
||||
{
|
||||
DiskAddressField addressField = diskSector.addressField;
|
||||
byte[] sectorBuffer = diskSector.buffer;
|
||||
int offset = addressField.track * 0x1000 + interleave[addressField.sector] * 256;
|
||||
System.arraycopy (sectorBuffer, 0, diskBuffer, offset, 256);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// expectedDataSize
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
@Override
|
||||
int expectedDataSize ()
|
||||
{
|
||||
return 343;
|
||||
}
|
||||
}
|
229
src/com/bytezone/diskbrowser/disk/MC3470.java
Normal file
229
src/com/bytezone/diskbrowser/disk/MC3470.java
Normal file
@ -0,0 +1,229 @@
|
||||
package com.bytezone.diskbrowser.disk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class MC3470
|
||||
{
|
||||
private final boolean debug = false;
|
||||
|
||||
private final byte[] dataBuffer = new byte[411];
|
||||
int dataPtr = 0;
|
||||
|
||||
private final List<DiskSector> diskSectors = new ArrayList<> ();
|
||||
DiskReader diskReader;
|
||||
|
||||
State currentState;
|
||||
DiskSector currentDiskSector;
|
||||
int expectedDataSize;
|
||||
|
||||
DiskReader diskReader16 = new DiskReader16Sector ();
|
||||
DiskReader diskReader13 = new DiskReader13Sector ();
|
||||
|
||||
enum State
|
||||
{
|
||||
ADDRESS, DATA, OTHER
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// readTrack
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
void readTrack (byte[] buffer, int offset, int bytesUsed, int bitCount)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
final int max = offset + bytesUsed;
|
||||
int totalBits = 0;
|
||||
|
||||
diskSectors.clear ();
|
||||
currentDiskSector = null;
|
||||
currentState = State.OTHER;
|
||||
|
||||
if (debug)
|
||||
{
|
||||
System.out.printf ("%nOffset : %06X%n", offset);
|
||||
System.out.printf ("Bytes used: %06X%n", bytesUsed);
|
||||
}
|
||||
|
||||
int inPtr = offset;
|
||||
while (inPtr < max)
|
||||
{
|
||||
int b = buffer[inPtr++] & 0xFF;
|
||||
for (int mask = 0x80; mask != 0; mask >>>= 1)
|
||||
{
|
||||
value <<= 1;
|
||||
if ((b & mask) != 0)
|
||||
value |= 1;
|
||||
|
||||
++totalBits;
|
||||
|
||||
if ((value & 0x80) != 0) // is hi-bit set?
|
||||
{
|
||||
dataBuffer[dataPtr++] = (byte) value;
|
||||
checkState (value);
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
if (inPtr == max && currentState == State.DATA)
|
||||
{
|
||||
System.out.println ("Unfinished business");
|
||||
}
|
||||
}
|
||||
|
||||
// if (bytesUsed > outputBuffer.length)
|
||||
// {
|
||||
// System.out.printf ("Bytes used %,5d%n", bytesUsed);
|
||||
// System.out.printf ("Buffer size %,5d%n", outPtr);
|
||||
// }
|
||||
|
||||
if (value != 0)
|
||||
System.out.printf ("********** Value not used: %01X%n", value);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// storeSectors
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
void storeSectors (byte[] diskBuffer)
|
||||
{
|
||||
for (DiskSector diskSector : diskSectors)
|
||||
diskReader.storeBuffer (diskSector, diskBuffer);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// checkState
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private void checkState (int value)
|
||||
{
|
||||
if (value == 0xB5 && isPrologue ())
|
||||
{
|
||||
diskReader = diskReader13;
|
||||
setState (State.ADDRESS);
|
||||
}
|
||||
|
||||
if (value == 0x96 && isPrologue ())
|
||||
{
|
||||
diskReader = diskReader16;
|
||||
setState (State.ADDRESS);
|
||||
}
|
||||
|
||||
if (value == 0xAD && isPrologue ())
|
||||
setState (State.DATA);
|
||||
|
||||
if (value == 0xEB && isEpilogue ())
|
||||
setState (State.OTHER);
|
||||
|
||||
if (dataPtr == expectedDataSize)
|
||||
setState (State.OTHER);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// setState
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private void setState (State newState)
|
||||
{
|
||||
if (currentState == newState && currentState == State.OTHER)
|
||||
return;
|
||||
assert currentState != newState;
|
||||
|
||||
switch (currentState) // this state is now finished
|
||||
{
|
||||
case ADDRESS:
|
||||
currentDiskSector = new DiskSector (new DiskAddressField (dataBuffer, 0));
|
||||
break;
|
||||
|
||||
case DATA:
|
||||
currentDiskSector.setBuffer (diskReader.decodeSector (dataBuffer, 0));
|
||||
diskSectors.add (currentDiskSector);
|
||||
break;
|
||||
|
||||
case OTHER:
|
||||
break;
|
||||
}
|
||||
|
||||
currentState = newState;
|
||||
dataPtr = 0; // start collecting new buffer
|
||||
|
||||
switch (currentState) // this state is now starting
|
||||
{
|
||||
case ADDRESS:
|
||||
expectedDataSize = 8;
|
||||
break;
|
||||
|
||||
case DATA:
|
||||
expectedDataSize = diskReader.expectedDataSize ();
|
||||
break;
|
||||
|
||||
case OTHER:
|
||||
expectedDataSize = -1; // unspecified length
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// is13Sector
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
boolean is13Sector ()
|
||||
{
|
||||
return diskSectors.size () == 13 && diskReader.sectorsPerTrack == 13;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// is16Sector
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
boolean is16Sector ()
|
||||
{
|
||||
return diskSectors.size () == 16 && diskReader.sectorsPerTrack == 16;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// isPrologue
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private boolean isPrologue ()
|
||||
{
|
||||
return dataPtr >= 3 && dataBuffer[dataPtr - 3] == (byte) 0xD5
|
||||
&& dataBuffer[dataPtr - 2] == (byte) 0xAA;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// isEpilogue
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private boolean isEpilogue ()
|
||||
{
|
||||
return dataPtr >= 3 && dataBuffer[dataPtr - 3] == (byte) 0xDE
|
||||
&& dataBuffer[dataPtr - 2] == (byte) 0xAA;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// DiskSector
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
class DiskSector
|
||||
{
|
||||
DiskAddressField addressField;
|
||||
byte[] buffer;
|
||||
|
||||
DiskSector (DiskAddressField addressField)
|
||||
{
|
||||
this.addressField = addressField;
|
||||
}
|
||||
|
||||
void setBuffer (byte[] buffer)
|
||||
{
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return addressField.toString ();
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ package com.bytezone.diskbrowser.disk;
|
||||
|
||||
class Nibblizer
|
||||
{
|
||||
// still used by NibDisk and V2dDisk
|
||||
|
||||
private static byte[] addressPrologue32 = { (byte) 0xD5, (byte) 0xAA, (byte) 0xB5 };
|
||||
private static byte[] addressPrologue33 = { (byte) 0xD5, (byte) 0xAA, (byte) 0x96 };
|
||||
private static byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
|
||||
@ -11,53 +13,13 @@ class Nibblizer
|
||||
{ 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
|
||||
|
||||
private static final int BLOCK_SIZE = 256;
|
||||
private static final int TRACK_SIZE = 4096;
|
||||
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;
|
||||
|
||||
// 32 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
|
||||
private static byte[] writeTranslateTable5and3 =
|
||||
{ (byte) 0xAB, (byte) 0xAD, (byte) 0xAE, (byte) 0xAF, (byte) 0xB5, (byte) 0xB6,
|
||||
(byte) 0xB7, (byte) 0xBA, (byte) 0xBB, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF,
|
||||
(byte) 0xD6, (byte) 0xD7, (byte) 0xDA, (byte) 0xDB, //
|
||||
(byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xEA, (byte) 0xEB, (byte) 0xED,
|
||||
(byte) 0xEE, (byte) 0xEF, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xFA,
|
||||
(byte) 0xFB, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
|
||||
|
||||
// 64 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
|
||||
private static byte[] writeTranslateTable6and2 =
|
||||
{ (byte) 0x96, (byte) 0x97, (byte) 0x9A, (byte) 0x9B, (byte) 0x9D, (byte) 0x9E,
|
||||
(byte) 0x9F, (byte) 0xA6, (byte) 0xA7, (byte) 0xAB, (byte) 0xAC, (byte) 0xAD,
|
||||
(byte) 0xAE, (byte) 0xAF, (byte) 0xB2, (byte) 0xB3, //
|
||||
(byte) 0xB4, (byte) 0xB5, (byte) 0xB6, (byte) 0xB7, (byte) 0xB9, (byte) 0xBA,
|
||||
(byte) 0xBB, (byte) 0xBC, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF, (byte) 0xCB,
|
||||
(byte) 0xCD, (byte) 0xCE, (byte) 0xCF, (byte) 0xD3, //
|
||||
(byte) 0xD6, (byte) 0xD7, (byte) 0xD9, (byte) 0xDA, (byte) 0xDB, (byte) 0xDC,
|
||||
(byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xE5, (byte) 0xE6, (byte) 0xE7,
|
||||
(byte) 0xE9, (byte) 0xEA, (byte) 0xEB, (byte) 0xEC, //
|
||||
(byte) 0xED, (byte) 0xEE, (byte) 0xEF, (byte) 0xF2, (byte) 0xF3, (byte) 0xF4,
|
||||
(byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB,
|
||||
(byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
|
||||
|
||||
private static byte[] readTranslateTable5and3 = new byte[85]; // skip first 171 blanks
|
||||
private static byte[] readTranslateTable6and2 = new byte[106]; // skip first 150 blanks
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < writeTranslateTable5and3.length; i++)
|
||||
{
|
||||
int j = (writeTranslateTable5and3[i] & 0xFF) - 0xAB; // skip first 171 blanks
|
||||
readTranslateTable5and3[j] = (byte) (i + 1); // offset by 1 to avoid zero
|
||||
}
|
||||
|
||||
for (int i = 0; i < writeTranslateTable6and2.length; i++)
|
||||
{
|
||||
int j = (writeTranslateTable6and2[i] & 0xFF) - 0x96; // skip first 150 blanks
|
||||
readTranslateTable6and2[j] = (byte) (i + 1); // offset by 1 to avoid zero
|
||||
}
|
||||
}
|
||||
private final ByteTranslator byteTranslator62 = new ByteTranslator6and2 ();
|
||||
private final ByteTranslator byteTranslator53 = new ByteTranslator5and3 ();
|
||||
|
||||
private final byte[] decodeDos33a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
|
||||
private final byte[] decodeDos33b = new byte[RAW_BUFFER_SIZE_DOS_33];
|
||||
@ -68,52 +30,35 @@ class Nibblizer
|
||||
private final byte[] decodeDos32a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_32];
|
||||
private final byte[] decodeDos32b = new byte[RAW_BUFFER_SIZE_DOS_32];
|
||||
|
||||
enum DosVersion
|
||||
{
|
||||
DOS_3_2, DOS_3_3
|
||||
}
|
||||
|
||||
private DosVersion currentDosVersion;
|
||||
int sectorsPerTrack;
|
||||
private int sectorsPerTrack;
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// processTrack
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
boolean processTrack (int trackNo, byte[] buffer, byte[] diskBuffer)
|
||||
boolean processTrack (int trackNo, int maxTracks, byte[] buffer, byte[] diskBuffer)
|
||||
{
|
||||
int ptr = 0;
|
||||
int totalSectors = 0;
|
||||
boolean[] sectorsFound = new boolean[16];
|
||||
sectorsPerTrack = maxTracks;
|
||||
|
||||
try
|
||||
{
|
||||
while (ptr < buffer.length)
|
||||
{
|
||||
int ptr2 = findBytes (buffer, ptr, addressPrologue33);
|
||||
if (ptr2 >= 0)
|
||||
{
|
||||
currentDosVersion = DosVersion.DOS_3_3;
|
||||
sectorsPerTrack = 16;
|
||||
}
|
||||
if (sectorsPerTrack == 13)
|
||||
ptr = findBytes (buffer, ptr, addressPrologue32);
|
||||
else
|
||||
{
|
||||
ptr2 = findBytes (buffer, ptr, addressPrologue32);
|
||||
if (ptr2 >= 0)
|
||||
{
|
||||
currentDosVersion = DosVersion.DOS_3_2;
|
||||
sectorsPerTrack = 13;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.printf ("Track: %02X/%02X - Address prologue not found%n", trackNo,
|
||||
totalSectors);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ptr = ptr2;
|
||||
ptr = findBytes (buffer, ptr, addressPrologue33);
|
||||
|
||||
AddressField addressField = getAddressField (buffer, ptr);
|
||||
if (ptr < 0)
|
||||
{
|
||||
System.out.printf ("Track: %02X - Address prologue not found%n", trackNo);
|
||||
return false;
|
||||
}
|
||||
|
||||
AddressField addressField = new AddressField (buffer, ptr);
|
||||
if (!addressField.isValid ())
|
||||
{
|
||||
System.out.printf ("Track: %02X - Invalid address field%n", trackNo);
|
||||
@ -145,26 +90,23 @@ class Nibblizer
|
||||
return false;
|
||||
}
|
||||
|
||||
DataField dataField = getDataField (buffer, ptr);
|
||||
DataField dataField = new DataField (buffer, ptr);
|
||||
if (!dataField.isValid ())
|
||||
{
|
||||
System.out.printf ("Track: %02X - Invalid data field%n", trackNo);
|
||||
return false;
|
||||
}
|
||||
|
||||
int offset = addressField.track * TRACK_SIZE;
|
||||
if (currentDosVersion == DosVersion.DOS_3_2)
|
||||
offset += addressField.sector * BLOCK_SIZE;
|
||||
int offset;
|
||||
if (sectorsPerTrack == 13)
|
||||
offset = addressField.track * 0x0D00 + addressField.sector * BLOCK_SIZE;
|
||||
else
|
||||
offset += interleave[addressField.sector] * BLOCK_SIZE;
|
||||
offset =
|
||||
addressField.track * 0x1000 + interleave[addressField.sector] * BLOCK_SIZE;
|
||||
|
||||
System.arraycopy (dataField.dataBuffer, 0, diskBuffer, offset, BLOCK_SIZE);
|
||||
|
||||
++totalSectors;
|
||||
|
||||
if (currentDosVersion == DosVersion.DOS_3_2 && totalSectors == 13)
|
||||
break;
|
||||
if (currentDosVersion == DosVersion.DOS_3_3 && totalSectors == 16)
|
||||
if (++totalSectors == sectorsPerTrack)
|
||||
break;
|
||||
|
||||
ptr += dataField.size ();
|
||||
@ -175,13 +117,7 @@ class Nibblizer
|
||||
e.printStackTrace ();
|
||||
}
|
||||
|
||||
if (currentDosVersion == DosVersion.DOS_3_2 && totalSectors != 13)
|
||||
{
|
||||
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (currentDosVersion == DosVersion.DOS_3_3 && totalSectors != 16)
|
||||
if (totalSectors != sectorsPerTrack)
|
||||
{
|
||||
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
|
||||
return false;
|
||||
@ -190,24 +126,6 @@ class Nibblizer
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// getAddressField
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private AddressField getAddressField (byte[] buffer, int offset)
|
||||
{
|
||||
return new AddressField (buffer, offset);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// getDataField
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private DataField getDataField (byte[] buffer, int offset)
|
||||
{
|
||||
return new DataField (buffer, offset);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// decode4and4
|
||||
// ---------------------------------------------------------------------------------//
|
||||
@ -225,113 +143,105 @@ class Nibblizer
|
||||
|
||||
private byte[] decode5and3 (byte[] buffer, int offset)
|
||||
{
|
||||
// convert legal disk values to actual 5 bit values
|
||||
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_32; i++) // 411 bytes
|
||||
decodeDos32a[i] = getByte5and3 (buffer[offset++]);
|
||||
|
||||
// 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;
|
||||
|
||||
// rearrange 410 bytes into 256
|
||||
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
|
||||
byte[] k = new byte[8];
|
||||
ptr = 0;
|
||||
int[] lines = { 0, 51, 102, 153, 204, 256, 307, 358 }; // NB 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--)
|
||||
try
|
||||
{
|
||||
for (int j = 0; j < 8; j++)
|
||||
k[j] = decodeDos32b[i + lines[j]];
|
||||
// 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]);
|
||||
decodeDos32a[i] = byteTranslator53.decode (buffer[offset++]);
|
||||
}
|
||||
|
||||
k[0] |= (k[5] & 0xE0) >>> 5;
|
||||
k[1] |= (k[6] & 0xE0) >>> 5;
|
||||
k[2] |= (k[7] & 0xE0) >>> 5;
|
||||
// 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;
|
||||
|
||||
k[3] |= (k[5] & 0x10) >>> 2;
|
||||
k[3] |= (k[6] & 0x10) >>> 3;
|
||||
k[3] |= (k[7] & 0x10) >>> 4;
|
||||
byte[] k = new byte[8];
|
||||
ptr = 0;
|
||||
final int[] lines = { 0, 51, 102, 153, 204, 256, 307, 358 }; // 255 is skipped
|
||||
|
||||
k[4] |= (k[5] & 0x08) >>> 1;
|
||||
k[4] |= (k[6] & 0x08) >>> 2;
|
||||
k[4] |= (k[7] & 0x08) >>> 3;
|
||||
// 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]];
|
||||
|
||||
k[0] |= (k[5] & 0xE0) >>> 5;
|
||||
k[1] |= (k[6] & 0xE0) >>> 5;
|
||||
k[2] |= (k[7] & 0xE0) >>> 5;
|
||||
|
||||
k[3] |= (k[5] & 0x10) >>> 2;
|
||||
k[3] |= (k[6] & 0x10) >>> 3;
|
||||
k[3] |= (k[7] & 0x10) >>> 4;
|
||||
|
||||
k[4] |= (k[5] & 0x08) >>> 1;
|
||||
k[4] |= (k[6] & 0x08) >>> 2;
|
||||
k[4] |= (k[7] & 0x08) >>> 3;
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
decodedBuffer[ptr++] = k[j];
|
||||
}
|
||||
|
||||
// add last byte
|
||||
decodedBuffer[255] = (byte) (decodeDos32b[255] | (decodeDos32b[409] >>> 3));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
decodedBuffer[ptr++] = k[j];
|
||||
}
|
||||
|
||||
// add last byte
|
||||
decodedBuffer[255] = (byte) (decodeDos32b[255] | (decodeDos32b[409] >>> 3));
|
||||
|
||||
return decodedBuffer;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// getByte5and3
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private byte getByte5and3 (byte b)
|
||||
{
|
||||
int val = (b & 0xFF) - 0xAB; // 0 - 84
|
||||
assert val >= 0 && val <= 84;
|
||||
byte trans = (byte) (readTranslateTable5and3[val] - 1); // 0 - 31 (5 bits)
|
||||
assert trans >= 0 && trans <= 31;
|
||||
return (byte) (trans << 3); // left justify 5 bits
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// getByte6and2
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private byte getByte6and2 (byte b)
|
||||
{
|
||||
int val = (b & 0xFF) - 0x96; // 0 - 105
|
||||
assert val >= 0 && val <= 105;
|
||||
byte trans = (byte) (readTranslateTable6and2[val] - 1); // 0 - 63 (6 bits)
|
||||
assert trans >= 0 && trans <= 63;
|
||||
return (byte) (trans << 2); // left justify 6 bits
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// decode6and2
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private byte[] decode6and2 (byte[] buffer, int offset)
|
||||
{
|
||||
// convert legal disk values to actual 6 bit values
|
||||
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++) // 343 bytes
|
||||
decodeDos33a[i] = getByte6and2 (buffer[offset++]);
|
||||
|
||||
// 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;
|
||||
|
||||
// rearrange 342 bytes into 256
|
||||
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
|
||||
|
||||
// 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++)
|
||||
try
|
||||
{
|
||||
byte val = decodeDos33b[i];
|
||||
// convert legal disk values to actual 6 bit values
|
||||
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++) // 343 bytes
|
||||
decodeDos33a[i] = byteTranslator62.decode (buffer[offset++]);
|
||||
|
||||
decodedBuffer[i] |= reverse ((val & 0x0C) >> 2);
|
||||
decodedBuffer[j] |= reverse ((val & 0x30) >> 4);
|
||||
// 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];
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
if (k < BLOCK_SIZE)
|
||||
decodedBuffer[k] |= reverse ((val & 0xC0) >> 6);
|
||||
}
|
||||
|
||||
return decodedBuffer;
|
||||
@ -376,7 +286,8 @@ class Nibblizer
|
||||
|
||||
// remove two bits and convert to translated bytes
|
||||
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++)
|
||||
encodedBuffer[i] = writeTranslateTable6and2[(encodeDos33b[i] & 0xFC) / 4];
|
||||
// encodedBuffer[i] = writeTranslateTable6and2[(encodeDos33b[i] & 0xFC) / 4];
|
||||
encodedBuffer[i] = byteTranslator62.encode (encodeDos33b[i]);
|
||||
|
||||
return encodedBuffer;
|
||||
}
|
||||
@ -496,17 +407,11 @@ class Nibblizer
|
||||
{
|
||||
super (buffer, offset);
|
||||
|
||||
// if (matchBytes (buffer, offset, addressPrologue33))
|
||||
// // && matchBytes (buffer, offset + 11, epilogue))
|
||||
// {
|
||||
volume = decode4and4 (buffer, offset + 3);
|
||||
track = decode4and4 (buffer, offset + 5);
|
||||
sector = decode4and4 (buffer, offset + 7);
|
||||
checksum = decode4and4 (buffer, offset + 9);
|
||||
valid = true;
|
||||
// }
|
||||
// else
|
||||
// System.out.println (listBytes (buffer, offset, 14));
|
||||
|
||||
length = 14;
|
||||
}
|
||||
@ -534,10 +439,10 @@ class Nibblizer
|
||||
if (matchBytes (buffer, offset, dataPrologue))
|
||||
{
|
||||
valid = true;
|
||||
if (currentDosVersion == DosVersion.DOS_3_3)
|
||||
dataBuffer = decode6and2 (buffer, offset + 3);
|
||||
else if (currentDosVersion == DosVersion.DOS_3_2)
|
||||
if (sectorsPerTrack == 13)
|
||||
dataBuffer = decode5and3 (buffer, offset + 3);
|
||||
else
|
||||
dataBuffer = decode6and2 (buffer, offset + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ class V2dDisk
|
||||
int halfTrackNo = trackNumber % 4;
|
||||
|
||||
if (halfTrackNo == 0) // only process full tracks
|
||||
nibbler.processTrack (fullTrackNo, trackData, diskBuffer);
|
||||
nibbler.processTrack (fullTrackNo, 16, trackData, diskBuffer);
|
||||
else
|
||||
System.out.printf ("%s skipping half track %02X / %02X%n", file.getName (),
|
||||
fullTrackNo, halfTrackNo);
|
||||
|
@ -10,18 +10,20 @@ import com.bytezone.diskbrowser.utilities.Utility;
|
||||
|
||||
class WozDisk
|
||||
{
|
||||
private static final byte[] WOZ_DISK_HEADER =
|
||||
{ 0x57, 0x4F, 0x5A, 0x31, (byte) 0xFF, 0x0a, 0x0D, 0x0A };
|
||||
private static final int TRK_SIZE = 0x1A00;
|
||||
private static final int INFO_SIZE = 0x3C;
|
||||
private static final int TMAP_SIZE = 0xA0;
|
||||
private static final int DATA_SIZE = TRK_SIZE - 10;
|
||||
private static byte[] header =
|
||||
{ 0x57, 0x4F, 0x5A, 0x31, (byte) 0xFF, 0x0a, 0x0D, 0x0A };
|
||||
|
||||
private final boolean debug = false;
|
||||
private int diskType; // 5.25 or 3.5
|
||||
int sectorsPerTrack;
|
||||
|
||||
final File file;
|
||||
final byte[] diskBuffer = new byte[4096 * 35];
|
||||
byte[] diskBuffer;
|
||||
|
||||
private final MC3470 mc3470 = new MC3470 ();
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// constructor
|
||||
@ -30,10 +32,9 @@ class WozDisk
|
||||
public WozDisk (File file) throws Exception
|
||||
{
|
||||
this.file = file;
|
||||
Nibblizer nibbler = new Nibblizer ();
|
||||
byte[] buffer = readFile ();
|
||||
|
||||
if (!matches (header, buffer))
|
||||
if (!matches (WOZ_DISK_HEADER, buffer))
|
||||
throw new Exception ("Header error");
|
||||
|
||||
int cs1 = readInt (buffer, 8, 4);
|
||||
@ -88,7 +89,8 @@ class WozDisk
|
||||
if (debug)
|
||||
System.out.println ("Reading TRKS");
|
||||
int tracks = chunkSize / TRK_SIZE;
|
||||
for (int track = 0; track < tracks; track++)
|
||||
|
||||
for (int trackNo = 0; trackNo < tracks; trackNo++)
|
||||
{
|
||||
int bytesUsed = readInt (buffer, ptr + DATA_SIZE, 2);
|
||||
int bitCount = readInt (buffer, ptr + DATA_SIZE + 2, 2);
|
||||
@ -99,22 +101,37 @@ class WozDisk
|
||||
System.out.printf ("Bit count .... %,6d%n", bitCount);
|
||||
}
|
||||
|
||||
byte[] trackData = readTrack (buffer, ptr, bytesUsed, bitCount);
|
||||
if (!nibbler.processTrack (track, trackData, diskBuffer))
|
||||
try
|
||||
{
|
||||
System.out.println ("Nibblizer failure");
|
||||
if (debug)
|
||||
System.out.println (HexFormatter.format (trackData));
|
||||
break read;
|
||||
mc3470.readTrack (buffer, ptr, bytesUsed, bitCount);
|
||||
|
||||
if (trackNo == 0)
|
||||
{
|
||||
if (mc3470.is13Sector ())
|
||||
diskBuffer = new byte[35 * 13 * 256];
|
||||
else if (mc3470.is16Sector ())
|
||||
diskBuffer = new byte[35 * 16 * 256];
|
||||
else
|
||||
{
|
||||
System.out.println ("unknown disk format");
|
||||
break read;
|
||||
}
|
||||
}
|
||||
|
||||
mc3470.storeSectors (diskBuffer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace ();
|
||||
}
|
||||
|
||||
ptr += TRK_SIZE;
|
||||
if (track == 0)
|
||||
sectorsPerTrack = nibbler.sectorsPerTrack;
|
||||
}
|
||||
}
|
||||
else if ("META".equals (chunkId))
|
||||
{
|
||||
System.out.printf ("[%s] %08X%n", chunkId, chunkSize);
|
||||
System.out.println (HexFormatter.format (buffer, ptr, chunkSize));
|
||||
ptr += chunkSize;
|
||||
}
|
||||
else
|
||||
@ -125,6 +142,15 @@ class WozDisk
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// getSectorsPerTrack
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
int getSectorsPerTrack ()
|
||||
{
|
||||
return mc3470.is13Sector () ? 13 : 16;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// readInt
|
||||
// ---------------------------------------------------------------------------------//
|
||||
@ -141,48 +167,6 @@ class WozDisk
|
||||
return value;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// readTrack
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
||||
private byte[] readTrack (byte[] buffer, int offset, int bytesUsed, int bitCount)
|
||||
{
|
||||
byte[] trackData = new byte[bytesUsed];
|
||||
int value = 0;
|
||||
int ptr = 0;
|
||||
final int max = offset + bytesUsed;
|
||||
int count = 0;
|
||||
|
||||
for (int i = offset; i < max; i++)
|
||||
{
|
||||
int b = buffer[i] & 0xFF;
|
||||
for (int mask = 0x80; mask > 0; mask >>>= 1)
|
||||
{
|
||||
value <<= 1;
|
||||
if ((b & mask) != 0)
|
||||
value |= 1;
|
||||
|
||||
++count;
|
||||
|
||||
if ((value & 0x80) != 0) // is hi-bit set?
|
||||
{
|
||||
trackData[ptr++] = (byte) value;
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value != 0)
|
||||
System.out.printf ("********** Value not used: %01X%n", value);
|
||||
if (debug && bitCount != count)
|
||||
{
|
||||
System.out.printf ("BitCount: %,4d%n", bitCount);
|
||||
System.out.printf ("Actual : %,4d%n", count);
|
||||
}
|
||||
|
||||
return trackData;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------//
|
||||
// readFile
|
||||
// ---------------------------------------------------------------------------------//
|
||||
|
Loading…
x
Reference in New Issue
Block a user