mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2025-02-21 11:28:58 +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);
|
public final SectorType macSector = new SectorType ("MAC", Color.green);
|
||||||
|
|
||||||
private int version; // http://www.seasip.info/Cpm/format22.html
|
private int version; // http://www.seasip.info/Cpm/format22.html
|
||||||
|
// // http://www.seasip.info/Cpm/format31.html
|
||||||
|
|
||||||
public CPMDisk (Disk disk)
|
public CPMDisk (Disk disk)
|
||||||
{
|
{
|
||||||
|
@ -231,30 +231,16 @@ public class AppleDisk implements Disk
|
|||||||
this.tracks = tracks;
|
this.tracks = tracks;
|
||||||
this.sectors = sectors;
|
this.sectors = sectors;
|
||||||
file = disk.file;
|
file = disk.file;
|
||||||
|
diskBuffer = disk.diskBuffer;
|
||||||
|
|
||||||
if (sectors == 13)
|
if (sectors == 13)
|
||||||
{
|
{
|
||||||
trackSize = 0xD00;
|
trackSize = 0xD00;
|
||||||
sectorSize = 256;
|
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
|
else
|
||||||
{
|
{
|
||||||
trackSize = 4096;
|
trackSize = 0x1000;
|
||||||
diskBuffer = disk.diskBuffer;
|
|
||||||
sectorSize = trackSize / sectors;
|
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
|
try
|
||||||
{
|
{
|
||||||
WozDisk wozDisk = new WozDisk (file);
|
WozDisk wozDisk = new WozDisk (file);
|
||||||
if (wozDisk.sectorsPerTrack == 13)
|
if (wozDisk.getSectorsPerTrack () == 13)
|
||||||
{
|
{
|
||||||
AppleDisk appleDisk = new AppleDisk (wozDisk, 35, 13);
|
AppleDisk appleDisk = new AppleDisk (wozDisk, 35, 13);
|
||||||
disk = checkDos (appleDisk);
|
disk = checkDos (appleDisk);
|
||||||
@ -248,7 +248,8 @@ public class DiskFactory
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
System.out.println (e);
|
// System.out.println (e);
|
||||||
|
e.printStackTrace ();
|
||||||
return null;
|
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
|
class Nibblizer
|
||||||
{
|
{
|
||||||
|
// still used by NibDisk and V2dDisk
|
||||||
|
|
||||||
private static byte[] addressPrologue32 = { (byte) 0xD5, (byte) 0xAA, (byte) 0xB5 };
|
private static byte[] addressPrologue32 = { (byte) 0xD5, (byte) 0xAA, (byte) 0xB5 };
|
||||||
private static byte[] addressPrologue33 = { (byte) 0xD5, (byte) 0xAA, (byte) 0x96 };
|
private static byte[] addressPrologue33 = { (byte) 0xD5, (byte) 0xAA, (byte) 0x96 };
|
||||||
private static byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
|
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 };
|
{ 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 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_33 = 342;
|
||||||
private static final int RAW_BUFFER_SIZE_DOS_32 = 410;
|
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_33 = RAW_BUFFER_SIZE_DOS_33 + 1;
|
||||||
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_32 = RAW_BUFFER_SIZE_DOS_32 + 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 final ByteTranslator byteTranslator62 = new ByteTranslator6and2 ();
|
||||||
private static byte[] writeTranslateTable5and3 =
|
private final ByteTranslator byteTranslator53 = new ByteTranslator5and3 ();
|
||||||
{ (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 byte[] decodeDos33a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
|
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[] 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[] decodeDos32a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_32];
|
||||||
private final byte[] decodeDos32b = new byte[RAW_BUFFER_SIZE_DOS_32];
|
private final byte[] decodeDos32b = new byte[RAW_BUFFER_SIZE_DOS_32];
|
||||||
|
|
||||||
enum DosVersion
|
private int sectorsPerTrack;
|
||||||
{
|
|
||||||
DOS_3_2, DOS_3_3
|
|
||||||
}
|
|
||||||
|
|
||||||
private DosVersion currentDosVersion;
|
|
||||||
int sectorsPerTrack;
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
// processTrack
|
// processTrack
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
||||||
boolean processTrack (int trackNo, byte[] buffer, byte[] diskBuffer)
|
boolean processTrack (int trackNo, int maxTracks, byte[] buffer, byte[] diskBuffer)
|
||||||
{
|
{
|
||||||
int ptr = 0;
|
int ptr = 0;
|
||||||
int totalSectors = 0;
|
int totalSectors = 0;
|
||||||
boolean[] sectorsFound = new boolean[16];
|
boolean[] sectorsFound = new boolean[16];
|
||||||
|
sectorsPerTrack = maxTracks;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (ptr < buffer.length)
|
while (ptr < buffer.length)
|
||||||
{
|
{
|
||||||
int ptr2 = findBytes (buffer, ptr, addressPrologue33);
|
if (sectorsPerTrack == 13)
|
||||||
if (ptr2 >= 0)
|
ptr = findBytes (buffer, ptr, addressPrologue32);
|
||||||
{
|
|
||||||
currentDosVersion = DosVersion.DOS_3_3;
|
|
||||||
sectorsPerTrack = 16;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
ptr = findBytes (buffer, ptr, addressPrologue33);
|
||||||
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;
|
|
||||||
|
|
||||||
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 ())
|
if (!addressField.isValid ())
|
||||||
{
|
{
|
||||||
System.out.printf ("Track: %02X - Invalid address field%n", trackNo);
|
System.out.printf ("Track: %02X - Invalid address field%n", trackNo);
|
||||||
@ -145,26 +90,23 @@ class Nibblizer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataField dataField = getDataField (buffer, ptr);
|
DataField dataField = new DataField (buffer, ptr);
|
||||||
if (!dataField.isValid ())
|
if (!dataField.isValid ())
|
||||||
{
|
{
|
||||||
System.out.printf ("Track: %02X - Invalid data field%n", trackNo);
|
System.out.printf ("Track: %02X - Invalid data field%n", trackNo);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = addressField.track * TRACK_SIZE;
|
int offset;
|
||||||
if (currentDosVersion == DosVersion.DOS_3_2)
|
if (sectorsPerTrack == 13)
|
||||||
offset += addressField.sector * BLOCK_SIZE;
|
offset = addressField.track * 0x0D00 + addressField.sector * BLOCK_SIZE;
|
||||||
else
|
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);
|
System.arraycopy (dataField.dataBuffer, 0, diskBuffer, offset, BLOCK_SIZE);
|
||||||
|
|
||||||
++totalSectors;
|
if (++totalSectors == sectorsPerTrack)
|
||||||
|
|
||||||
if (currentDosVersion == DosVersion.DOS_3_2 && totalSectors == 13)
|
|
||||||
break;
|
|
||||||
if (currentDosVersion == DosVersion.DOS_3_3 && totalSectors == 16)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ptr += dataField.size ();
|
ptr += dataField.size ();
|
||||||
@ -175,13 +117,7 @@ class Nibblizer
|
|||||||
e.printStackTrace ();
|
e.printStackTrace ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentDosVersion == DosVersion.DOS_3_2 && totalSectors != 13)
|
if (totalSectors != sectorsPerTrack)
|
||||||
{
|
|
||||||
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentDosVersion == DosVersion.DOS_3_3 && totalSectors != 16)
|
|
||||||
{
|
{
|
||||||
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
|
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
|
||||||
return false;
|
return false;
|
||||||
@ -190,24 +126,6 @@ class Nibblizer
|
|||||||
return true;
|
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
|
// decode4and4
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
@ -225,113 +143,105 @@ class Nibblizer
|
|||||||
|
|
||||||
private byte[] decode5and3 (byte[] buffer, int offset)
|
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
|
// rearrange 410 bytes into 256
|
||||||
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
|
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
|
try
|
||||||
// do this 51 times, giving 255 bytes
|
|
||||||
for (int i = 50; i >= 0; i--)
|
|
||||||
{
|
{
|
||||||
for (int j = 0; j < 8; j++)
|
// convert legal disk values to actual 5 bit values
|
||||||
k[j] = decodeDos32b[i + lines[j]];
|
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;
|
// reconstruct 410 bytes each with 5 bits
|
||||||
k[1] |= (k[6] & 0xE0) >>> 5;
|
byte chk = 0;
|
||||||
k[2] |= (k[7] & 0xE0) >>> 5;
|
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;
|
byte[] k = new byte[8];
|
||||||
k[3] |= (k[6] & 0x10) >>> 3;
|
ptr = 0;
|
||||||
k[3] |= (k[7] & 0x10) >>> 4;
|
final int[] lines = { 0, 51, 102, 153, 204, 256, 307, 358 }; // 255 is skipped
|
||||||
|
|
||||||
k[4] |= (k[5] & 0x08) >>> 1;
|
// process 8 disk bytes at a time, giving 5 valid bytes
|
||||||
k[4] |= (k[6] & 0x08) >>> 2;
|
// do this 51 times, giving 255 bytes
|
||||||
k[4] |= (k[7] & 0x08) >>> 3;
|
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;
|
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
|
// decode6and2
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
||||||
private byte[] decode6and2 (byte[] buffer, int offset)
|
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
|
// rearrange 342 bytes into 256
|
||||||
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
|
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
|
||||||
|
|
||||||
// move 6 bits into place
|
try
|
||||||
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];
|
// 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);
|
// reconstruct 342 bytes each with 6 bits
|
||||||
decodedBuffer[j] |= reverse ((val & 0x30) >> 4);
|
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;
|
return decodedBuffer;
|
||||||
@ -376,7 +286,8 @@ class Nibblizer
|
|||||||
|
|
||||||
// remove two bits and convert to translated bytes
|
// remove two bits and convert to translated bytes
|
||||||
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++)
|
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;
|
return encodedBuffer;
|
||||||
}
|
}
|
||||||
@ -496,17 +407,11 @@ class Nibblizer
|
|||||||
{
|
{
|
||||||
super (buffer, offset);
|
super (buffer, offset);
|
||||||
|
|
||||||
// if (matchBytes (buffer, offset, addressPrologue33))
|
|
||||||
// // && matchBytes (buffer, offset + 11, epilogue))
|
|
||||||
// {
|
|
||||||
volume = decode4and4 (buffer, offset + 3);
|
volume = decode4and4 (buffer, offset + 3);
|
||||||
track = decode4and4 (buffer, offset + 5);
|
track = decode4and4 (buffer, offset + 5);
|
||||||
sector = decode4and4 (buffer, offset + 7);
|
sector = decode4and4 (buffer, offset + 7);
|
||||||
checksum = decode4and4 (buffer, offset + 9);
|
checksum = decode4and4 (buffer, offset + 9);
|
||||||
valid = true;
|
valid = true;
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// System.out.println (listBytes (buffer, offset, 14));
|
|
||||||
|
|
||||||
length = 14;
|
length = 14;
|
||||||
}
|
}
|
||||||
@ -534,10 +439,10 @@ class Nibblizer
|
|||||||
if (matchBytes (buffer, offset, dataPrologue))
|
if (matchBytes (buffer, offset, dataPrologue))
|
||||||
{
|
{
|
||||||
valid = true;
|
valid = true;
|
||||||
if (currentDosVersion == DosVersion.DOS_3_3)
|
if (sectorsPerTrack == 13)
|
||||||
dataBuffer = decode6and2 (buffer, offset + 3);
|
|
||||||
else if (currentDosVersion == DosVersion.DOS_3_2)
|
|
||||||
dataBuffer = decode5and3 (buffer, offset + 3);
|
dataBuffer = decode5and3 (buffer, offset + 3);
|
||||||
|
else
|
||||||
|
dataBuffer = decode6and2 (buffer, offset + 3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -85,7 +85,7 @@ class V2dDisk
|
|||||||
int halfTrackNo = trackNumber % 4;
|
int halfTrackNo = trackNumber % 4;
|
||||||
|
|
||||||
if (halfTrackNo == 0) // only process full tracks
|
if (halfTrackNo == 0) // only process full tracks
|
||||||
nibbler.processTrack (fullTrackNo, trackData, diskBuffer);
|
nibbler.processTrack (fullTrackNo, 16, trackData, diskBuffer);
|
||||||
else
|
else
|
||||||
System.out.printf ("%s skipping half track %02X / %02X%n", file.getName (),
|
System.out.printf ("%s skipping half track %02X / %02X%n", file.getName (),
|
||||||
fullTrackNo, halfTrackNo);
|
fullTrackNo, halfTrackNo);
|
||||||
|
@ -10,18 +10,20 @@ import com.bytezone.diskbrowser.utilities.Utility;
|
|||||||
|
|
||||||
class WozDisk
|
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 TRK_SIZE = 0x1A00;
|
||||||
private static final int INFO_SIZE = 0x3C;
|
private static final int INFO_SIZE = 0x3C;
|
||||||
private static final int TMAP_SIZE = 0xA0;
|
private static final int TMAP_SIZE = 0xA0;
|
||||||
private static final int DATA_SIZE = TRK_SIZE - 10;
|
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 final boolean debug = false;
|
||||||
private int diskType; // 5.25 or 3.5
|
private int diskType; // 5.25 or 3.5
|
||||||
int sectorsPerTrack;
|
|
||||||
|
|
||||||
final File file;
|
final File file;
|
||||||
final byte[] diskBuffer = new byte[4096 * 35];
|
byte[] diskBuffer;
|
||||||
|
|
||||||
|
private final MC3470 mc3470 = new MC3470 ();
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
// constructor
|
// constructor
|
||||||
@ -30,10 +32,9 @@ class WozDisk
|
|||||||
public WozDisk (File file) throws Exception
|
public WozDisk (File file) throws Exception
|
||||||
{
|
{
|
||||||
this.file = file;
|
this.file = file;
|
||||||
Nibblizer nibbler = new Nibblizer ();
|
|
||||||
byte[] buffer = readFile ();
|
byte[] buffer = readFile ();
|
||||||
|
|
||||||
if (!matches (header, buffer))
|
if (!matches (WOZ_DISK_HEADER, buffer))
|
||||||
throw new Exception ("Header error");
|
throw new Exception ("Header error");
|
||||||
|
|
||||||
int cs1 = readInt (buffer, 8, 4);
|
int cs1 = readInt (buffer, 8, 4);
|
||||||
@ -88,7 +89,8 @@ class WozDisk
|
|||||||
if (debug)
|
if (debug)
|
||||||
System.out.println ("Reading TRKS");
|
System.out.println ("Reading TRKS");
|
||||||
int tracks = chunkSize / TRK_SIZE;
|
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 bytesUsed = readInt (buffer, ptr + DATA_SIZE, 2);
|
||||||
int bitCount = readInt (buffer, ptr + DATA_SIZE + 2, 2);
|
int bitCount = readInt (buffer, ptr + DATA_SIZE + 2, 2);
|
||||||
@ -99,22 +101,37 @@ class WozDisk
|
|||||||
System.out.printf ("Bit count .... %,6d%n", bitCount);
|
System.out.printf ("Bit count .... %,6d%n", bitCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] trackData = readTrack (buffer, ptr, bytesUsed, bitCount);
|
try
|
||||||
if (!nibbler.processTrack (track, trackData, diskBuffer))
|
|
||||||
{
|
{
|
||||||
System.out.println ("Nibblizer failure");
|
mc3470.readTrack (buffer, ptr, bytesUsed, bitCount);
|
||||||
if (debug)
|
|
||||||
System.out.println (HexFormatter.format (trackData));
|
if (trackNo == 0)
|
||||||
break read;
|
{
|
||||||
|
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;
|
ptr += TRK_SIZE;
|
||||||
if (track == 0)
|
|
||||||
sectorsPerTrack = nibbler.sectorsPerTrack;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ("META".equals (chunkId))
|
else if ("META".equals (chunkId))
|
||||||
{
|
{
|
||||||
System.out.printf ("[%s] %08X%n", chunkId, chunkSize);
|
System.out.printf ("[%s] %08X%n", chunkId, chunkSize);
|
||||||
|
System.out.println (HexFormatter.format (buffer, ptr, chunkSize));
|
||||||
ptr += chunkSize;
|
ptr += chunkSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -125,6 +142,15 @@ class WozDisk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------//
|
||||||
|
// getSectorsPerTrack
|
||||||
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
int getSectorsPerTrack ()
|
||||||
|
{
|
||||||
|
return mc3470.is13Sector () ? 13 : 16;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
// readInt
|
// readInt
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
@ -141,48 +167,6 @@ class WozDisk
|
|||||||
return value;
|
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
|
// readFile
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
Loading…
x
Reference in New Issue
Block a user