added support for .woz files

This commit is contained in:
Denis Molony 2018-06-08 22:14:19 +10:00
parent 9d57fcf366
commit 7f728e8e53
6 changed files with 292 additions and 29 deletions

View File

@ -226,6 +226,21 @@ public class AppleDisk implements Disk
diskBuffer = disk.buffer;
}
public AppleDisk (WozDisk disk) // not used yet
{
tracks = 35;
trackSize = 4096;
file = disk.file;
diskBuffer = disk.diskBuffer;
sectorSize = 256;
sectors = 16;
blocks = tracks * sectors;
hasData = new boolean[blocks];
checkSectorsForData ();
}
private byte[] getPrefix (File path)
{
byte[] buffer = new byte[64];

View File

@ -247,6 +247,16 @@ public class DiskFactory
return null;
}
if (suffix.equals ("woz"))
{
if (debug)
System.out.println (" ** woz **");
WozDisk wozDisk = new WozDisk (file);
AppleDisk appleDisk16 = new AppleDisk (wozDisk);
disk = checkDos (appleDisk16);
return disk;
}
long length = file.length ();
if (length == 116480) // 13 sector disk

View File

@ -18,7 +18,7 @@ public class NibDisk
// .nib files are 232,960 bytes
// 6,656 bytes x 35 tracks (0x1A00)
// add 'nib' to TreeBuilder to allow nib files to be selected
// add 'nib' to Utility.suffixes to allow nib files to be selected
public NibDisk (File file)
{

View File

@ -93,7 +93,7 @@ public class Nibblizer
{
for (int i = 0; i < writeTranslateTable.length; i++)
{
int j = (writeTranslateTable[i] & 0xFF) - 150; // skip first 150 blanks
int j = (writeTranslateTable[i] & 0xFF) - 0x96; // skip first 150 blanks
readTranslateTable[j] = (byte) (i + 1); // offset by 1 to avoid zero
}
}
@ -125,39 +125,72 @@ public class Nibblizer
public boolean processTrack (int trackNo, byte[] buffer, byte[] diskBuffer)
{
int ptr = 0;
while (buffer[ptr] == (byte) 0xEB)
{
System.out.printf ("%s overrun 0xEB offset %d in track %02X%n", file.getName (),
ptr, trackNo);
++ptr;
}
ptr += skipBytes (buffer, ptr, (byte) 0xFF); // gap1
int totalSectors = 0;
boolean[] sectorsFound = new boolean[16];
while (ptr < buffer.length)
{
ptr = findBytes (buffer, ptr, addressPrologue);
if (ptr < 0)
{
System.out.printf ("Track: %02X - Address prologue not found%n", trackNo);
// System.out.println (HexFormatter.format (buffer));
return false;
}
AddressField addressField = getAddressField (buffer, ptr);
if (!addressField.isValid ())
{
System.out.printf ("Track: %02X - Invalid address field%n", trackNo);
return false;
}
if (addressField.track != trackNo)
{
System.out.printf ("Track: %02X - Wrong track found (%02X)%n", trackNo,
addressField.track);
return false;
}
if (sectorsFound[addressField.sector])
{
System.out.printf ("Track: %02X - Sector already processes (%02X)%n", trackNo,
addressField.sector);
return false;
}
sectorsFound[addressField.sector] = true;
assert addressField.track == trackNo;
ptr += addressField.size ();
ptr += skipBytes (buffer, ptr, (byte) 0xFF); // gap2
ptr = findBytes (buffer, ptr, dataPrologue);
if (ptr < 0)
{
System.out.printf ("Track: %02X - Data prologue not found%n", trackNo);
return false;
}
DataField dataField = getDataField (buffer, ptr);
if (!dataField.isValid ())
{
System.out.printf ("Track: %02X - Invalid data field%n", trackNo);
return false;
}
int offset = addressField.track * TRACK_SIZE
+ interleave[DOS][addressField.sector] * BLOCK_SIZE;
System.arraycopy (dataField.dataBuffer, 0, diskBuffer, offset, BLOCK_SIZE);
if (++totalSectors == 16)
break;
ptr += dataField.size ();
ptr += skipBytes (buffer, ptr, (byte) 0xFF); // gap3
}
if (totalSectors != 16)
{
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
return false;
}
// System.out.printf ("Track: %02X - OK%n", trackNo);
return true;
}
@ -260,13 +293,13 @@ public class Nibblizer
return bits == 1 ? 2 : bits == 2 ? 1 : bits;
}
private int skipBytes (byte[] buffer, int offset, byte skipValue)
{
int count = 0;
while (offset < buffer.length && buffer[offset++] == skipValue)
++count;
return count;
}
// private int skipBytes (byte[] buffer, int offset, byte skipValue)
// {
// int count = 0;
// while (offset < buffer.length && buffer[offset++] == skipValue)
// ++count;
// return count;
// }
private String listBytes (byte[] buffer, int offset, int length)
{
@ -327,6 +360,12 @@ public class Nibblizer
assert length > 0;
return length;
}
@Override
public String toString ()
{
return String.format ("[Offset: %04X, Length: %04X]", offset, length);
}
}
class AddressField extends Field
@ -337,8 +376,8 @@ public class Nibblizer
{
super (buffer, offset);
if (matchBytes (buffer, offset, addressPrologue)
&& matchBytes (buffer, offset + 11, epilogue))
if (matchBytes (buffer, offset, addressPrologue))
// && matchBytes (buffer, offset + 11, epilogue))
{
volume = decode4and4 (buffer, offset + 3);
track = decode4and4 (buffer, offset + 5);
@ -351,6 +390,13 @@ public class Nibblizer
length = 14;
}
@Override
public String toString ()
{
return String.format ("[volume: %02X, track: %02X, sector: %02X, checksum: %02X]",
volume, track, sector, checksum);
}
}
class DataField extends Field
@ -365,12 +411,12 @@ public class Nibblizer
{
valid = true;
dataBuffer = decode6and2 (buffer, offset + 3);
if (!matchBytes (buffer, offset + 3 + BUFFER_WITH_CHECKSUM_SIZE, epilogue))
{
System.out.print (" bad data epilogue: ");
System.out
.println (listBytes (buffer, offset + 3 + BUFFER_WITH_CHECKSUM_SIZE, 3));
}
// if (!matchBytes (buffer, offset + 3 + BUFFER_WITH_CHECKSUM_SIZE, epilogue))
// {
// System.out.print (" bad data epilogue: ");
// System.out
// .println (listBytes (buffer, offset + 3 + BUFFER_WITH_CHECKSUM_SIZE, 3));
// }
}
else
{

View File

@ -0,0 +1,192 @@
package com.bytezone.diskbrowser.disk;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class WozDisk
{
private static final int TRK_SIZE = 0x1A00;
private static final int DATA_SIZE = TRK_SIZE - 10;
private static byte[] header =
{ 0x57, 0x4F, 0x5A, 0x31, (byte) 0xFF, 0x0a, 0x0D, 0x0A };
private static final String SPACES = " ";
private final boolean debug = false;
final File file;
private final Nibblizer nibbler;
final byte[] diskBuffer = new byte[4096 * 35];
public WozDisk (File f)
{
this.file = f;
nibbler = new Nibblizer (f);
byte[] id = new byte[8];
byte[] checksum = new byte[4];
byte[] trackBuffer = new byte[TRK_SIZE];
byte[] infoBuffer = new byte[60];
byte[] tmapBuffer = new byte[160];
try
{
BufferedInputStream in = new BufferedInputStream (new FileInputStream (file));
in.read (id);
assert matches (id, header);
in.read (checksum);
read: while (in.available () > 8)
{
String chunkId = readString (in, 4);
int chunkSize = readInt (in, 4);
if ("INFO".equals (chunkId))
{
if (debug)
{
in.read (infoBuffer);
System.out.printf ("Version ........... %02X%n", infoBuffer[0]);
System.out.printf ("Disk type ......... %02X%n", infoBuffer[1]);
System.out.printf ("Write protected ... %02X%n", infoBuffer[2]);
System.out.printf ("Synchronised ...... %02X%n", infoBuffer[3]);
System.out.printf ("Cleaned ........... %02X%n", infoBuffer[4]);
System.out.printf ("Creator ........... %s%n%n",
new String (infoBuffer, 5, 32));
}
else
in.skip (infoBuffer.length);
}
else if ("TMAP".equals (chunkId))
{
if (debug)
{
in.read (tmapBuffer);
int ptr = 0;
for (int track = 0; track < 40; track++)
{
for (int qtr = 0; qtr < 4; qtr++)
System.out.printf ("%02X ", tmapBuffer[ptr++]);
System.out.println ();
}
System.out.println ();
}
else
in.skip (tmapBuffer.length);
}
else if ("TRKS".equals (chunkId))
{
int tracks = chunkSize / TRK_SIZE;
for (int track = 0; track < tracks; track++)
{
int bytesRead = in.read (trackBuffer);
assert bytesRead == TRK_SIZE;
int bytesUsed = readInt (trackBuffer, DATA_SIZE, 2);
int bitCount = readInt (trackBuffer, DATA_SIZE + 2, 2);
byte[] trackData = new byte[bytesUsed];
readTrack (trackBuffer, trackData, bytesUsed);
if (!nibbler.processTrack (track, trackData, diskBuffer))
{
System.out.println ("Nibblizer failure");
// System.out.println (HexFormatter.format (trackBuffer, 0, trackBuffer.length,
// TRK_SIZE * track + 256));
// System.out.println ();
break read;
}
}
}
else if ("META".equals (chunkId))
{
System.out.printf ("[%s] %08X%n", chunkId, chunkSize);
skip (in, chunkSize);
}
else
{
System.out.printf ("Unknown %08X%n", chunkSize);
skip (in, chunkSize);
}
}
in.close ();
}
catch (IOException e)
{
e.printStackTrace ();
System.exit (1);
}
}
private void skip (BufferedInputStream file, int size) throws IOException
{
while ((size -= file.skip (size)) > 0)
;
}
private String readString (BufferedInputStream file, int size) throws IOException
{
byte[] bytes = new byte[size];
file.read (bytes);
// for (byte b : bytes)
// System.out.printf ("%02X ", b);
// System.out.println ();
return new String (bytes);
}
private int readInt (byte[] buffer, int offset, int length)
{
int shift = 0;
int value = 0;
for (int i = 0; i < length; i++)
{
value |= (buffer[offset + i] & 0xFF) << shift;
shift += 8;
}
return value;
}
private int readInt (BufferedInputStream file, int size) throws IOException
{
byte[] buffer = new byte[size];
file.read (buffer);
return readInt (buffer, 0, size);
}
private boolean matches (byte[] b1, byte[] b2)
{
for (int i = 0; i < b1.length; i++)
if (b1[i] != b2[i])
return false;
return true;
}
private void readTrack (byte[] buffer, byte[] trackData, int bytesUsed)
{
// int consecutiveZeros = 0;
int value = 0;
int ptr = 0;
for (int i = 0; i < bytesUsed; i++)
{
int b = buffer[i] & 0xFF;
for (int mask = 0x80; mask > 0; mask >>>= 1)
{
int bit = (b & mask) == 0 ? 0 : 1;
// if (bit == 1)
// consecutiveZeros = 0;
// else if (++consecutiveZeros > 3)
// bit = (random.nextInt () & 0x01);
value <<= 1;
value |= bit;
if ((value & 0x80) != 0) // is hi-bit set?
{
trackData[ptr++] = (byte) (value & 0xFF);
value = 0;
}
}
}
assert value == 0;
}
}

View File

@ -8,7 +8,7 @@ import java.util.List;
public class Utility
{
public static final List<String> suffixes =
Arrays.asList ("po", "dsk", "do", "hdv", "2mg", "v2d", "d13", "sdk");
Arrays.asList ("po", "dsk", "do", "hdv", "2mg", "v2d", "d13", "sdk", "woz");
// not used - it doesn't work with Oracle's JDK
// private static boolean hasRetinaDisplay ()