dmolony-DiskBrowser/src/com/bytezone/diskbrowser/disk/V2dDisk.java

142 lines
4.6 KiB
Java
Raw Normal View History

2016-11-28 00:45:17 +00:00
package com.bytezone.diskbrowser.disk;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
2016-11-28 09:11:11 +00:00
import com.bytezone.diskbrowser.disk.Nibblizer.AddressField;
import com.bytezone.diskbrowser.disk.Nibblizer.DataField;
2016-11-28 00:45:17 +00:00
import com.bytezone.diskbrowser.utilities.HexFormatter;
/*
2016-11-28 10:43:50 +00:00
* from Gerard Putter's email:
2016-11-28 00:45:17 +00:00
* Offsets in bytes
* From To Meaning
* 0000 0003 Length of disk image, from offset 8 to the end (big endian)
* 0004 0007 Type indication; always 'D5NI'
* 0008 0009 Number of tracks (typical value: $23, but can be different). Also big endian.
* 000A 000B Track nummer * 4, starting with track # 0. Big endian.
* 000C 000D Length of track, not counting this length-field. Big endian.
* 000E 000E + length field - 1 Nibble-data of track, byte-for-byte.
* After this, the pattern from offset 000A repeats for each track. Note that
* "track number * 4" means that on a regular disk the tracks are numbered 0, 4, 8 etc.
* Half-tracks are numbered 2, 6, etc. The stepper motor of the disk uses 4 phases to
* travel from one track to the next, so quarter-tracks could also be stored with this
* format (I have never heard of disk actually using quarter tracks, though).
*/
2016-11-28 06:26:26 +00:00
// Physical disk interleave:
// Info from http://www.applelogic.org/TheAppleIIEGettingStarted.html
// Block ..: 0 1 2 3 4 5 6 7 8 9 A B C D E F
// Position: 0 8 1 9 2 A 3 B 4 C 5 D 6 E 7 F - Prodos (.PO disks)
// Position: 0 7 E 6 D 5 C 4 B 3 A 2 9 1 8 F - Dos (.DO disks)
2016-11-28 10:43:50 +00:00
2016-11-28 06:26:26 +00:00
public class V2dDisk
2016-11-28 00:45:17 +00:00
{
2016-11-28 09:11:11 +00:00
private static int[][] interleave =
{ { 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 DOS = 0;
private static final int PRODOS = 1;
2016-11-28 00:45:17 +00:00
2016-11-28 04:25:52 +00:00
private final Nibblizer nibbler = new Nibblizer ();
2016-11-28 00:45:17 +00:00
2016-11-28 06:26:26 +00:00
final File file;
final int tracks;
2016-11-29 21:27:44 +00:00
// int actualTracks;
2016-11-28 06:26:26 +00:00
final byte[] buffer = new byte[4096 * 35];
2016-11-28 00:45:17 +00:00
public V2dDisk (File file)
{
2016-11-28 06:26:26 +00:00
this.file = file;
int tracks = 0;
2016-11-28 00:45:17 +00:00
try
{
2016-11-28 06:26:26 +00:00
byte[] diskBuffer = new byte[10];
2016-11-28 00:45:17 +00:00
BufferedInputStream in = new BufferedInputStream (new FileInputStream (file));
in.read (diskBuffer);
int diskLength = HexFormatter.getLongBigEndian (diskBuffer, 0); // 4 bytes
String id = HexFormatter.getString (diskBuffer, 4, 4); // 4 bytes
2016-11-28 06:26:26 +00:00
tracks = HexFormatter.getShortBigEndian (diskBuffer, 8); // 2 bytes
2016-11-28 10:43:50 +00:00
2016-11-29 21:27:44 +00:00
assert diskLength + 8 == file.length ();
2016-11-28 10:43:50 +00:00
assert "D5NI".equals (id);
2016-11-28 00:45:17 +00:00
for (int i = 0; i < tracks; i++)
{
byte[] trackHeader = new byte[4];
in.read (trackHeader);
int trackNumber = HexFormatter.getShortBigEndian (trackHeader, 0);
2016-11-29 21:27:44 +00:00
int trackLength = HexFormatter.getShortBigEndian (trackHeader, 2); // 6304
2016-11-28 00:45:17 +00:00
int fullTrackNo = trackNumber / 4;
int halfTrackNo = trackNumber % 4;
byte[] trackData = new byte[trackLength];
in.read (trackData);
2016-11-28 10:43:50 +00:00
// only process full tracks
2016-11-29 21:27:44 +00:00
if (halfTrackNo == 0)
processTrack (fullTrackNo, trackData, buffer);
else
System.out.printf ("%s skipping half track %02X / %02X%n", file.getName (),
fullTrackNo, halfTrackNo);
2016-11-28 00:45:17 +00:00
}
in.close ();
}
catch (IOException e)
{
e.printStackTrace ();
}
2016-11-28 06:26:26 +00:00
this.tracks = tracks;
2016-11-28 00:45:17 +00:00
}
2016-11-28 10:43:50 +00:00
private boolean processTrack (int trackNo, byte[] buffer, byte[] diskBuffer)
2016-11-28 00:45:17 +00:00
{
int ptr = 0;
2016-11-28 09:11:11 +00:00
while (buffer[ptr] == (byte) 0xEB)
2016-11-28 00:45:17 +00:00
{
2016-11-29 21:27:44 +00:00
System.out.printf ("%s overrun 0xEB offset %d in track %02X%n", file.getName (),
ptr, trackNo);
2016-11-28 00:45:17 +00:00
++ptr;
}
2016-11-28 09:11:11 +00:00
ptr += nibbler.skipBytes (buffer, ptr, (byte) 0xFF); // gap1
2016-11-28 00:45:17 +00:00
while (ptr < buffer.length)
{
2016-11-28 09:11:11 +00:00
AddressField addressField = nibbler.getAddressField (buffer, ptr);
if (!addressField.isValid ())
2016-11-28 06:26:26 +00:00
return false;
2016-11-28 00:45:17 +00:00
2016-11-28 09:11:11 +00:00
ptr += addressField.size ();
ptr += nibbler.skipBytes (buffer, ptr, (byte) 0xFF); // gap2
2016-11-28 00:45:17 +00:00
2016-11-28 09:11:11 +00:00
DataField dataField = nibbler.getDataField (buffer, ptr);
if (!dataField.isValid ())
2016-11-29 21:27:44 +00:00
{
System.out.printf ("skipping data %02X / %02X%n", addressField.track,
addressField.sector);
2016-11-28 06:26:26 +00:00
return false;
2016-11-29 21:27:44 +00:00
}
2016-11-28 00:45:17 +00:00
2016-11-29 21:27:44 +00:00
// System.out.printf ("decoding track %02X / %02X%n", addressField.track,
// addressField.sector);
2016-11-28 09:11:11 +00:00
byte[] decodedBuffer = nibbler.decode6and2 (buffer, ptr + 3);
2016-11-28 06:26:26 +00:00
2016-11-28 09:11:11 +00:00
int offset = addressField.track * 4096 + interleave[DOS][addressField.sector] * 256;
2016-11-28 06:26:26 +00:00
System.arraycopy (decodedBuffer, 0, diskBuffer, offset, 256);
2016-11-28 04:25:52 +00:00
2016-11-28 09:11:11 +00:00
ptr += dataField.size ();
ptr += nibbler.skipBytes (buffer, ptr, (byte) 0xFF); // gap3
2016-11-28 00:45:17 +00:00
}
return true;
}
}