mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-11-25 16:34:00 +00:00
DOS 4.1 changes
This commit is contained in:
parent
d9b656cfa0
commit
1b5f3f95a9
@ -18,7 +18,7 @@ public class SimpleText2 extends AbstractFile
|
||||
|
||||
// store a pointer to each new line
|
||||
int ptr = 0;
|
||||
while (buffer[ptr] != -1)
|
||||
while (ptr < buffer.length && buffer[ptr] != -1)
|
||||
{
|
||||
int length = buffer[ptr] & 0xFF;
|
||||
lineStarts.add (ptr);
|
||||
@ -37,6 +37,8 @@ public class SimpleText2 extends AbstractFile
|
||||
|
||||
for (Integer i : lineStarts)
|
||||
text.append (String.format ("%05X %s%n", i, getLine (i)));
|
||||
if (text.charAt (text.length () - 1) == '\n')
|
||||
text.deleteCharAt (text.length () - 1);
|
||||
return text.toString ();
|
||||
}
|
||||
|
||||
@ -46,8 +48,8 @@ public class SimpleText2 extends AbstractFile
|
||||
StringBuilder text = new StringBuilder ();
|
||||
|
||||
for (Integer i : lineStarts)
|
||||
text.append (HexFormatter.formatNoHeader (buffer, i, (buffer[i] & 0xFF) + 1)
|
||||
+ "\n");
|
||||
text.append (
|
||||
HexFormatter.formatNoHeader (buffer, i, (buffer[i] & 0xFF) + 1) + "\n");
|
||||
text.append (HexFormatter.formatNoHeader (buffer, buffer.length - 2, 2) + "\n");
|
||||
|
||||
return text.toString ();
|
||||
|
@ -396,7 +396,8 @@ public class AppleDisk implements Disk
|
||||
int ptr = 0;
|
||||
for (DiskAddress da : daList)
|
||||
{
|
||||
if (da != null && da.getBlock () > 0) // sparse text/PNT/PIC files may have gaps
|
||||
// sparse text/PNT/PIC files may have gaps
|
||||
if (da != null && (da.getBlock () > 0 || ((AppleDiskAddress) da).zeroFlag ()))
|
||||
readBuffer (da, buffer, ptr);
|
||||
ptr += sectorSize;
|
||||
}
|
||||
@ -458,6 +459,9 @@ public class AppleDisk implements Disk
|
||||
@Override
|
||||
public DiskAddress getDiskAddress (int track, int sector)
|
||||
{
|
||||
// track &= 0x3F;
|
||||
// sector &= 0x1F;
|
||||
|
||||
if (!isValidAddress (track, sector))
|
||||
{
|
||||
System.out.println ("Invalid block : " + track + "/" + sector);
|
||||
@ -502,10 +506,14 @@ public class AppleDisk implements Disk
|
||||
@Override
|
||||
public boolean isValidAddress (int track, int sector)
|
||||
{
|
||||
track &= 0x3F;
|
||||
sector &= 0x1F;
|
||||
|
||||
if (track < 0 || track >= this.tracks)
|
||||
return false;
|
||||
if (sector < 0 || sector >= this.sectors)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ public class AppleDiskAddress implements DiskAddress
|
||||
private final int track;
|
||||
private final int sector;
|
||||
public final Disk owner;
|
||||
private boolean zeroFlag;
|
||||
|
||||
public AppleDiskAddress (Disk owner, int block)
|
||||
{
|
||||
@ -19,15 +20,15 @@ public class AppleDiskAddress implements DiskAddress
|
||||
public AppleDiskAddress (Disk owner, int track, int sector)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.track = track;
|
||||
this.sector = sector;
|
||||
this.block = track * owner.getSectorsPerTrack () + sector;
|
||||
zeroFlag = (track & 0x40) != 0;
|
||||
this.track = track & 0x3F;
|
||||
this.sector = sector & 0x1F;
|
||||
this.block = this.track * owner.getSectorsPerTrack () + this.sector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
public boolean zeroFlag ()
|
||||
{
|
||||
return String.format ("[Block=%3d, Track=%2d, Sector=%2d]", block, track, sector);
|
||||
return zeroFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,4 +66,11 @@ public class AppleDiskAddress implements DiskAddress
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return String.format ("[Block=%3d, Track=%2d, Sector=%2d, Zero=%s]", block, track,
|
||||
sector, zeroFlag);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.bytezone.diskbrowser.dos;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -10,6 +11,7 @@ import com.bytezone.diskbrowser.disk.FormattedDisk;
|
||||
import com.bytezone.diskbrowser.dos.DosDisk.FileType;
|
||||
import com.bytezone.diskbrowser.gui.DataSource;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
import com.bytezone.diskbrowser.utilities.Utility;
|
||||
|
||||
abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
{
|
||||
@ -22,6 +24,7 @@ abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
protected int reportedSize;
|
||||
protected boolean locked;
|
||||
protected DataSource appleFile;
|
||||
protected LocalDateTime lastModified;
|
||||
|
||||
protected DiskAddress catalogSectorDA;
|
||||
protected final List<DiskAddress> dataSectors = new ArrayList<DiskAddress> ();
|
||||
@ -34,33 +37,34 @@ abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
{
|
||||
this.dosDisk = dosDisk;
|
||||
this.disk = dosDisk.getDisk ();
|
||||
this.disk = dosDisk.getDisk ();
|
||||
this.catalogSectorDA = catalogSector;
|
||||
|
||||
reportedSize = HexFormatter.unsignedShort (entryBuffer, 33);
|
||||
int type = entryBuffer[2] & 0xFF;
|
||||
locked = (type & 0x80) > 0;
|
||||
|
||||
if ((type & 0x7F) == 0)
|
||||
int type = entryBuffer[2] & 0x7F;
|
||||
locked = (entryBuffer[2] & 0x80) != 0;
|
||||
|
||||
if (type == 0)
|
||||
fileType = FileType.Text;
|
||||
else if ((type & 0x01) > 0)
|
||||
else if ((type == 0x01))
|
||||
fileType = FileType.IntegerBasic;
|
||||
else if ((type & 0x02) > 0)
|
||||
else if ((type == 0x02))
|
||||
fileType = FileType.ApplesoftBasic;
|
||||
else if ((type & 0x04) > 0)
|
||||
else if ((type == 0x04))
|
||||
fileType = FileType.Binary;
|
||||
else if ((type & 0x08) > 0)
|
||||
else if ((type == 0x08))
|
||||
fileType = FileType.SS;
|
||||
else if ((type & 0x10) > 0)
|
||||
else if ((type == 0x10))
|
||||
fileType = FileType.Relocatable;
|
||||
else if ((type & 0x20) > 0)
|
||||
else if ((type == 0x20))
|
||||
fileType = FileType.AA;
|
||||
else if ((type & 0x40) > 0)
|
||||
else if ((type == 0x40))
|
||||
fileType = FileType.BB;
|
||||
else
|
||||
System.out.println ("Unknown file type : " + (type & 0x7F));
|
||||
System.out.println ("Unknown file type : " + type);
|
||||
|
||||
name = getName ("", entryBuffer);
|
||||
lastModified = Utility.getDateTime (entryBuffer, 0x1B);
|
||||
// CATALOG command only formats the LO byte - see Beneath Apple DOS pp4-6
|
||||
String base = String.format ("%s%s %03d ", (locked) ? "*" : " ", getFileType (),
|
||||
(entryBuffer[33] & 0xFF));
|
||||
@ -71,6 +75,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
{
|
||||
StringBuilder text = new StringBuilder (base);
|
||||
int max = buffer[0] == (byte) 0xFF ? 32 : 33;
|
||||
if (dosDisk.getVersion () >= 0x41)
|
||||
max = 27;
|
||||
for (int i = 3; i < max; i++)
|
||||
{
|
||||
int c = buffer[i] & 0xFF;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.bytezone.diskbrowser.dos;
|
||||
|
||||
import com.bytezone.diskbrowser.disk.AppleDiskAddress;
|
||||
import com.bytezone.diskbrowser.disk.DiskAddress;
|
||||
import com.bytezone.diskbrowser.dos.DosDisk.FileType;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
@ -20,7 +21,7 @@ class CatalogEntry extends AbstractCatalogEntry
|
||||
DiskAddress da = disk.getDiskAddress (entryBuffer[0], entryBuffer[1]);
|
||||
|
||||
// Loop through all TS-list sectors
|
||||
loop: while (da.getBlock () > 0)
|
||||
loop: while (da.getBlock () > 0 || ((AppleDiskAddress) da).zeroFlag ())
|
||||
{
|
||||
if (dosDisk.stillAvailable (da))
|
||||
dosDisk.sectorTypes[da.getBlock ()] = dosDisk.tsListSector;
|
||||
@ -55,7 +56,7 @@ class CatalogEntry extends AbstractCatalogEntry
|
||||
sectorBuffer[i], sectorBuffer[i + 1], name.trim ());
|
||||
break loop;
|
||||
}
|
||||
if (da.getBlock () == 0)
|
||||
if (da.getBlock () == 0 && !((AppleDiskAddress) da).zeroFlag ())
|
||||
{
|
||||
if (fileType != FileType.Text)
|
||||
break;
|
||||
@ -132,6 +133,10 @@ class CatalogEntry extends AbstractCatalogEntry
|
||||
String lengthText = length == 0 ? "" : String.format ("$%4X %,6d", length, length);
|
||||
String message = "";
|
||||
String lockedFlag = (locked) ? "*" : " ";
|
||||
if (dosDisk.dosVTOCSector.dosVersion >= 0x41)
|
||||
{
|
||||
message = lastModified.toString ().replace ('T', ' ');
|
||||
}
|
||||
if (reportedSize != actualSize)
|
||||
message += "Bad size (" + reportedSize + ") ";
|
||||
if (dataSectors.size () == 0)
|
||||
|
@ -4,6 +4,7 @@ import com.bytezone.diskbrowser.disk.AbstractSector;
|
||||
import com.bytezone.diskbrowser.disk.Disk;
|
||||
import com.bytezone.diskbrowser.disk.DiskAddress;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
import com.bytezone.diskbrowser.utilities.Utility;
|
||||
|
||||
class DosCatalogSector extends AbstractSector
|
||||
{
|
||||
@ -12,73 +13,119 @@ class DosCatalogSector extends AbstractSector
|
||||
"SS file", "Relocatable file", "AA file", "BB file" };
|
||||
private static int CATALOG_ENTRY_SIZE = 35;
|
||||
|
||||
public DosCatalogSector (Disk disk, byte[] buffer, DiskAddress diskAddress)
|
||||
private final DosDisk dosDisk;
|
||||
|
||||
public DosCatalogSector (DosDisk dosDisk, Disk disk, byte[] buffer,
|
||||
DiskAddress diskAddress)
|
||||
{
|
||||
super (disk, buffer, diskAddress);
|
||||
this.dosDisk = dosDisk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createText ()
|
||||
{
|
||||
StringBuilder text = getHeader ("Catalog Sector");
|
||||
StringBuilder text =
|
||||
getHeader ("DOS " + dosDisk.getVersionText () + " Catalog Sector");
|
||||
addText (text, buffer, 0, 1, "Not used");
|
||||
addText (text, buffer, 1, 2, "Next catalog track/sector");
|
||||
addText (text, buffer, 3, 4, "Not used");
|
||||
addText (text, buffer, 7, 4, "Not used");
|
||||
|
||||
boolean dos4 = dosDisk.getVersion () > 3;
|
||||
|
||||
for (int i = 11; i <= 255; i += CATALOG_ENTRY_SIZE)
|
||||
{
|
||||
text.append ("\n");
|
||||
if (true)
|
||||
{
|
||||
if (buffer[i] == (byte) 0xFF)
|
||||
{
|
||||
addText (text, buffer, i + 0, 2,
|
||||
"DEL: file @ " + HexFormatter.format2 (buffer[i + 32]) + " "
|
||||
+ HexFormatter.format2 (buffer[i + 1]));
|
||||
addText (text, buffer, i + 2, 1, "DEL: File type " + getType (buffer[i + 2]));
|
||||
if (buffer[i + 3] == 0)
|
||||
addText (text, buffer, i + 3, 4, "");
|
||||
else
|
||||
addText (text, buffer, i + 3, 4, "DEL: " + getName (buffer, i));
|
||||
addTextAndDecimal (text, buffer, i + 33, 2, "DEL: Sector count");
|
||||
}
|
||||
else if (buffer[i] > 0)
|
||||
{
|
||||
addText (text, buffer, i + 0, 2, "TS list track/sector");
|
||||
addText (text, buffer, i + 2, 1, "File type " + getType (buffer[i + 2]));
|
||||
if (buffer[i + 3] == 0)
|
||||
addText (text, buffer, i + 3, 4, "");
|
||||
else
|
||||
{
|
||||
addText (text, buffer, i + 3, 4, getName (buffer, i));
|
||||
for (int j = 0; j < 24; j += 4)
|
||||
addText (text, buffer, i + j + 7, 4, "");
|
||||
addText (text, buffer, i + 31, 2, "");
|
||||
}
|
||||
addTextAndDecimal (text, buffer, i + 33, 2, "Sector count");
|
||||
}
|
||||
else
|
||||
{
|
||||
addText (text, buffer, i + 0, 2, "");
|
||||
addText (text, buffer, i + 2, 1, "");
|
||||
addText (text, buffer, i + 3, 4, "");
|
||||
addText (text, buffer, i + 33, 2, "");
|
||||
}
|
||||
}
|
||||
if (dos4)
|
||||
createDos4Text (text, i);
|
||||
else
|
||||
createDos3Text (text, i);
|
||||
}
|
||||
|
||||
text.deleteCharAt (text.length () - 1);
|
||||
return text.toString ();
|
||||
}
|
||||
|
||||
private String getName (byte[] buffer, int offset)
|
||||
private void createDos4Text (StringBuilder text, int i)
|
||||
{
|
||||
int track = buffer[i] & 0x3F;
|
||||
int sector = buffer[i + 1] & 0x1F;
|
||||
int fileType = buffer[i + 2] & 0x7F;
|
||||
|
||||
boolean deleteFlag = (buffer[i] & 0x80) != 0;
|
||||
boolean zeroTrackFlag = (buffer[i] & 0x40) != 0;
|
||||
boolean lockedFlag = (buffer[i + 2] & 0x80) != 0;
|
||||
|
||||
if (buffer[i] == 0 && !zeroTrackFlag)
|
||||
{
|
||||
addText (text, buffer, i + 0, 2, "");
|
||||
addText (text, buffer, i + 2, 1, "");
|
||||
addText (text, buffer, i + 3, 4, "");
|
||||
addText (text, buffer, i + 33, 2, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
addText (text, buffer, i, 1,
|
||||
String.format ("TS list track (%s, %s)", deleteFlag ? "deleted" : "not deleted",
|
||||
zeroTrackFlag ? "track zero" : "not track zero"));
|
||||
addText (text, buffer, i + 1, 1, "TS list sector");
|
||||
addText (text, buffer, i + 2, 1,
|
||||
String.format ("File type (%s)", lockedFlag ? "locked" : "unlocked"));
|
||||
addText (text, buffer, i + 3, 4, getName (buffer, i + 3, 24));
|
||||
for (int j = 0; j < 20; j += 4)
|
||||
addText (text, buffer, i + 7 + j, 4, "");
|
||||
addText (text, buffer, i + 27, 3,
|
||||
"Date/time initialised: " + Utility.getDateTime (buffer, i + 27));
|
||||
addText (text, buffer, i + 30, 3, "");
|
||||
addTextAndDecimal (text, buffer, i + 33, 2, "File size");
|
||||
}
|
||||
}
|
||||
|
||||
private void createDos3Text (StringBuilder text, int i)
|
||||
{
|
||||
if (buffer[i] == (byte) 0xFF) // file is deleted
|
||||
{
|
||||
addText (text, buffer, i, 2, "DEL: file @ " + HexFormatter.format2 (buffer[i + 32])
|
||||
+ " " + HexFormatter.format2 (buffer[i + 1]));
|
||||
addText (text, buffer, i + 2, 1, "DEL: File type " + getType (buffer[i + 2]));
|
||||
if (buffer[i + 3] == 0)
|
||||
addText (text, buffer, i + 3, 4, "");
|
||||
else
|
||||
addText (text, buffer, i + 3, 4, "DEL: " + getName (buffer, i + 3, 29));
|
||||
addTextAndDecimal (text, buffer, i + 33, 2, "DEL: Sector count");
|
||||
}
|
||||
else if (buffer[i] > 0) // file exists
|
||||
{
|
||||
addText (text, buffer, i, 2, "TS list track/sector");
|
||||
addText (text, buffer, i + 2, 1, "File type " + getType (buffer[i + 2]));
|
||||
if (buffer[i + 3] == 0)
|
||||
addText (text, buffer, i + 3, 4, "");
|
||||
else
|
||||
{
|
||||
addText (text, buffer, i + 3, 4, getName (buffer, i + 3, 30));
|
||||
for (int j = 0; j < 24; j += 4)
|
||||
addText (text, buffer, i + j + 7, 4, "");
|
||||
addText (text, buffer, i + 31, 2, "");
|
||||
}
|
||||
addTextAndDecimal (text, buffer, i + 33, 2, "Sector count");
|
||||
}
|
||||
else // no file
|
||||
{
|
||||
addText (text, buffer, i + 0, 2, "");
|
||||
addText (text, buffer, i + 2, 1, "");
|
||||
addText (text, buffer, i + 3, 4, "");
|
||||
addText (text, buffer, i + 33, 2, "");
|
||||
}
|
||||
}
|
||||
|
||||
private String getName (byte[] buffer, int offset, int length)
|
||||
{
|
||||
StringBuilder text = new StringBuilder ();
|
||||
int max = buffer[offset] == (byte) 0xFF ? 32 : 33;
|
||||
for (int i = 3; i < max; i++)
|
||||
// int max = buffer[offset] == (byte) 0xFF ? 32 : 33;
|
||||
for (int i = offset; i < offset + length; i++)
|
||||
{
|
||||
int c = buffer[i + offset] & 0xFF;
|
||||
int c = buffer[i] & 0xFF;
|
||||
if (c == 136)
|
||||
{
|
||||
if (text.length () > 0)
|
||||
@ -87,10 +134,10 @@ class DosCatalogSector extends AbstractSector
|
||||
}
|
||||
if (c > 127)
|
||||
c -= c < 160 ? 64 : 128;
|
||||
if (c < 32) // non-printable
|
||||
if (c < 32) // non-printable
|
||||
text.append ("^" + (char) (c + 64));
|
||||
else
|
||||
text.append ((char) c); // standard ascii
|
||||
text.append ((char) c); // standard ascii
|
||||
}
|
||||
return text.toString ();
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public class DosDisk extends AbstractFormattedDisk
|
||||
private static final int CATALOG_TRACK = 17;
|
||||
private static final int VTOC_SECTOR = 0;
|
||||
|
||||
private final DosVTOCSector dosVTOCSector;
|
||||
final DosVTOCSector dosVTOCSector;
|
||||
private final Color green = new Color (0, 200, 0);
|
||||
private final DefaultMutableTreeNode volumeNode;
|
||||
|
||||
@ -152,6 +152,12 @@ public class DosDisk extends AbstractFormattedDisk
|
||||
|
||||
int track = sectorBuffer[1] & 0xFF;
|
||||
int sector = sectorBuffer[2] & 0xFF;
|
||||
if (dosVTOCSector.dosVersion >= 0x41)
|
||||
{
|
||||
track = track & 0x3F;
|
||||
sector = sector & 0x1F;
|
||||
}
|
||||
|
||||
if (!disk.isValidAddress (track, sector))
|
||||
break;
|
||||
|
||||
@ -254,6 +260,28 @@ public class DosDisk extends AbstractFormattedDisk
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getVersionText ()
|
||||
{
|
||||
switch (getVersion ())
|
||||
{
|
||||
case 0x01:
|
||||
return "3.1";
|
||||
case 0x02:
|
||||
return "3.2";
|
||||
case 0x03:
|
||||
return "3.3";
|
||||
case 0x41:
|
||||
return "4.1";
|
||||
default:
|
||||
return "??";
|
||||
}
|
||||
}
|
||||
|
||||
public int getVersion ()
|
||||
{
|
||||
return dosVTOCSector.dosVersion;
|
||||
}
|
||||
|
||||
private static int checkFormat (AppleDisk disk)
|
||||
{
|
||||
byte[] buffer = disk.readSector (0x11, 0x00);
|
||||
@ -272,10 +300,10 @@ public class DosDisk extends AbstractFormattedDisk
|
||||
// // return 0;
|
||||
// }
|
||||
|
||||
int version = buffer[3];
|
||||
if (version < -1 || version > 4)
|
||||
int version = buffer[3] & 0xFF;
|
||||
if (version > 0x42 && version != 0xFF)
|
||||
{
|
||||
System.out.println ("Bad version : " + buffer[3]);
|
||||
System.out.printf ("Bad version : %02X%n", version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -347,7 +375,7 @@ public class DosDisk extends AbstractFormattedDisk
|
||||
if (type == tsListSector)
|
||||
return new DosTSListSector (getSectorFilename (da), disk, buffer, da);
|
||||
if (type == catalogSector)
|
||||
return new DosCatalogSector (disk, buffer, da);
|
||||
return new DosCatalogSector (this, disk, buffer, da);
|
||||
if (type == dataSector)
|
||||
return new DefaultSector (
|
||||
"Data Sector at " + address + " : " + getSectorFilename (da), disk, buffer, da);
|
||||
@ -369,7 +397,7 @@ public class DosDisk extends AbstractFormattedDisk
|
||||
{
|
||||
String newLine = String.format ("%n");
|
||||
String line = "- --- --- ------------------------------ ----- -------------"
|
||||
+ " -- ---- ----------------" + newLine;
|
||||
+ " -- ---- -------------------" + newLine;
|
||||
StringBuilder text = new StringBuilder ();
|
||||
text.append (String.format ("Disk : %s%n%n", getAbsolutePath ()));
|
||||
text.append ("L Typ Len Name Addr"
|
||||
@ -405,33 +433,33 @@ public class DosDisk extends AbstractFormattedDisk
|
||||
}
|
||||
|
||||
/* From http://apple2history.org/history/ah15/
|
||||
*
|
||||
There were actually three versions of DOS 3.3 that Apple released without
|
||||
*
|
||||
There were actually three versions of DOS 3.3 that Apple released without
|
||||
bumping the version number:
|
||||
|
||||
The first version that was released had FPBASIC and INTBASIC files that were 50
|
||||
sectors in size.
|
||||
|
||||
The second version of DOS 3.3, often referred to as “DOS 3.3e”, appeared at the
|
||||
time the Apple IIe was released. In this version, the FPBASIC and INTBASIC files
|
||||
were 42 sectors in size. The changes introduced at that time included code to turn
|
||||
off the IIe 80-column card at boot time, and an attempt to fix a bug in the APPEND
|
||||
command. This fix reportedly introduced an even worse bug, but as the command was
|
||||
not heavily used it did not make much of an impact on most programmers. The APPEND
|
||||
|
||||
The second version of DOS 3.3, often referred to as “DOS 3.3e”, appeared at the
|
||||
time the Apple IIe was released. In this version, the FPBASIC and INTBASIC files
|
||||
were 42 sectors in size. The changes introduced at that time included code to turn
|
||||
off the IIe 80-column card at boot time, and an attempt to fix a bug in the APPEND
|
||||
command. This fix reportedly introduced an even worse bug, but as the command was
|
||||
not heavily used it did not make much of an impact on most programmers. The APPEND
|
||||
fix was applied by utilizing some formerly unused space in the DOS 3.3 code.
|
||||
|
||||
The third version of DOS 3.3 appeared just before the first release of ProDOS.
|
||||
The only mention of this in the press was in the DOSTalk column of Softalk magazine.
|
||||
This final version of DOS 3.3 included a different fix for the APPEND bug, using
|
||||
|
||||
The third version of DOS 3.3 appeared just before the first release of ProDOS.
|
||||
The only mention of this in the press was in the DOSTalk column of Softalk magazine.
|
||||
This final version of DOS 3.3 included a different fix for the APPEND bug, using
|
||||
another bit of unused space in DOS 3.3.
|
||||
|
||||
With regard to the FPBASIC and INTBASIC files: There were three differences between
|
||||
the 50 sector and the 42 sector versions of the INTBASIC file. Firstly, the
|
||||
$F800-$FFFF section was removed. This area was the code for the Monitor, and with
|
||||
the changes introduced in the Apple IIe, it could cause some things to “break” if
|
||||
the older Monitor code was executed. Secondly, a FOR/NEXT bug in Integer BASIC was
|
||||
fixed. Finally, there was a three-byte bug in the Programmer’s Aid ROM #1 chip.
|
||||
The code for this chip was included in the INTBASIC file, and could therefore be
|
||||
With regard to the FPBASIC and INTBASIC files: There were three differences between
|
||||
the 50 sector and the 42 sector versions of the INTBASIC file. Firstly, the
|
||||
$F800-$FFFF section was removed. This area was the code for the Monitor, and with
|
||||
the changes introduced in the Apple IIe, it could cause some things to “break” if
|
||||
the older Monitor code was executed. Secondly, a FOR/NEXT bug in Integer BASIC was
|
||||
fixed. Finally, there was a three-byte bug in the Programmer’s Aid ROM #1 chip.
|
||||
The code for this chip was included in the INTBASIC file, and could therefore be
|
||||
patched.
|
||||
*/
|
||||
}
|
@ -4,12 +4,13 @@ import com.bytezone.diskbrowser.disk.AbstractSector;
|
||||
import com.bytezone.diskbrowser.disk.Disk;
|
||||
import com.bytezone.diskbrowser.disk.DiskAddress;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
import com.bytezone.diskbrowser.utilities.Utility;
|
||||
|
||||
class DosVTOCSector extends AbstractSector
|
||||
{
|
||||
DosDisk parentDisk;
|
||||
int volume;
|
||||
int DOSVersion;
|
||||
int dosVersion; // 1, 2, 3 or 0x41...
|
||||
int maxTSPairs;
|
||||
int lastAllocTrack;
|
||||
int direction;
|
||||
@ -25,7 +26,7 @@ class DosVTOCSector extends AbstractSector
|
||||
super (disk, buffer, diskAddress);
|
||||
|
||||
this.parentDisk = parentDisk;
|
||||
DOSVersion = buffer[3];
|
||||
dosVersion = buffer[3];
|
||||
volume = buffer[6] & 0xFF;
|
||||
maxTSPairs = buffer[39];
|
||||
lastAllocTrack = buffer[48];
|
||||
@ -38,6 +39,63 @@ class DosVTOCSector extends AbstractSector
|
||||
|
||||
@Override
|
||||
public String createText ()
|
||||
{
|
||||
return dosVersion <= 3 ? createDosText () : createOtherText ();
|
||||
}
|
||||
|
||||
private String createOtherText ()
|
||||
{
|
||||
StringBuilder text = getHeader ("DOS 4.1 VTOC Sector");
|
||||
addText (text, buffer, 0, 1, "Not used");
|
||||
addText (text, buffer, 1, 2, "First directory track/sector");
|
||||
addText (text, buffer, 3, 1, "DOS release number");
|
||||
addText (text, buffer, 4, 1, "Build number");
|
||||
addText (text, buffer, 5, 1, "Ram DOS " + (char) (buffer[5] & 0x7F));
|
||||
|
||||
addTextAndDecimal (text, buffer, 6, 1, "Diskette volume");
|
||||
addText (text, buffer, 7, 1, "Volume type " + (char) (buffer[7] & 0x7F));
|
||||
|
||||
int ptr = 8;
|
||||
addText (text, buffer, ptr, 4, "Volume name: " + getName (buffer, ptr));
|
||||
for (int j = 4; j < 24; j += 4)
|
||||
addText (text, buffer, ptr + j, 4, "");
|
||||
|
||||
addText (text, buffer, 0x20, 3,
|
||||
"Date/time initialised: " + Utility.getDateTime (buffer, 0x20));
|
||||
addText (text, buffer, 0x23, 3, "");
|
||||
addText (text, buffer, 0x26, 1, "Not used");
|
||||
|
||||
addTextAndDecimal (text, buffer, 0x27, 1, "Maximum TS pairs");
|
||||
addText (text, buffer, 0x28, 2, "Volume library");
|
||||
addText (text, buffer, 0x2A, 3,
|
||||
"Date/time modified: " + Utility.getDateTime (buffer, 0x2A));
|
||||
addText (text, buffer, 0x2D, 3, "");
|
||||
|
||||
addTextAndDecimal (text, buffer, 0x30, 1, "Last allocated track");
|
||||
addText (text, buffer, 0x31, 1, "Direction to look when allocating the next file");
|
||||
addText (text, buffer, 0x32, 2, "Not used");
|
||||
addTextAndDecimal (text, buffer, 0x34, 1, "Maximum tracks");
|
||||
addTextAndDecimal (text, buffer, 0x35, 1, "Maximum sectors");
|
||||
addTextAndDecimal (text, buffer, 0x36, 2, "Bytes per sector");
|
||||
|
||||
boolean bootSectorEmpty = parentDisk.getDisk ().isSectorEmpty (0);
|
||||
for (int i = 0x38; i <= 0xC3; i += 4)
|
||||
{
|
||||
String extra = "";
|
||||
if (i == 0x38 && bootSectorEmpty)
|
||||
extra = "(unusable)";
|
||||
else if (i == 124)
|
||||
extra = "(VTOC and Catalog)";
|
||||
addText (text, buffer, i, 4, String.format ("Track %02X %s %s", (i - 56) / 4,
|
||||
getBitmap (buffer[i], buffer[i + 1]), extra));
|
||||
}
|
||||
|
||||
text.deleteCharAt (text.length () - 1);
|
||||
|
||||
return text.toString ();
|
||||
}
|
||||
|
||||
private String createDosText ()
|
||||
{
|
||||
StringBuilder text = getHeader ("VTOC Sector");
|
||||
addText (text, buffer, 0, 1, "Not used");
|
||||
@ -138,11 +196,35 @@ class DosVTOCSector extends AbstractSector
|
||||
return block;
|
||||
}
|
||||
|
||||
// duplicate of DosCatalogSector.getName()
|
||||
private String getName (byte[] buffer, int offset)
|
||||
{
|
||||
StringBuilder text = new StringBuilder ();
|
||||
int max = 24;
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
int c = buffer[i + offset] & 0xFF;
|
||||
if (c == 136)
|
||||
{
|
||||
if (text.length () > 0)
|
||||
text.deleteCharAt (text.length () - 1);
|
||||
continue;
|
||||
}
|
||||
if (c > 127)
|
||||
c -= c < 160 ? 64 : 128;
|
||||
if (c < 32) // non-printable
|
||||
text.append ("^" + (char) (c + 64));
|
||||
else
|
||||
text.append ((char) c); // standard ascii
|
||||
}
|
||||
return text.toString ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
StringBuffer text = new StringBuffer ();
|
||||
text.append ("DOS version : 3." + DOSVersion);
|
||||
text.append ("DOS version : 3." + dosVersion);
|
||||
text.append ("\nVolume : " + volume);
|
||||
text.append ("\nMax TS pairs : " + maxTSPairs);
|
||||
text.append ("\nLast allocated T : " + lastAllocTrack);
|
||||
|
@ -7,6 +7,7 @@ import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.bytezone.diskbrowser.disk.AppleDiskAddress;
|
||||
import com.bytezone.diskbrowser.disk.Disk;
|
||||
import com.bytezone.diskbrowser.disk.DiskAddress;
|
||||
import com.bytezone.diskbrowser.disk.FormattedDisk;
|
||||
@ -152,7 +153,7 @@ class DiskLayoutSelection implements Iterable<DiskAddress>
|
||||
highlights.clear ();
|
||||
if (list != null)
|
||||
for (DiskAddress da : list)
|
||||
if (da != null && da.getBlock () > 0)
|
||||
if (da != null && (da.getBlock () > 0 || ((AppleDiskAddress) da).zeroFlag ()))
|
||||
highlights.add (da);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ package com.bytezone.diskbrowser.utilities;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@ -58,6 +60,24 @@ public class Utility
|
||||
return false;
|
||||
}
|
||||
|
||||
public static LocalDateTime getDateTime (byte[] buffer, int ptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
int[] val = new int[6];
|
||||
for (int i = 0; i < 6; i++)
|
||||
val[i] = Integer.parseInt (String.format ("%02X", buffer[ptr + i] & 0xFF));
|
||||
|
||||
LocalDateTime date =
|
||||
LocalDateTime.of (val[3] + 2000, val[5], val[4], val[2], val[1], val[0]);
|
||||
return date;
|
||||
}
|
||||
catch (DateTimeException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean matches (byte[] buffer, int offset, byte[] key)
|
||||
{
|
||||
int ptr = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user