DOS 4.1 changes

This commit is contained in:
Denis Molony 2019-01-25 15:57:15 +11:00
parent d9b656cfa0
commit 1b5f3f95a9
10 changed files with 306 additions and 99 deletions

View File

@ -18,7 +18,7 @@ public class SimpleText2 extends AbstractFile
// store a pointer to each new line // store a pointer to each new line
int ptr = 0; int ptr = 0;
while (buffer[ptr] != -1) while (ptr < buffer.length && buffer[ptr] != -1)
{ {
int length = buffer[ptr] & 0xFF; int length = buffer[ptr] & 0xFF;
lineStarts.add (ptr); lineStarts.add (ptr);
@ -37,6 +37,8 @@ public class SimpleText2 extends AbstractFile
for (Integer i : lineStarts) for (Integer i : lineStarts)
text.append (String.format ("%05X %s%n", i, getLine (i))); 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 (); return text.toString ();
} }
@ -46,8 +48,8 @@ public class SimpleText2 extends AbstractFile
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
for (Integer i : lineStarts) for (Integer i : lineStarts)
text.append (HexFormatter.formatNoHeader (buffer, i, (buffer[i] & 0xFF) + 1) text.append (
+ "\n"); HexFormatter.formatNoHeader (buffer, i, (buffer[i] & 0xFF) + 1) + "\n");
text.append (HexFormatter.formatNoHeader (buffer, buffer.length - 2, 2) + "\n"); text.append (HexFormatter.formatNoHeader (buffer, buffer.length - 2, 2) + "\n");
return text.toString (); return text.toString ();

View File

