2018-06-08 12:14:19 +00:00
|
|
|
package com.bytezone.diskbrowser.disk;
|
|
|
|
|
|
|
|
import java.io.BufferedInputStream;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
|
2018-06-10 03:12:32 +00:00
|
|
|
import com.bytezone.diskbrowser.utilities.Utility;
|
|
|
|
|
2018-06-08 12:14:19 +00:00
|
|
|
public class WozDisk
|
|
|
|
{
|
|
|
|
private static final int TRK_SIZE = 0x1A00;
|
2018-06-09 01:11:02 +00:00
|
|
|
private static final int INFO_SIZE = 0x3C;
|
|
|
|
private static final int TMAP_SIZE = 0xA0;
|
2018-06-08 12:14:19 +00:00
|
|
|
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;
|
|
|
|
final byte[] diskBuffer = new byte[4096 * 35];
|
|
|
|
|
2018-06-09 01:11:02 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// constructor
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-08 12:14:19 +00:00
|
|
|
public WozDisk (File f)
|
|
|
|
{
|
|
|
|
this.file = f;
|
2018-06-09 01:11:02 +00:00
|
|
|
Nibblizer nibbler = new Nibblizer (f);
|
2018-06-10 03:12:32 +00:00
|
|
|
byte[] buffer = null;
|
2018-06-08 12:14:19 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
BufferedInputStream in = new BufferedInputStream (new FileInputStream (file));
|
2018-06-10 03:12:32 +00:00
|
|
|
buffer = in.readAllBytes ();
|
|
|
|
in.close ();
|
|
|
|
}
|
|
|
|
catch (IOException e)
|
|
|
|
{
|
|
|
|
e.printStackTrace ();
|
|
|
|
return;
|
|
|
|
}
|
2018-06-08 12:14:19 +00:00
|
|
|
|
2018-06-10 03:12:32 +00:00
|
|
|
assert matches (header, buffer);
|
|
|
|
|
|
|
|
int cs1 = readInt (buffer, 8, 4);
|
|
|
|
int cs2 = Utility.crc32 (buffer, 12, 256 - 12 + 35 * 6656);
|
|
|
|
if (cs1 != cs2)
|
|
|
|
{
|
|
|
|
System.out.printf ("Checksum: %08X%n", cs1);
|
|
|
|
System.out.printf ("Calculat: %08X%n", cs2);
|
|
|
|
}
|
2018-06-08 12:14:19 +00:00
|
|
|
|
2018-06-10 03:12:32 +00:00
|
|
|
int ptr = 12;
|
|
|
|
read: while (ptr < buffer.length)
|
|
|
|
{
|
|
|
|
String chunkId = readString (buffer, ptr, 4);
|
|
|
|
ptr += 4;
|
|
|
|
int chunkSize = readInt (buffer, ptr, 4);
|
|
|
|
ptr += 4;
|
|
|
|
|
|
|
|
if ("INFO".equals (chunkId))
|
|
|
|
{
|
|
|
|
if (debug)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
2018-06-10 03:12:32 +00:00
|
|
|
System.out.printf ("Version ........... %02X%n", buffer[ptr]);
|
|
|
|
System.out.printf ("Disk type ......... %02X%n", buffer[ptr + 1]);
|
|
|
|
System.out.printf ("Write protected ... %02X%n", buffer[ptr + 2]);
|
|
|
|
System.out.printf ("Synchronised ...... %02X%n", buffer[ptr + 3]);
|
|
|
|
System.out.printf ("Cleaned ........... %02X%n", buffer[ptr + 4]);
|
|
|
|
System.out.printf ("Creator ........... %s%n%n",
|
|
|
|
new String (buffer, ptr + 5, 32));
|
2018-06-08 12:14:19 +00:00
|
|
|
}
|
2018-06-10 03:12:32 +00:00
|
|
|
ptr += INFO_SIZE;
|
|
|
|
}
|
|
|
|
else if ("TMAP".equals (chunkId))
|
|
|
|
{
|
|
|
|
if (debug)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
2018-06-10 03:12:32 +00:00
|
|
|
for (int track = 0; track < 40; track++)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
2018-06-10 03:12:32 +00:00
|
|
|
for (int qtr = 0; qtr < 4; qtr++)
|
|
|
|
System.out.printf ("%02X ", buffer[ptr++]);
|
2018-06-08 12:14:19 +00:00
|
|
|
System.out.println ();
|
|
|
|
}
|
2018-06-10 03:12:32 +00:00
|
|
|
System.out.println ();
|
2018-06-08 12:14:19 +00:00
|
|
|
}
|
2018-06-10 03:12:32 +00:00
|
|
|
else
|
|
|
|
ptr += TMAP_SIZE;
|
|
|
|
}
|
|
|
|
else if ("TRKS".equals (chunkId))
|
|
|
|
{
|
|
|
|
int tracks = chunkSize / TRK_SIZE;
|
|
|
|
for (int track = 0; track < tracks; track++)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
2018-06-10 03:12:32 +00:00
|
|
|
int bytesUsed = readInt (buffer, ptr + DATA_SIZE, 2);
|
|
|
|
int bitCount = readInt (buffer, ptr + DATA_SIZE + 2, 2);
|
|
|
|
|
|
|
|
byte[] trackData = new byte[bytesUsed];
|
|
|
|
readTrack (buffer, ptr, trackData, bytesUsed);
|
|
|
|
if (!nibbler.processTrack (track, trackData, diskBuffer))
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
2018-06-10 03:12:32 +00:00
|
|
|
System.out.println ("Nibblizer failure");
|
|
|
|
break read;
|
2018-06-08 12:14:19 +00:00
|
|
|
}
|
2018-06-10 03:12:32 +00:00
|
|
|
ptr += TRK_SIZE;
|
2018-06-08 12:14:19 +00:00
|
|
|
}
|
|
|
|
}
|
2018-06-10 03:12:32 +00:00
|
|
|
else if ("META".equals (chunkId))
|
|
|
|
{
|
|
|
|
System.out.printf ("[%s] %08X%n", chunkId, chunkSize);
|
|
|
|
ptr += chunkSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
System.out.printf ("Unknown %08X%n", chunkSize);
|
|
|
|
ptr += chunkSize;
|
|
|
|
}
|
2018-06-08 12:14:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-09 01:11:02 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// skip
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-08 12:14:19 +00:00
|
|
|
private void skip (BufferedInputStream file, int size) throws IOException
|
|
|
|
{
|
|
|
|
while ((size -= file.skip (size)) > 0)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
2018-06-09 01:11:02 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// readString
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-10 03:12:32 +00:00
|
|
|
private String readString (byte[] buffer, int offset, int length)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
2018-06-10 03:12:32 +00:00
|
|
|
// byte[] bytes = new byte[size];
|
|
|
|
// file.read (bytes);
|
|
|
|
return new String (buffer, offset, length);
|
2018-06-08 12:14:19 +00:00
|
|
|
}
|
|
|
|
|
2018-06-09 01:11:02 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// readInt
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-08 12:14:19 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-06-09 01:11:02 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// readInt
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-10 03:12:32 +00:00
|
|
|
// private int readInt (BufferedInputStream file, int size) throws IOException
|
|
|
|
// {
|
|
|
|
// byte[] buffer = new byte[size];
|
|
|
|
// file.read (buffer);
|
|
|
|
// return readInt (buffer, 0, size);
|
|
|
|
// }
|
2018-06-08 12:14:19 +00:00
|
|
|
|
2018-06-09 01:11:02 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// matches
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-08 12:14:19 +00:00
|
|
|
private boolean matches (byte[] b1, byte[] b2)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < b1.length; i++)
|
|
|
|
if (b1[i] != b2[i])
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-09 01:11:02 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// readTrack
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
2018-06-10 03:12:32 +00:00
|
|
|
private void readTrack (byte[] buffer, int offset, byte[] trackData, int bytesUsed)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
|
|
|
// int consecutiveZeros = 0;
|
|
|
|
int value = 0;
|
|
|
|
int ptr = 0;
|
|
|
|
|
2018-06-10 03:12:32 +00:00
|
|
|
for (int i = offset; i < offset + bytesUsed; i++)
|
2018-06-08 12:14:19 +00:00
|
|
|
{
|
|
|
|
int b = buffer[i] & 0xFF;
|
|
|
|
for (int mask = 0x80; mask > 0; mask >>>= 1)
|
|
|
|
{
|
|
|
|
int bit = (b & mask) == 0 ? 0 : 1;
|
|
|
|
|
|
|
|
value <<= 1;
|
|
|
|
value |= bit;
|
|
|
|
|
|
|
|
if ((value & 0x80) != 0) // is hi-bit set?
|
|
|
|
{
|
|
|
|
trackData[ptr++] = (byte) (value & 0xFF);
|
|
|
|
value = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert value == 0;
|
|
|
|
}
|
|
|
|
}
|