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,53 +13,104 @@ 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);
else
createDos3Text (text, i);
}
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
private void createDos4Text (StringBuilder text, int i)
{ {
if (buffer[i] == (byte) 0xFF) 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 + 0, 2, "");
"DEL: file @ " + HexFormatter.format2 (buffer[i + 32]) + " " addText (text, buffer, i + 2, 1, "");
+ HexFormatter.format2 (buffer[i + 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])); addText (text, buffer, i + 2, 1, "DEL: File type " + getType (buffer[i + 2]));
if (buffer[i + 3] == 0) if (buffer[i + 3] == 0)
addText (text, buffer, i + 3, 4, ""); addText (text, buffer, i + 3, 4, "");
else else
addText (text, buffer, i + 3, 4, "DEL: " + getName (buffer, i)); addText (text, buffer, i + 3, 4, "DEL: " + getName (buffer, i + 3, 29));
addTextAndDecimal (text, buffer, i + 33, 2, "DEL: Sector count"); addTextAndDecimal (text, buffer, i + 33, 2, "DEL: Sector count");
} }
else if (buffer[i] > 0) else if (buffer[i] > 0) // file exists
{ {
addText (text, buffer, i + 0, 2, "TS list track/sector"); addText (text, buffer, i, 2, "TS list track/sector");
addText (text, buffer, i + 2, 1, "File type " + getType (buffer[i + 2])); addText (text, buffer, i + 2, 1, "File type " + getType (buffer[i + 2]));
if (buffer[i + 3] == 0) if (buffer[i + 3] == 0)
addText (text, buffer, i + 3, 4, ""); addText (text, buffer, i + 3, 4, "");
else else
{ {
addText (text, buffer, i + 3, 4, getName (buffer, i)); addText (text, buffer, i + 3, 4, getName (buffer, i + 3, 30));
for (int j = 0; j < 24; j += 4) for (int j = 0; j < 24; j += 4)
addText (text, buffer, i + j + 7, 4, ""); addText (text, buffer, i + j + 7, 4, "");
addText (text, buffer, i + 31, 2, ""); addText (text, buffer, i + 31, 2, "");
} }
addTextAndDecimal (text, buffer, i + 33, 2, "Sector count"); addTextAndDecimal (text, buffer, i + 33, 2, "Sector count");
} }
else else // no file
{ {
addText (text, buffer, i + 0, 2, ""); addText (text, buffer, i + 0, 2, "");
addText (text, buffer, i + 2, 1, ""); addText (text, buffer, i + 2, 1, "");
@ -66,19 +118,14 @@ class DosCatalogSector extends AbstractSector
addText (text, buffer, i + 33, 2, ""); addText (text, buffer, i + 33, 2, "");
} }
} }
}
text.deleteCharAt (text.length () - 1); private String getName (byte[] buffer, int offset, int length)
return text.toString ();
}
private String getName (byte[] buffer, int offset)
{ {
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)

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"

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;