@ -396,7 +396,8 @@ public class AppleDisk implements Disk
int ptr = 0; int ptr = 0;
for (DiskAddress da : daList) 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); readBuffer (da, buffer, ptr);
ptr += sectorSize; ptr += sectorSize;
} }
@ -458,6 +459,9 @@ public class AppleDisk implements Disk
@Override @Override
public DiskAddress getDiskAddress (int track, int sector) public DiskAddress getDiskAddress (int track, int sector)
{ {
// track &= 0x3F;
// sector &= 0x1F;
if (!isValidAddress (track, sector)) if (!isValidAddress (track, sector))
{ {
System.out.println ("Invalid block : " + track + "/" + sector); System.out.println ("Invalid block : " + track + "/" + sector);
@ -502,10 +506,14 @@ public class AppleDisk implements Disk
@Override @Override
public boolean isValidAddress (int track, int sector) public boolean isValidAddress (int track, int sector)
{ {
track &= 0x3F;
sector &= 0x1F;
if (track < 0 || track >= this.tracks) if (track < 0 || track >= this.tracks)
return false; return false;
if (sector < 0 || sector >= this.sectors) if (sector < 0 || sector >= this.sectors)
return false; return false;
return true; return true;
} }

View File

@ -6,6 +6,7 @@ public class AppleDiskAddress implements DiskAddress
private final int track; private final int track;
private final int sector; private final int sector;
public final Disk owner; public final Disk owner;
private boolean zeroFlag;
public AppleDiskAddress (Disk owner, int block) public AppleDiskAddress (Disk owner, int block)
{ {
@ -19,15 +20,15 @@ public class AppleDiskAddress implements DiskAddress
public AppleDiskAddress (Disk owner, int track, int sector) public AppleDiskAddress (Disk owner, int track, int sector)
{ {
this.owner = owner; this.owner = owner;
this.track = track; zeroFlag = (track & 0x40) != 0;
this.sector = sector; this.track = track & 0x3F;
this.block = track * owner.getSectorsPerTrack () + sector; this.sector = sector & 0x1F;
this.block = this.track * owner.getSectorsPerTrack () + this.sector;
} }
@Override public boolean zeroFlag ()
public String toString ()
{ {
return String.format ("[Block=%3d, Track=%2d, Sector=%2d]", block, track, sector); return zeroFlag;
} }
@Override @Override
@ -65,4 +66,11 @@ public class AppleDiskAddress implements DiskAddress
{ {
return owner; return owner;
} }
@Override
public String toString ()
{
return String.format ("[Block=%3d, Track=%2d, Sector=%2d, Zero=%s]", block, track,
sector, zeroFlag);
}
} }

View File

@ -1,5 +1,6 @@
package com.bytezone.diskbrowser.dos; package com.bytezone.diskbrowser.dos;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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.dos.DosDisk.FileType;
import com.bytezone.diskbrowser.gui.DataSource; import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
abstract class AbstractCatalogEntry implements AppleFileSource abstract class AbstractCatalogEntry implements AppleFileSource
{ {
@ -22,6 +24,7 @@ abstract class AbstractCatalogEntry implements AppleFileSource
protected int reportedSize; protected int reportedSize;
protected boolean locked; protected boolean locked;
protected DataSource appleFile; protected DataSource appleFile;
protected LocalDateTime lastModified;
protected DiskAddress catalogSectorDA; protected DiskAddress catalogSectorDA;
protected final List<DiskAddress> dataSectors = new ArrayList<DiskAddress> (); protected final List<DiskAddress> dataSectors = new ArrayList<DiskAddress> ();
@ -34,33 +37,34 @@ abstract class AbstractCatalogEntry implements AppleFileSource
{ {
this.dosDisk = dosDisk; this.dosDisk = dosDisk;
this.disk = dosDisk.getDisk (); this.disk = dosDisk.getDisk ();
this.disk = dosDisk.getDisk ();
this.catalogSectorDA = catalogSector; this.catalogSectorDA = catalogSector;
reportedSize = HexFormatter.unsignedShort (entryBuffer, 33); 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; fileType = FileType.Text;
else if ((type & 0x01) > 0) else if ((type == 0x01))
fileType = FileType.IntegerBasic; fileType = FileType.IntegerBasic;
else if ((type & 0x02) > 0) else if ((type == 0x02))
fileType = FileType.ApplesoftBasic; fileType = FileType.ApplesoftBasic;
else if ((type & 0x04) > 0) else if ((type == 0x04))
fileType = FileType.Binary; fileType = FileType.Binary;
else if ((type & 0x08) > 0) else if ((type == 0x08))
fileType = FileType.SS; fileType = FileType.SS;
else if ((type & 0x10) > 0) else if ((type == 0x10))
fileType = FileType.Relocatable; fileType = FileType.Relocatable;
else if ((type & 0x20) > 0) else if ((type == 0x20))
fileType = FileType.AA; fileType = FileType.AA;
else if ((type & 0x40) > 0) else if ((type == 0x40))
fileType = FileType.BB; fileType = FileType.BB;
else else
System.out.println ("Unknown file type : " + (type & 0x7F)); System.out.println ("Unknown file type : " + type);
name = getName ("", entryBuffer); name = getName ("", entryBuffer);
lastModified = Utility.getDateTime (entryBuffer, 0x1B);
// CATALOG command only formats the LO byte - see Beneath Apple DOS pp4-6 // CATALOG command only formats the LO byte - see Beneath Apple DOS pp4-6
String base = String.format ("%s%s %03d ", (locked) ? "*" : " ", getFileType (), String base = String.format ("%s%s %03d ", (locked) ? "*" : " ", getFileType (),
(entryBuffer[33] & 0xFF)); (entryBuffer[33] & 0xFF));
@ -71,6 +75,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
{ {
StringBuilder text = new StringBuilder (base); StringBuilder text = new StringBuilder (base);
int max = buffer[0] == (byte) 0xFF ? 32 : 33; int max = buffer[0] == (byte) 0xFF ? 32 : 33;
if (dosDisk.getVersion () >= 0x41)
max = 27;
for (int i = 3; i < max; i++) for (int i = 3; i < max; i++)
{ {
int c = buffer[i] & 0xFF; int c = buffer[i] & 0xFF;

View File

@ -1,5 +1,6 @@
package com.bytezone.diskbrowser.dos; package com.bytezone.diskbrowser.dos;
import com.bytezone.diskbrowser.disk.AppleDiskAddress;
import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.dos.DosDisk.FileType; import com.bytezone.diskbrowser.dos.DosDisk.FileType;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
@ -20,7 +21,7 @@ class CatalogEntry extends AbstractCatalogEntry
DiskAddress da = disk.getDiskAddress (entryBuffer[0], entryBuffer[1]); DiskAddress da = disk.getDiskAddress (entryBuffer[0], entryBuffer[1]);
// Loop through all TS-list sectors // Loop through all TS-list sectors
loop: while (da.getBlock () > 0) loop: while (da.getBlock () > 0 || ((AppleDiskAddress) da).zeroFlag ())
{ {
if (dosDisk.stillAvailable (da)) if (dosDisk.stillAvailable (da))
dosDisk.sectorTypes[da.getBlock ()] = dosDisk.tsListSector; dosDisk.sectorTypes[da.getBlock ()] = dosDisk.tsListSector;
@ -55,7 +56,7 @@ class CatalogEntry extends AbstractCatalogEntry
sectorBuffer[i], sectorBuffer[i + 1], name.trim ()); sectorBuffer[i], sectorBuffer[i + 1], name.trim ());
break loop; break loop;
} }
if (da.getBlock () == 0) if (da.getBlock () == 0 && !((AppleDiskAddress) da).zeroFlag ())
{ {
if (fileType != FileType.Text) if (fileType != FileType.Text)
break; break;
@ -132,6 +133,10 @@ class CatalogEntry extends AbstractCatalogEntry
String lengthText = length == 0 ? "" : String.format ("$%4X %,6d", length, length); String lengthText = length == 0 ? "" : String.format ("$%4X %,6d", length, length);
String message = ""; String message = "";
String lockedFlag = (locked) ? "*" : " "; String lockedFlag = (locked) ? "*" : " ";
if (dosDisk.dosVTOCSector.dosVersion >= 0x41)
{
message = lastModified.toString ().replace ('T', ' ');
}
if (reportedSize != actualSize) if (reportedSize != actualSize)
message += "Bad size (" + reportedSize + ") "; message += "Bad size (" + reportedSize + ") ";
if (dataSectors.size () == 0) if (dataSectors.size () == 0)

View File

@ -4,6 +4,7 @@ import com.bytezone.diskbrowser.disk.AbstractSector;
import com.bytezone.diskbrowser.disk.Disk; import com.bytezone.diskbrowser.disk.Disk;
import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
class DosCatalogSector extends AbstractSector class DosCatalogSector extends AbstractSector
{ {
@ -12,73 +13,119 @@ class DosCatalogSector extends AbstractSector
"SS file", "Relocatable file", "AA file", "BB file" }; "SS file", "Relocatable file", "AA file", "BB file" };
private static int CATALOG_ENTRY_SIZE = 35; 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); super (disk, buffer, diskAddress);
this.dosDisk = dosDisk;
} }
@Override @Override
public String createText () 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, 0, 1, "Not used");
addText (text, buffer, 1, 2, "Next catalog track/sector"); addText (text, buffer, 1, 2, "Next catalog track/sector");
addText (text, buffer, 3, 4, "Not used"); addText (text, buffer, 3, 4, "Not used");
addText (text, buffer, 7, 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) for (int i = 11; i <= 255; i += CATALOG_ENTRY_SIZE)
{ {
text.append ("\n"); text.append ("\n");
if (true) if (dos4)
{ createDos4Text (text, i);
if (buffer[i] == (byte) 0xFF) else
{ createDos3Text (text, i);
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, "");
}
}
} }
text.deleteCharAt (text.length () - 1); text.deleteCharAt (text.length () - 1);
return text.toString (); 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 (); StringBuilder text = new StringBuilder ();
int max = buffer[offset] == (byte) 0xFF ? 32 : 33; // int max = buffer[offset] == (byte) 0xFF ? 32 : 33;
for (int i = 3; i < max; i++) for (int i = offset; i < offset + length; i++)
{ {
int c = buffer[i + offset] & 0xFF; int c = buffer[i] & 0xFF;
if (c == 136) if (c == 136)
{ {
if (text.length () > 0) if (text.length () > 0)
@ -87,10 +134,10 @@ class DosCatalogSector extends AbstractSector
} }
if (c > 127) if (c > 127)
c -= c < 160 ? 64 : 128; c -= c < 160 ? 64 : 128;
if (c < 32) // non-printable if (c < 32) // non-printable
text.append ("^" + (char) (c + 64)); text.append ("^" + (char) (c + 64));
else else
text.append ((char) c); // standard ascii text.append ((char) c); // standard ascii
} }
return text.toString (); return text.toString ();
} }

View File

@ -18,7 +18,7 @@ public class DosDisk extends AbstractFormattedDisk
private static final int CATALOG_TRACK = 17; private static final int CATALOG_TRACK = 17;
private static final int VTOC_SECTOR = 0; 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 Color green = new Color (0, 200, 0);
private final DefaultMutableTreeNode volumeNode; private final DefaultMutableTreeNode volumeNode;
@ -152,6 +152,12 @@ public class DosDisk extends AbstractFormattedDisk
int track = sectorBuffer[1] & 0xFF; int track = sectorBuffer[1] & 0xFF;
int sector = sectorBuffer[2] & 0xFF; int sector = sectorBuffer[2] & 0xFF;
if (dosVTOCSector.dosVersion >= 0x41)
{
track = track & 0x3F;
sector = sector & 0x1F;
}
if (!disk.isValidAddress (track, sector)) if (!disk.isValidAddress (track, sector))
break; break;
@ -254,6 +260,28 @@ public class DosDisk extends AbstractFormattedDisk
return false; 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) private static int checkFormat (AppleDisk disk)
{ {
byte[] buffer = disk.readSector (0x11, 0x00); byte[] buffer = disk.readSector (0x11, 0x00);
@ -272,10 +300,10 @@ public class DosDisk extends AbstractFormattedDisk
// // return 0; // // return 0;
// } // }
int version = buffer[3]; int version = buffer[3] & 0xFF;
if (version < -1 || version > 4) if (version > 0x42 && version != 0xFF)
{ {
System.out.println ("Bad version : " + buffer[3]); System.out.printf ("Bad version : %02X%n", version);
return 0; return 0;
} }
@ -347,7 +375,7 @@ public class DosDisk extends AbstractFormattedDisk
if (type == tsListSector) if (type == tsListSector)
return new DosTSListSector (getSectorFilename (da), disk, buffer, da); return new DosTSListSector (getSectorFilename (da), disk, buffer, da);
if (type == catalogSector) if (type == catalogSector)
return new DosCatalogSector (disk, buffer, da); return new DosCatalogSector (this, disk, buffer, da);
if (type == dataSector) if (type == dataSector)
return new DefaultSector ( return new DefaultSector (
"Data Sector at " + address + " : " + getSectorFilename (da), disk, buffer, da); "Data Sector at " + address + " : " + getSectorFilename (da), disk, buffer, da);
@ -369,7 +397,7 @@ public class DosDisk extends AbstractFormattedDisk
{ {
String newLine = String.format ("%n"); String newLine = String.format ("%n");
String line = "- --- --- ------------------------------ ----- -------------" String line = "- --- --- ------------------------------ ----- -------------"
+ " -- ---- ----------------" + newLine; + " -- ---- -------------------" + newLine;
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append (String.format ("Disk : %s%n%n", getAbsolutePath ())); text.append (String.format ("Disk : %s%n%n", getAbsolutePath ()));
text.append ("L Typ Len Name Addr" text.append ("L Typ Len Name Addr"
@ -405,33 +433,33 @@ public class DosDisk extends AbstractFormattedDisk
} }
/* From http://apple2history.org/history/ah15/ /* 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: bumping the version number:
The first version that was released had FPBASIC and INTBASIC files that were 50 The first version that was released had FPBASIC and INTBASIC files that were 50
sectors in size. sectors in size.
The second version of DOS 3.3, often referred to as DOS 3.3e, appeared at the 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 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 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 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 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 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. 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 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. 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 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. another bit of unused space in DOS 3.3.
With regard to the FPBASIC and INTBASIC files: There were three differences between 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 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 $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 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 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 Programmers Aid ROM #1 chip. fixed. Finally, there was a three-byte bug in the Programmers Aid ROM #1 chip.
The code for this chip was included in the INTBASIC file, and could therefore be The code for this chip was included in the INTBASIC file, and could therefore be
patched. patched.
*/ */
} }

View File

@ -4,12 +4,13 @@ import com.bytezone.diskbrowser.disk.AbstractSector;
import com.bytezone.diskbrowser.disk.Disk; import com.bytezone.diskbrowser.disk.Disk;
import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
class DosVTOCSector extends AbstractSector class DosVTOCSector extends AbstractSector
{ {
DosDisk parentDisk; DosDisk parentDisk;
int volume; int volume;
int DOSVersion; int dosVersion; // 1, 2, 3 or 0x41...
int maxTSPairs; int maxTSPairs;
int lastAllocTrack; int lastAllocTrack;
int direction; int direction;
@ -25,7 +26,7 @@ class DosVTOCSector extends AbstractSector
super (disk, buffer, diskAddress); super (disk, buffer, diskAddress);
this.parentDisk = parentDisk; this.parentDisk = parentDisk;
DOSVersion = buffer[3]; dosVersion = buffer[3];
volume = buffer[6] & 0xFF; volume = buffer[6] & 0xFF;
maxTSPairs = buffer[39]; maxTSPairs = buffer[39];
lastAllocTrack = buffer[48]; lastAllocTrack = buffer[48];
@ -38,6 +39,63 @@ class DosVTOCSector extends AbstractSector
@Override @Override
public String createText () 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"); StringBuilder text = getHeader ("VTOC Sector");
addText (text, buffer, 0, 1, "Not used"); addText (text, buffer, 0, 1, "Not used");
@ -138,11 +196,35 @@ class DosVTOCSector extends AbstractSector
return block; 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 @Override
public String toString () public String toString ()
{ {
StringBuffer text = new StringBuffer (); StringBuffer text = new StringBuffer ();
text.append ("DOS version : 3." + DOSVersion); text.append ("DOS version : 3." + dosVersion);
text.append ("\nVolume : " + volume); text.append ("\nVolume : " + volume);
text.append ("\nMax TS pairs : " + maxTSPairs); text.append ("\nMax TS pairs : " + maxTSPairs);
text.append ("\nLast allocated T : " + lastAllocTrack); text.append ("\nLast allocated T : " + lastAllocTrack);

View File

@ -7,6 +7,7 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import com.bytezone.diskbrowser.disk.AppleDiskAddress;
import com.bytezone.diskbrowser.disk.Disk; import com.bytezone.diskbrowser.disk.Disk;
import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.disk.FormattedDisk; import com.bytezone.diskbrowser.disk.FormattedDisk;
@ -152,7 +153,7 @@ class DiskLayoutSelection implements Iterable<DiskAddress>
highlights.clear (); highlights.clear ();
if (list != null) if (list != null)
for (DiskAddress da : list) for (DiskAddress da : list)
if (da != null && da.getBlock () > 0) if (da != null && (da.getBlock () > 0 || ((AppleDiskAddress) da).zeroFlag ()))
highlights.add (da); highlights.add (da);
} }

View File

@ -2,6 +2,8 @@ package com.bytezone.diskbrowser.utilities;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -58,6 +60,24 @@ public class Utility
return false; 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) public static boolean matches (byte[] buffer, int offset, byte[] key)
{ {
int ptr = 0; int ptr = 0;