2018-08-17 01:20:00 +00:00
|
|
|
package com.bytezone.diskbrowser.nib;
|
2016-11-28 00:45:17 +00:00
|
|
|
|
|
|
|
import java.io.BufferedInputStream;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
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
|
|
|
|
2018-08-17 01:20:00 +00:00
|
|
|
public class V2dFile
|
2016-11-28 00:45:17 +00:00
|
|
|
{
|
2018-06-13 10:52:45 +00:00
|
|
|
// private static int[][] interleave =
|
2018-04-25 20:41:03 +00:00
|
|
|
// { { 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 } };
|
2016-12-01 13:25:41 +00:00
|
|
|
|
2018-04-25 20:41:03 +00:00
|
|
|
// private static final int DOS = 0;
|
|
|
|
// private static final int PRODOS = 1;
|
2016-11-28 00:45:17 +00:00
|
|
|
|
2016-12-01 13:25:41 +00:00
|
|
|
private static final int TRACK_LENGTH = 6304;
|
|
|
|
|
2016-12-03 08:20:01 +00:00
|
|
|
private final Nibblizer nibbler;
|
2016-11-28 00:45:17 +00:00
|
|
|
|
2018-08-17 01:20:00 +00:00
|
|
|
public final File file;
|
2016-11-28 06:26:26 +00:00
|
|
|
final int tracks;
|
|
|
|
|
2016-12-03 08:20:01 +00:00
|
|
|
final byte[] diskBuffer = new byte[4096 * 35];
|
2016-11-28 06:26:26 +00:00
|
|
|
|
2018-08-13 09:17:05 +00:00
|
|
|
public V2dFile (File file)
|
2016-11-28 00:45:17 +00:00
|
|
|
{
|
2016-11-28 06:26:26 +00:00
|
|
|
this.file = file;
|
|
|
|
int tracks = 0;
|
2018-06-10 20:45:11 +00:00
|
|
|
nibbler = new Nibblizer ();
|
2016-12-01 13:25:41 +00:00
|
|
|
|
2016-11-28 00:45:17 +00:00
|
|
|
try
|
|
|
|
{
|
2016-12-03 08:20:01 +00:00
|
|
|
byte[] header = new byte[10];
|
2016-11-28 00:45:17 +00:00
|
|
|
BufferedInputStream in = new BufferedInputStream (new FileInputStream (file));
|
2016-12-03 08:20:01 +00:00
|
|
|
in.read (header);
|
2016-11-28 00:45:17 +00:00
|
|
|
|
2016-12-03 08:20:01 +00:00
|
|
|
int diskLength = HexFormatter.getLongBigEndian (header, 0); // 4 bytes
|
|
|
|
String id = HexFormatter.getString (header, 4, 4); // 4 bytes
|
|
|
|
tracks = HexFormatter.getShortBigEndian (header, 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
|
|
|
|
2016-12-01 13:25:41 +00:00
|
|
|
byte[] trackHeader = new byte[4];
|
|
|
|
byte[] trackData = new byte[TRACK_LENGTH];
|
|
|
|
|
2016-11-28 00:45:17 +00:00
|
|
|
for (int i = 0; i < tracks; i++)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
2016-12-01 13:25:41 +00:00
|
|
|
assert trackLength == TRACK_LENGTH;
|
|
|
|
|
|
|
|
int dataRead = in.read (trackData);
|
|
|
|
assert dataRead == TRACK_LENGTH;
|
|
|
|
|
2016-11-28 00:45:17 +00:00
|
|
|
int fullTrackNo = trackNumber / 4;
|
|
|
|
int halfTrackNo = trackNumber % 4;
|
|
|
|
|
2016-12-01 13:25:41 +00:00
|
|
|
if (halfTrackNo == 0) // only process full tracks
|
2018-08-11 00:07:50 +00:00
|
|
|
nibbler.processTrack (fullTrackNo, 16, trackData, diskBuffer);
|
2016-11-29 21:27:44 +00:00
|
|
|
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
|
|
|
}
|
2018-08-17 01:20:00 +00:00
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
// getDiskBuffer
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
public byte[] getDiskBuffer ()
|
|
|
|
{
|
|
|
|
return diskBuffer;
|
|
|
|
}
|
2016-11-28 00:45:17 +00:00
|
|
|
}
|