mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-09-27 09:55:28 +00:00
749 lines
25 KiB
Java
749 lines
25 KiB
Java
package com.bytezone.diskbrowser.nib;
|
|
|
|
import java.io.BufferedInputStream;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
|
|
import com.bytezone.diskbrowser.utilities.Utility;
|
|
|
|
// -----------------------------------------------------------------------------------//
|
|
public class WozFile
|
|
//-----------------------------------------------------------------------------------//
|
|
{
|
|
private static final byte[] address16prologue =
|
|
{ (byte) 0xD5, (byte) 0xAA, (byte) 0x96 };
|
|
private static final byte[] address13prologue =
|
|
{ (byte) 0xD5, (byte) 0xAA, (byte) 0xB5 };
|
|
private static final byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
|
|
private static final byte[] epilogue = { (byte) 0xDE, (byte) 0xAA, (byte) 0xEB };
|
|
// apparently it can be DE AA Ex
|
|
|
|
private static final int BLOCK_SIZE = 512;
|
|
private static final int SECTOR_SIZE = 256;
|
|
|
|
private static final int TRK_SIZE = 0x1A00;
|
|
private static final int DATA_SIZE = TRK_SIZE - 10;
|
|
|
|
private static int[][] interleave =
|
|
{ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, // 13 sector
|
|
{ 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 } }; // 16 sector
|
|
|
|
public final File file;
|
|
|
|
private Info info;
|
|
private Meta meta;
|
|
private int diskSectors;
|
|
|
|
private byte[] addressPrologue;
|
|
private byte[] diskBuffer;
|
|
private List<Track> tracks;
|
|
|
|
private final boolean debug1 = false;
|
|
private final boolean showTracks = false;
|
|
|
|
private final ByteTranslator6and2 byteTranslator6and2 = new ByteTranslator6and2 ();
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public WozFile (File file) throws DiskNibbleException
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
this.file = file;
|
|
|
|
byte[] buffer = readFile (file);
|
|
String header = new String (buffer, 0, 4);
|
|
if (!"WOZ1".equals (header) && !"WOZ2".equals (header))
|
|
throw new DiskNibbleException ("Header error");
|
|
|
|
int checksum1 = val32 (buffer, 8);
|
|
int checksum2 = Utility.crc32 (buffer, 12, buffer.length - 12);
|
|
if (checksum1 != checksum2)
|
|
{
|
|
System.out.printf ("Stored checksum : %08X%n", checksum1);
|
|
System.out.printf ("Calculated checksum : %08X%n", checksum2);
|
|
throw new DiskNibbleException ("Checksum error");
|
|
}
|
|
|
|
int ptr = 12;
|
|
while (ptr < buffer.length)
|
|
{
|
|
validateChunk (buffer, ptr);
|
|
|
|
String chunkId = new String (buffer, ptr, 4);
|
|
int size = val32 (buffer, ptr + 4);
|
|
if (debug1)
|
|
System.out.printf ("%n%s %,9d%n", chunkId, size);
|
|
|
|
switch (chunkId)
|
|
{
|
|
case "INFO": // 60 bytes
|
|
info = new Info (buffer, ptr);
|
|
if (info.wozVersion >= 2)
|
|
setPrologue (info.bootSectorFormat == 2 ? 13 : 16);
|
|
break;
|
|
case "TMAP": // 160 bytes
|
|
tmap (buffer, ptr);
|
|
break;
|
|
case "TRKS": // starts at 248, data at 256
|
|
tracks = trks (buffer, ptr);
|
|
break;
|
|
case "META":
|
|
meta = new Meta (buffer, ptr, size);
|
|
break;
|
|
case "WRIT":
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ptr += size + 8;
|
|
}
|
|
|
|
if (info.diskType == 1) // 5.25"
|
|
{
|
|
diskBuffer = new byte[tracks.size () * diskSectors * SECTOR_SIZE];
|
|
|
|
for (Track track : tracks)
|
|
track.pack (diskBuffer);
|
|
}
|
|
else if (info.diskType == 2) // 3.5"
|
|
{
|
|
List<Sector> sectors = new ArrayList<> ();
|
|
for (Track track : tracks)
|
|
sectors.addAll (track.sectors);
|
|
Collections.sort (sectors);
|
|
|
|
diskBuffer = new byte[800 * info.sides * BLOCK_SIZE];
|
|
ptr = 0;
|
|
|
|
for (Sector sector : sectors)
|
|
{
|
|
sector.pack35 (diskBuffer, ptr);
|
|
ptr += BLOCK_SIZE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private boolean validateChunk (byte[] buffer, int ptr) throws DiskNibbleException
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
int size = val32 (buffer, ptr + 4);
|
|
if (size <= 0 || size + ptr + 8 > buffer.length)
|
|
{
|
|
if (info != null)
|
|
System.out.println (info);
|
|
throw new DiskNibbleException (String.format ("Invalid chunk size: %08X%n", size));
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
int val = buffer[ptr + i] & 0xFF;
|
|
if (val < 'A' || val > 'Z') // not uppercase ascii
|
|
{
|
|
if (info != null)
|
|
System.out.println (info);
|
|
throw new DiskNibbleException (
|
|
String.format ("Invalid chunk name character: %02X%n", val));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public byte[] getDiskBuffer ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return diskBuffer;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public int getDiskType ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return info.diskType;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public int getSides ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return info.sides;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public int getTracks ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return tracks.size ();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public int getSectorsPerTrack ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return diskSectors;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private void setPrologue (int diskSectors)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
this.diskSectors = diskSectors;
|
|
addressPrologue = diskSectors == 13 ? address13prologue : address16prologue;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private void tmap (byte[] buffer, int ptr)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
ptr += 8;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private List<Track> trks (byte[] rawBuffer, int ptr)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
List<Track> tracks = new ArrayList<> ();
|
|
ptr += 8;
|
|
|
|
int reclen = info.wozVersion == 1 ? TRK_SIZE : 8;
|
|
int max = info.wozVersion == 1 ? 35 : 160;
|
|
|
|
for (int i = 0; i < max; i++)
|
|
{
|
|
try
|
|
{
|
|
Track trk = new Track (i, rawBuffer, ptr);
|
|
if (trk.bitCount == 0)
|
|
break;
|
|
tracks.add (trk);
|
|
if (showTracks)
|
|
System.out.printf ("%n$%02X %s%n", i, trk);
|
|
}
|
|
catch (DiskNibbleException e)
|
|
{
|
|
e.printStackTrace ();
|
|
}
|
|
ptr += reclen;
|
|
}
|
|
return tracks;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private int val8 (byte[] buffer, int ptr)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return (buffer[ptr] & 0xFF);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private int val16 (byte[] buffer, int ptr)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return (buffer[ptr] & 0xFF) //
|
|
| ((buffer[ptr + 1] & 0xFF) << 8);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private int val32 (byte[] buffer, int ptr)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return (buffer[ptr] & 0xFF) //
|
|
| ((buffer[ptr + 1] & 0xFF) << 8) //
|
|
| ((buffer[ptr + 2] & 0xFF) << 16) //
|
|
| ((buffer[ptr + 3] & 0xFF) << 24);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private int decode4and4 (byte[] buffer, int offset)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
int odds = ((buffer[offset] & 0xFF) << 1) | 0x01;
|
|
int evens = buffer[offset + 1] & 0xFF;
|
|
return odds & evens;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private byte[] readFile (File file)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
try (BufferedInputStream in = new BufferedInputStream (new FileInputStream (file)))
|
|
{
|
|
return in.readAllBytes ();
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
e.printStackTrace ();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
@Override
|
|
public String toString ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
if (meta != null)
|
|
return info.toString () + "\n\n" + meta.toString ();
|
|
return info.toString ();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public static void main (String[] args)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
String home = "/Users/denismolony/";
|
|
String wozBase1 = home + "Dropbox/Examples/woz test images/WOZ 1.0/";
|
|
String wozBase2 = home + "Dropbox/Examples/woz test images/WOZ 2.0/";
|
|
String wozBase3 = home + "Dropbox/Examples/woz test images/WOZ 2.0/3.5/";
|
|
File[] files = { new File (home + "code/python/wozardry-2.0/bill.woz"),
|
|
new File (wozBase2 + "DOS 3.3 System Master.woz"),
|
|
new File (wozBase1 + "DOS 3.3 System Master.woz"),
|
|
new File (wozBase3 + "Apple IIgs System Disk 1.1.woz") };
|
|
try
|
|
{
|
|
new WozFile (files[3]);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
e.printStackTrace ();
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
class Info
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
int wozVersion;
|
|
int diskType;
|
|
int writeProtected;
|
|
int synchronised;
|
|
int cleaned;
|
|
String creator;
|
|
|
|
int sides;
|
|
int bootSectorFormat;
|
|
int optimalBitTiming;
|
|
int compatibleHardware;
|
|
int requiredRam;
|
|
int largestTrack;
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
Info (byte[] buffer, int ptr)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
wozVersion = val8 (buffer, ptr + 8);
|
|
|
|
diskType = val8 (buffer, ptr + 9);
|
|
writeProtected = val8 (buffer, ptr + 10);
|
|
synchronised = val8 (buffer, ptr + 11);
|
|
cleaned = val8 (buffer, ptr + 12);
|
|
creator = new String (buffer, ptr + 13, 32);
|
|
|
|
if (wozVersion >= 2)
|
|
{
|
|
sides = val8 (buffer, ptr + 45);
|
|
bootSectorFormat = val8 (buffer, ptr + 46);
|
|
optimalBitTiming = val8 (buffer, ptr + 47);
|
|
compatibleHardware = val16 (buffer, ptr + 48);
|
|
requiredRam = val16 (buffer, ptr + 50);
|
|
largestTrack = val16 (buffer, ptr + 52);
|
|
}
|
|
|
|
if (debug1)
|
|
System.out.println (this);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
@Override
|
|
public String toString ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
StringBuilder text = new StringBuilder ("WOZ info:\n\n");
|
|
|
|
String diskTypeText = diskType == 1 ? "5.25" : "3.5";
|
|
|
|
text.append (String.format ("Version ............. %d%n", wozVersion));
|
|
text.append (
|
|
String.format ("Disk type ........... %d (%s\")%n", diskType, diskTypeText));
|
|
text.append (String.format ("Write protected ..... %d%n", writeProtected));
|
|
text.append (String.format ("Synchronized ........ %d%n", synchronised));
|
|
text.append (String.format ("Cleaned ............. %d%n", cleaned));
|
|
text.append (String.format ("Creator ............. %s", creator));
|
|
|
|
if (wozVersion > 1)
|
|
{
|
|
String bootSectorFormatText =
|
|
bootSectorFormat == 0 ? "Unknown" : bootSectorFormat == 1 ? "16 sector"
|
|
: bootSectorFormat == 2 ? "13 sector" : "Hybrid";
|
|
|
|
text.append (String.format ("%nSides ............... %d%n", sides));
|
|
text.append (String.format ("Boot sector format .. %d (%s)%n", bootSectorFormat,
|
|
bootSectorFormatText));
|
|
text.append (String.format ("Optimal bit timing .. %d%n", optimalBitTiming));
|
|
text.append (String.format ("Compatible hardware . %d%n", compatibleHardware));
|
|
text.append (String.format ("Required RAM ........ %d%n", requiredRam));
|
|
text.append (String.format ("Largest track ....... %d", largestTrack));
|
|
}
|
|
|
|
return text.toString ();
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------//
|
|
class Meta
|
|
// -----------------------------------------------------------------------------------//
|
|
{
|
|
List<String> lines = new ArrayList<> ();
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
Meta (byte[] buffer, int ptr, int length)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
String dots = " ......................";
|
|
String metaData = new String (buffer, ptr + 8, length);
|
|
String[] chunks = metaData.split ("\n");
|
|
for (String chunk : chunks)
|
|
{
|
|
String[] parts = chunk.split ("\t");
|
|
if (parts.length >= 2)
|
|
lines.add (String.format ("%-21.21s %s", parts[0] + dots, parts[1]));
|
|
else
|
|
lines.add (String.format ("%-21.21s", parts[0] + dots));
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
@Override
|
|
public String toString ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
StringBuilder text = new StringBuilder ("WOZ meta:\n\n");
|
|
|
|
for (String line : lines)
|
|
text.append (String.format ("%s%n", line));
|
|
|
|
if (text.length () > 0)
|
|
text.deleteCharAt (text.length () - 1);
|
|
|
|
return text.toString ();
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------//
|
|
class Track implements Iterable<Sector>
|
|
// -----------------------------------------------------------------------------------//
|
|
{
|
|
private int trackNo;
|
|
private int startingBlock;
|
|
private int blockCount; // WOZ2 - not needed
|
|
private int bitCount;
|
|
private int bytesUsed; // WOZ1 - not needed
|
|
|
|
private byte[] rawBuffer;
|
|
private byte[] newBuffer;
|
|
|
|
private int bitIndex;
|
|
private int byteIndex;
|
|
private int trackIndex;
|
|
private int revolutions;
|
|
|
|
List<Sector> sectors = new ArrayList<> ();
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public Track (int trackNo, byte[] rawBuffer, int ptr) throws DiskNibbleException
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
this.rawBuffer = rawBuffer;
|
|
this.trackNo = trackNo;
|
|
|
|
if (info.wozVersion == 1)
|
|
{
|
|
bytesUsed = val16 (rawBuffer, ptr + DATA_SIZE);
|
|
bitCount = val16 (rawBuffer, ptr + DATA_SIZE + 2);
|
|
|
|
if (debug1)
|
|
System.out.println (
|
|
(String.format ("Bytes: %2d, Bits: %,8d%n%n", bytesUsed, bitCount)));
|
|
}
|
|
else
|
|
{
|
|
startingBlock = val16 (rawBuffer, ptr);
|
|
blockCount = val16 (rawBuffer, ptr + 2);
|
|
bitCount = val32 (rawBuffer, ptr + 4);
|
|
|
|
if (debug1)
|
|
System.out.println ((String.format ("%nStart: %4d, Blocks: %2d, Bits: %,8d%n",
|
|
startingBlock, blockCount, bitCount)));
|
|
}
|
|
|
|
if (bitCount == 0)
|
|
return;
|
|
|
|
resetIndex ();
|
|
|
|
if (addressPrologue == null) // WOZ1
|
|
if (findNext (address16prologue, ptr) > 0)
|
|
setPrologue (16);
|
|
else if (findNext (address13prologue, ptr) > 0)
|
|
setPrologue (13);
|
|
else
|
|
throw new DiskNibbleException ("No address prologue found");
|
|
|
|
int offset = -1;
|
|
|
|
while (sectors.size () < diskSectors)
|
|
{
|
|
offset = findNext (addressPrologue, offset + 1);
|
|
if (offset < 0)
|
|
break;
|
|
|
|
Sector sector = new Sector (this, offset);
|
|
if (isDuplicate (sector))
|
|
break;
|
|
sectors.add (sector);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private boolean isDuplicate (Sector newSector)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
for (Sector sector : sectors)
|
|
if (sector.sectorNo == newSector.sectorNo)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private void resetIndex ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
trackIndex = 0;
|
|
bitIndex = 0;
|
|
|
|
if (info.wozVersion == 1)
|
|
byteIndex = 256 + trackNo * TRK_SIZE;
|
|
else
|
|
byteIndex = startingBlock * BLOCK_SIZE;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
boolean nextBit ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
boolean bit = (rawBuffer[byteIndex] & (0x80 >>> bitIndex)) != 0;
|
|
|
|
if (++trackIndex >= bitCount)
|
|
{
|
|
++revolutions;
|
|
resetIndex ();
|
|
}
|
|
else if (++bitIndex >= 8)
|
|
{
|
|
++byteIndex;
|
|
bitIndex = 0;
|
|
}
|
|
|
|
return bit;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
int nextByte ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
byte b = 0;
|
|
while ((b & 0x80) == 0)
|
|
{
|
|
b <<= 1;
|
|
if (nextBit ())
|
|
b |= 0x01;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
void readTrack ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
if (newBuffer != null)
|
|
return;
|
|
|
|
int max = (bitCount - 1) / 8 + 1;
|
|
max += 600;
|
|
newBuffer = new byte[max];
|
|
|
|
for (int i = 0; i < max; i++)
|
|
newBuffer[i] = (byte) nextByte ();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
int findNext (byte[] key, int start)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
readTrack ();
|
|
|
|
int max = newBuffer.length - key.length;
|
|
outer: for (int ptr = start; ptr < max; ptr++)
|
|
{
|
|
for (int keyPtr = 0; keyPtr < key.length; keyPtr++)
|
|
if (newBuffer[ptr + keyPtr] != key[keyPtr])
|
|
continue outer;
|
|
return ptr;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
void pack (byte[] diskBuffer) throws DiskNibbleException
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
int ndx = diskSectors == 13 ? 0 : 1;
|
|
DiskReader diskReader = DiskReader.getInstance (diskSectors);
|
|
|
|
for (Sector sector : sectors)
|
|
if (sector.dataOffset > 0)
|
|
{
|
|
byte[] decodedBuffer =
|
|
diskReader.decodeSector (newBuffer, sector.dataOffset + 3);
|
|
int ptr = SECTOR_SIZE
|
|
* (sector.trackNo * diskSectors + interleave[ndx][sector.sectorNo]);
|
|
System.arraycopy (decodedBuffer, 0, diskBuffer, ptr, decodedBuffer.length);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
@Override
|
|
public String toString ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
StringBuilder text = new StringBuilder ();
|
|
if (info.wozVersion == 1)
|
|
text.append (
|
|
String.format ("WOZ1: Bytes: %2d, Bits: %,8d%n%n", bytesUsed, bitCount));
|
|
else
|
|
text.append (String.format ("WOZ2: Start: %4d, Blocks: %2d, Bits: %,8d%n%n",
|
|
startingBlock, blockCount, bitCount));
|
|
|
|
int count = 0;
|
|
for (Sector sector : sectors)
|
|
text.append (String.format ("%2d %s%n", count++, sector));
|
|
text.deleteCharAt (text.length () - 1);
|
|
|
|
return text.toString ();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
@Override
|
|
public Iterator<Sector> iterator ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
return sectors.iterator ();
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public class Sector implements Comparable<Sector>
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
private final Track track;
|
|
private int trackNo, sectorNo, volume, checksum;
|
|
private final int addressOffset;
|
|
private int dataOffset;
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
Sector (Track track, int addressOffset)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
this.track = track;
|
|
|
|
if (info.diskType == 1)
|
|
{
|
|
volume = decode4and4 (track.newBuffer, addressOffset + 3);
|
|
trackNo = decode4and4 (track.newBuffer, addressOffset + 5);
|
|
sectorNo = decode4and4 (track.newBuffer, addressOffset + 7);
|
|
checksum = decode4and4 (track.newBuffer, addressOffset + 9);
|
|
}
|
|
else
|
|
{
|
|
// http://apple2.guidero.us/doku.php/articles/iicplus_smartport_secrets
|
|
// SWIM Chip User's Ref pp 6
|
|
// uPD72070.pdf
|
|
try
|
|
{
|
|
int b1 = byteTranslator6and2.decode (track.newBuffer[addressOffset + 3]);
|
|
sectorNo = byteTranslator6and2.decode (track.newBuffer[addressOffset + 4]);
|
|
int b3 = byteTranslator6and2.decode (track.newBuffer[addressOffset + 5]);
|
|
int format = byteTranslator6and2.decode (track.newBuffer[addressOffset + 6]);
|
|
checksum = byteTranslator6and2.decode (track.newBuffer[addressOffset + 7]);
|
|
|
|
trackNo = (b1 & 0x3F) | ((b3 & 0x1F) << 6);
|
|
volume = (b3 & 0x20) >>> 5; // side
|
|
|
|
int chk = b1 ^ sectorNo ^ b3 ^ format;
|
|
assert chk == checksum;
|
|
}
|
|
catch (DiskNibbleException e)
|
|
{
|
|
e.printStackTrace ();
|
|
}
|
|
}
|
|
|
|
// int epiloguePtr = track.findNext (epilogue, addressOffset + 11);
|
|
// assert epiloguePtr == addressOffset + 11;
|
|
|
|
this.addressOffset = addressOffset;
|
|
dataOffset = track.findNext (dataPrologue, addressOffset + 11);
|
|
if (dataOffset > addressOffset + 200)
|
|
dataOffset = -1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
void pack35 (byte[] diskBuffer, int ptr) throws DiskNibbleException
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
DiskReader diskReader = DiskReader.getInstance (0);
|
|
|
|
// start decoding from 4 bytes past the data prologue (3 bytes for prologue
|
|
// itself, and another byte for the sector number)
|
|
byte[] decodedBuffer = diskReader.decodeSector (track.newBuffer, dataOffset + 4);
|
|
|
|
// return 512 bytes (ignore the 12 tag bytes)
|
|
System.arraycopy (decodedBuffer, DiskReaderGCR.TAG_SIZE, diskBuffer, ptr, 512);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
@Override
|
|
public String toString ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
String fld = info.diskType == 1 ? "Vol" : info.diskType == 2 ? "Sde" : "???";
|
|
String dataOffsetText = dataOffset < 0 ? "" : String.format ("%04X", dataOffset);
|
|
|
|
return String.format (
|
|
"%s: %02X Trk: %02X Sct: %02X Chk: %02X Add: %04X Dat: %s", fld, volume,
|
|
trackNo, sectorNo, checksum, addressOffset, dataOffsetText);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
@Override
|
|
public int compareTo (Sector o)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
if (this.trackNo != o.trackNo)
|
|
return this.trackNo - o.trackNo;
|
|
if (this.volume != o.volume) // side
|
|
return this.volume - o.volume;
|
|
return this.sectorNo - o.sectorNo;
|
|
}
|
|
}
|
|
}
|