From 1b5f3f95a92388446d689886d1f9f34818f743a3 Mon Sep 17 00:00:00 2001 From: Denis Molony Date: Fri, 25 Jan 2019 15:57:15 +1100 Subject: [PATCH] DOS 4.1 changes --- .../diskbrowser/applefile/SimpleText2.java | 8 +- .../bytezone/diskbrowser/disk/AppleDisk.java | 10 +- .../diskbrowser/disk/AppleDiskAddress.java | 20 ++- .../diskbrowser/dos/AbstractCatalogEntry.java | 30 ++-- .../diskbrowser/dos/CatalogEntry.java | 9 +- .../diskbrowser/dos/DosCatalogSector.java | 137 ++++++++++++------ src/com/bytezone/diskbrowser/dos/DosDisk.java | 80 ++++++---- .../diskbrowser/dos/DosVTOCSector.java | 88 ++++++++++- .../diskbrowser/gui/DiskLayoutSelection.java | 3 +- .../diskbrowser/utilities/Utility.java | 20 +++ 10 files changed, 306 insertions(+), 99 deletions(-) diff --git a/src/com/bytezone/diskbrowser/applefile/SimpleText2.java b/src/com/bytezone/diskbrowser/applefile/SimpleText2.java index 3833f71..f81112f 100755 --- a/src/com/bytezone/diskbrowser/applefile/SimpleText2.java +++ b/src/com/bytezone/diskbrowser/applefile/SimpleText2.java @@ -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 (); diff --git a/src/com/bytezone/diskbrowser/disk/AppleDisk.java b/src/com/bytezone/diskbrowser/disk/AppleDisk.java index a99e977..b539544 100755 --- a/src/com/bytezone/diskbrowser/disk/AppleDisk.java +++ b/src/com/bytezone/diskbrowser/disk/AppleDisk.java @@ -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; } diff --git a/src/com/bytezone/diskbrowser/disk/AppleDiskAddress.java b/src/com/bytezone/diskbrowser/disk/AppleDiskAddress.java index 4ae196f..7138678 100755 --- a/src/com/bytezone/diskbrowser/disk/AppleDiskAddress.java +++ b/src/com/bytezone/diskbrowser/disk/AppleDiskAddress.java @@ -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); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/dos/AbstractCatalogEntry.java b/src/com/bytezone/diskbrowser/dos/AbstractCatalogEntry.java index d2928dc..78d8ae9 100644 --- a/src/com/bytezone/diskbrowser/dos/AbstractCatalogEntry.java +++ b/src/com/bytezone/diskbrowser/dos/AbstractCatalogEntry.java @@ -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 dataSectors = new ArrayList (); @@ -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; diff --git a/src/com/bytezone/diskbrowser/dos/CatalogEntry.java b/src/com/bytezone/diskbrowser/dos/CatalogEntry.java index 1428db0..1f12940 100644 --- a/src/com/bytezone/diskbrowser/dos/CatalogEntry.java +++ b/src/com/bytezone/diskbrowser/dos/CatalogEntry.java @@ -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) diff --git a/src/com/bytezone/diskbrowser/dos/DosCatalogSector.java b/src/com/bytezone/diskbrowser/dos/DosCatalogSector.java index 86fe5fc..c711634 100755 --- a/src/com/bytezone/diskbrowser/dos/DosCatalogSector.java +++ b/src/com/bytezone/diskbrowser/dos/DosCatalogSector.java @@ -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 (); } diff --git a/src/com/bytezone/diskbrowser/dos/DosDisk.java b/src/com/bytezone/diskbrowser/dos/DosDisk.java index 427afda..ba2f4e1 100755 --- a/src/com/bytezone/diskbrowser/dos/DosDisk.java +++ b/src/com/bytezone/diskbrowser/dos/DosDisk.java @@ -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. */ } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/dos/DosVTOCSector.java b/src/com/bytezone/diskbrowser/dos/DosVTOCSector.java index 5c68f6f..23415d7 100755 --- a/src/com/bytezone/diskbrowser/dos/DosVTOCSector.java +++ b/src/com/bytezone/diskbrowser/dos/DosVTOCSector.java @@ -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); diff --git a/src/com/bytezone/diskbrowser/gui/DiskLayoutSelection.java b/src/com/bytezone/diskbrowser/gui/DiskLayoutSelection.java index f289543..1d96af7 100755 --- a/src/com/bytezone/diskbrowser/gui/DiskLayoutSelection.java +++ b/src/com/bytezone/diskbrowser/gui/DiskLayoutSelection.java @@ -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 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); } diff --git a/src/com/bytezone/diskbrowser/utilities/Utility.java b/src/com/bytezone/diskbrowser/utilities/Utility.java index af81ef5..6089b18 100644 --- a/src/com/bytezone/diskbrowser/utilities/Utility.java +++ b/src/com/bytezone/diskbrowser/utilities/Utility.java @@ -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;