From add2b8f946fff8b1396147d556eda0de60157b29 Mon Sep 17 00:00:00 2001 From: Denis Molony Date: Sat, 8 Feb 2020 18:28:22 +1000 Subject: [PATCH] method header lines --- .../diskbrowser/dos/AbstractCatalogEntry.java | 33 +- .../diskbrowser/dos/CatalogEntry.java | 10 +- .../diskbrowser/dos/DeletedCatalogEntry.java | 16 +- .../diskbrowser/dos/DosCatalogSector.java | 319 ++--- src/com/bytezone/diskbrowser/dos/DosDisk.java | 1022 +++++++++-------- .../diskbrowser/dos/DosTSListSector.java | 172 +-- .../diskbrowser/dos/DosVTOCSector.java | 595 +++++----- 7 files changed, 1141 insertions(+), 1026 deletions(-) diff --git a/src/com/bytezone/diskbrowser/dos/AbstractCatalogEntry.java b/src/com/bytezone/diskbrowser/dos/AbstractCatalogEntry.java index 6261cdc..4648619 100644 --- a/src/com/bytezone/diskbrowser/dos/AbstractCatalogEntry.java +++ b/src/com/bytezone/diskbrowser/dos/AbstractCatalogEntry.java @@ -28,7 +28,9 @@ import com.bytezone.diskbrowser.gui.DataSource; import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.Utility; +// -----------------------------------------------------------------------------------// abstract class AbstractCatalogEntry implements AppleFileSource +// -----------------------------------------------------------------------------------// { protected Disk disk; protected DosDisk dosDisk; @@ -47,8 +49,9 @@ abstract class AbstractCatalogEntry implements AppleFileSource private CatalogEntry link; - public AbstractCatalogEntry (DosDisk dosDisk, DiskAddress catalogSector, - byte[] entryBuffer) + // ---------------------------------------------------------------------------------// + AbstractCatalogEntry (DosDisk dosDisk, DiskAddress catalogSector, byte[] entryBuffer) + // ---------------------------------------------------------------------------------// { this.dosDisk = dosDisk; this.disk = dosDisk.getDisk (); @@ -88,7 +91,9 @@ abstract class AbstractCatalogEntry implements AppleFileSource catalogName = getName (base, entryBuffer).replace ("^", ""); } + // ---------------------------------------------------------------------------------// private String getName (String base, byte[] buffer) + // ---------------------------------------------------------------------------------// { StringBuilder text = new StringBuilder (base); int max = buffer[0] == (byte) 0xFF ? 32 : 33; @@ -115,7 +120,9 @@ abstract class AbstractCatalogEntry implements AppleFileSource return text.toString (); } + // ---------------------------------------------------------------------------------// protected String getFileType () + // ---------------------------------------------------------------------------------// { switch (fileType) { @@ -143,15 +150,19 @@ abstract class AbstractCatalogEntry implements AppleFileSource // maybe this should be in the FormattedDisk // maybe DiskAddress should have a 'valid' flag + // ---------------------------------------------------------------------------------// protected DiskAddress getValidAddress (byte[] buffer, int offset) + // ---------------------------------------------------------------------------------// { if (disk.isValidAddress (buffer[offset], buffer[offset + 1])) return disk.getDiskAddress (buffer[offset], buffer[offset + 1]); return null; } + // ---------------------------------------------------------------------------------// @Override public DataSource getDataSource () + // ---------------------------------------------------------------------------------// { if (appleFile != null) return appleFile; @@ -297,7 +308,9 @@ abstract class AbstractCatalogEntry implements AppleFileSource return appleFile; } + // ---------------------------------------------------------------------------------// private byte[] getExactBuffer (byte[] buffer) + // ---------------------------------------------------------------------------------// { byte[] exactBuffer; @@ -319,14 +332,18 @@ abstract class AbstractCatalogEntry implements AppleFileSource return exactBuffer; } + // ---------------------------------------------------------------------------------// private boolean isRunCommand (byte[] buffer) + // ---------------------------------------------------------------------------------// { // see Stargate - Disk 1, Side A.woz return buffer[0] == 0x4C && buffer[1] == (byte) 0xFC && buffer[2] == (byte) 0xA4 && buffer[3] == 0x00; } + // ---------------------------------------------------------------------------------// private boolean isScrunched (int reportedLength) + // ---------------------------------------------------------------------------------// { if ((name.equals ("FLY LOGO") || name.equals ("FLY LOGO SCRUNCHED")) && reportedLength == 0x14FA) @@ -338,8 +355,10 @@ abstract class AbstractCatalogEntry implements AppleFileSource return false; } + // ---------------------------------------------------------------------------------// @Override public boolean contains (DiskAddress da) + // ---------------------------------------------------------------------------------// { for (DiskAddress sector : tsSectors) if (sector.matches (da)) @@ -354,21 +373,27 @@ abstract class AbstractCatalogEntry implements AppleFileSource return false; } + // ---------------------------------------------------------------------------------// @Override public String getUniqueName () + // ---------------------------------------------------------------------------------// { // this might not be unique if the file has been deleted return name; } + // ---------------------------------------------------------------------------------// @Override public FormattedDisk getFormattedDisk () + // ---------------------------------------------------------------------------------// { return dosDisk; } + // ---------------------------------------------------------------------------------// @Override public List getSectors () + // ---------------------------------------------------------------------------------// { List sectors = new ArrayList<> (); sectors.add (catalogSectorDA); @@ -377,13 +402,17 @@ abstract class AbstractCatalogEntry implements AppleFileSource return sectors; } + // ---------------------------------------------------------------------------------// void link (CatalogEntry catalogEntry) + // ---------------------------------------------------------------------------------// { this.link = catalogEntry; } + // ---------------------------------------------------------------------------------// @Override public String toString () + // ---------------------------------------------------------------------------------// { return catalogName; } diff --git a/src/com/bytezone/diskbrowser/dos/CatalogEntry.java b/src/com/bytezone/diskbrowser/dos/CatalogEntry.java index b1ad061..1051345 100644 --- a/src/com/bytezone/diskbrowser/dos/CatalogEntry.java +++ b/src/com/bytezone/diskbrowser/dos/CatalogEntry.java @@ -5,13 +5,17 @@ import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.dos.DosDisk.FileType; import com.bytezone.diskbrowser.utilities.HexFormatter; +// -----------------------------------------------------------------------------------// class CatalogEntry extends AbstractCatalogEntry +// -----------------------------------------------------------------------------------// { private int textFileGaps; private int length; private int address; - public CatalogEntry (DosDisk dosDisk, DiskAddress catalogSector, byte[] entryBuffer) + // ---------------------------------------------------------------------------------// + CatalogEntry (DosDisk dosDisk, DiskAddress catalogSector, byte[] entryBuffer) + // ---------------------------------------------------------------------------------// { super (dosDisk, catalogSector, entryBuffer); // build lists of ts and data sectors @@ -127,7 +131,9 @@ class CatalogEntry extends AbstractCatalogEntry } } - public String getDetails () + // ---------------------------------------------------------------------------------// + String getDetails () + // ---------------------------------------------------------------------------------// { int actualSize = dataSectors.size () + tsSectors.size () - textFileGaps; String addressText = address == 0 ? "" : String.format ("$%4X", address); diff --git a/src/com/bytezone/diskbrowser/dos/DeletedCatalogEntry.java b/src/com/bytezone/diskbrowser/dos/DeletedCatalogEntry.java index 8ec8a56..40b9a84 100644 --- a/src/com/bytezone/diskbrowser/dos/DeletedCatalogEntry.java +++ b/src/com/bytezone/diskbrowser/dos/DeletedCatalogEntry.java @@ -5,13 +5,17 @@ import com.bytezone.diskbrowser.disk.AppleDiskAddress; import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.gui.DataSource; +// -----------------------------------------------------------------------------------// class DeletedCatalogEntry extends AbstractCatalogEntry +// -----------------------------------------------------------------------------------// { boolean allSectorsAvailable = true; boolean debug = false; - public DeletedCatalogEntry (DosDisk dosDisk, DiskAddress catalogSector, - byte[] entryBuffer, int dosVersion) + // ---------------------------------------------------------------------------------// + DeletedCatalogEntry (DosDisk dosDisk, DiskAddress catalogSector, byte[] entryBuffer, + int dosVersion) + // ---------------------------------------------------------------------------------// { super (dosDisk, catalogSector, entryBuffer); @@ -93,15 +97,19 @@ class DeletedCatalogEntry extends AbstractCatalogEntry allSectorsAvailable = false; } + // ---------------------------------------------------------------------------------// @Override public String getUniqueName () + // ---------------------------------------------------------------------------------// { // name might not be unique if the file has been deleted return "!" + name; } + // ---------------------------------------------------------------------------------// @Override public DataSource getDataSource () + // ---------------------------------------------------------------------------------// { if (!allSectorsAvailable && appleFile == null) { @@ -112,7 +120,9 @@ class DeletedCatalogEntry extends AbstractCatalogEntry return super.getDataSource (); } - public String getDetails () + // ---------------------------------------------------------------------------------// + String getDetails () + // ---------------------------------------------------------------------------------// { return String.format ("%-30s %s", name, allSectorsAvailable ? "Recoverable" : "Not recoverable"); diff --git a/src/com/bytezone/diskbrowser/dos/DosCatalogSector.java b/src/com/bytezone/diskbrowser/dos/DosCatalogSector.java index f9ed8fb..ef1de0a 100755 --- a/src/com/bytezone/diskbrowser/dos/DosCatalogSector.java +++ b/src/com/bytezone/diskbrowser/dos/DosCatalogSector.java @@ -1,154 +1,167 @@ -package com.bytezone.diskbrowser.dos; - -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 -{ - private static final String[] fileTypes = - { "Text file", "Integer Basic program", "Applesoft Basic program", "Binary file", - "SS file", "Relocatable file", "AA file", "Lisa file" }; - private static int CATALOG_ENTRY_SIZE = 35; - - 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 ("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 (dos4) - createDos4Text (text, i); - else - createDos3Text (text, i); - } - - text.deleteCharAt (text.length () - 1); - return text.toString (); - } - - 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 = offset; i < offset + length; i++) - { - int c = buffer[i] & 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 (); - } - - private String getType (byte value) - { - int type = value & 0x7F; - boolean locked = (value & 0x80) > 0; - int val = 7; - for (int i = 64; i > type; val--, i /= 2) - ; - return "(" + fileTypes[val] + (locked ? ", locked)" : ", unlocked)"); - } +package com.bytezone.diskbrowser.dos; + +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 +// -----------------------------------------------------------------------------------// +{ + private static final String[] fileTypes = + { "Text file", "Integer Basic program", "Applesoft Basic program", "Binary file", + "SS file", "Relocatable file", "AA file", "Lisa file" }; + private static int CATALOG_ENTRY_SIZE = 35; + + private final DosDisk dosDisk; + + // ---------------------------------------------------------------------------------// + DosCatalogSector (DosDisk dosDisk, Disk disk, byte[] buffer, DiskAddress diskAddress) + // ---------------------------------------------------------------------------------// + { + super (disk, buffer, diskAddress); + this.dosDisk = dosDisk; + } + + // ---------------------------------------------------------------------------------// + @Override + public String createText () + // ---------------------------------------------------------------------------------// + { + 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 (dos4) + createDos4Text (text, i); + else + createDos3Text (text, i); + } + + text.deleteCharAt (text.length () - 1); + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + 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 = offset; i < offset + length; i++) + { + int c = buffer[i] & 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 (); + } + + // ---------------------------------------------------------------------------------// + private String getType (byte value) + // ---------------------------------------------------------------------------------// + { + int type = value & 0x7F; + boolean locked = (value & 0x80) > 0; + int val = 7; + for (int i = 64; i > type; val--, i /= 2) + ; + return "(" + fileTypes[val] + (locked ? ", locked)" : ", unlocked)"); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/dos/DosDisk.java b/src/com/bytezone/diskbrowser/dos/DosDisk.java index 63ddbe2..bad478a 100755 --- a/src/com/bytezone/diskbrowser/dos/DosDisk.java +++ b/src/com/bytezone/diskbrowser/dos/DosDisk.java @@ -1,497 +1,527 @@ -package com.bytezone.diskbrowser.dos; - -import java.awt.Color; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.tree.DefaultMutableTreeNode; - -import com.bytezone.diskbrowser.applefile.AppleFileSource; -import com.bytezone.diskbrowser.applefile.BootSector; -import com.bytezone.diskbrowser.disk.AbstractFormattedDisk; -import com.bytezone.diskbrowser.disk.AppleDisk; -import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; -import com.bytezone.diskbrowser.disk.DefaultSector; -import com.bytezone.diskbrowser.disk.Disk; -import com.bytezone.diskbrowser.disk.DiskAddress; -import com.bytezone.diskbrowser.disk.SectorType; -import com.bytezone.diskbrowser.gui.DataSource; - -public class DosDisk extends AbstractFormattedDisk -{ - private static final int ENTRY_SIZE = 35; - private static final int CATALOG_TRACK = 17; - private static final int VTOC_SECTOR = 0; - - final DosVTOCSector dosVTOCSector; - private final Color green = new Color (0, 200, 0); - private final DefaultMutableTreeNode volumeNode; - - private int freeSectors; - private int usedSectors; - private final int volumeNo; // for multi-volume disks - - public final SectorType vtocSector = new SectorType ("VTOC", Color.magenta); - public final SectorType catalogSector = new SectorType ("Catalog", green); - public final SectorType tsListSector = new SectorType ("TSList", Color.blue); - public final SectorType dataSector = new SectorType ("Data", Color.red); - public final SectorType dosSector = new SectorType ("DOS", Color.lightGray); - - protected List deletedFileEntries = new ArrayList<> (); - - enum FileType - { - Text, ApplesoftBasic, IntegerBasic, Binary, Relocatable, SS, AA, BB - } - - public DosDisk (Disk disk) - { - this (disk, 0); - } - - public DosDisk (Disk disk, int volumeNo) - { - super (disk); - - this.volumeNo = volumeNo; - - sectorTypesList.add (dosSector); - sectorTypesList.add (vtocSector); - sectorTypesList.add (catalogSector); - sectorTypesList.add (tsListSector); - sectorTypesList.add (dataSector); - - DiskAddress da = disk.getDiskAddress (0, 0); - byte[] sectorBuffer = disk.readSector (da); // Boot sector - bootSector = new BootSector (disk, sectorBuffer, "DOS", da); - - da = disk.getDiskAddress (CATALOG_TRACK, VTOC_SECTOR); - sectorBuffer = disk.readSector (da); // VTOC - dosVTOCSector = new DosVTOCSector (this, disk, sectorBuffer, da); - sectorTypes[da.getBlock ()] = vtocSector; - - DiskAddress catalogStart = disk.getDiskAddress (sectorBuffer[1], sectorBuffer[2]); - - if (dosVTOCSector.sectorSize != disk.getBlockSize ()) - System.out.println ("Invalid sector size : " + dosVTOCSector.sectorSize); - if (dosVTOCSector.maxSectors != disk.getSectorsPerTrack ()) - System.out.println ("Invalid sectors per track : " + dosVTOCSector.maxSectors); - - // sectorTypes[CATALOG_TRACK * dosVTOCSector.maxSectors] = vtocSector; - - // assert (maxTracks == disk.getTotalTracks ()); - // assert (dosVTOCSector.maxSectors == disk.getSectorsPerTrack ()); - // assert (sectorSize == disk.getBlockSize ()); HFSAssembler.dsk fails this - // assert (catalogStart.getTrack () == CATALOG_TRACK); - - // arcboot.dsk starts the catalog at 17/13 - // assert (catalogStart.getSector () == 15); - - // build list of CatalogEntry objects - DefaultMutableTreeNode rootNode = getCatalogTreeRoot (); - volumeNode = new DefaultMutableTreeNode (); - DefaultMutableTreeNode deletedFilesNode = new DefaultMutableTreeNode (); - rootNode.add (volumeNode); - - // flag the catalog sectors before any file mistakenly grabs them - da = disk.getDiskAddress (catalogStart.getBlock ()); - do - { - if (!disk.isValidAddress (da)) - break; - sectorBuffer = disk.readSector (da); - if (!disk.isValidAddress (sectorBuffer[1], sectorBuffer[2])) - break; - - // The first byte is officially unused, but it always seems to contain 0x00 or 0xFF - // See beautifulboot.dsk. - // if (sectorBuffer[0] != 0 && (sectorBuffer[0] & 0xFF) != 0xFF && false) - // { - // System.out - // .println ("Dos catalog sector buffer byte #0 invalid : " + sectorBuffer[0]); - // break; - // } - - sectorTypes[da.getBlock ()] = catalogSector; - - int track = sectorBuffer[1] & 0xFF; - int sector = sectorBuffer[2] & 0xFF; - if (!disk.isValidAddress (track, sector)) - break; - - da = disk.getDiskAddress (track, sector); - - } while (da.getBlock () != 0); - - // same loop, but now all the catalog sectors are properly flagged - da = disk.getDiskAddress (catalogStart.getBlock ()); - do - { - if (!disk.isValidAddress (da)) - break; - sectorBuffer = disk.readSector (da); - if (!disk.isValidAddress (sectorBuffer[1], sectorBuffer[2])) - break; - - for (int ptr = 11; ptr < 256; ptr += ENTRY_SIZE) - { - if (sectorBuffer[ptr] == 0) // empty slot, no more catalog entries - continue; - - byte[] entry = new byte[ENTRY_SIZE]; - System.arraycopy (sectorBuffer, ptr, entry, 0, ENTRY_SIZE); - int track = entry[0] & 0xFF; - boolean deletedFlag = (entry[0] & 0x80) != 0; - - if (deletedFlag) // deleted file - { - DeletedCatalogEntry deletedCatalogEntry = - new DeletedCatalogEntry (this, da, entry, dosVTOCSector.dosVersion); - deletedFileEntries.add (deletedCatalogEntry); - DefaultMutableTreeNode node = new DefaultMutableTreeNode (deletedCatalogEntry); - node.setAllowsChildren (false); - deletedFilesNode.add (node); - } - else - { - CatalogEntry catalogEntry = new CatalogEntry (this, da, entry); - fileEntries.add (catalogEntry); - DefaultMutableTreeNode node = new DefaultMutableTreeNode (catalogEntry); - node.setAllowsChildren (false); - volumeNode.add (node); - } - } - - 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; - - da = disk.getDiskAddress (sectorBuffer[1], sectorBuffer[2]); - - } while (da.getBlock () != 0); - - // link double hi-res files - for (AppleFileSource fe : fileEntries) - { - String name = fe.getUniqueName (); - if (name.endsWith (".AUX")) - { - String partner1 = name.substring (0, name.length () - 4); - String partner2 = partner1 + ".BIN"; - for (AppleFileSource fe2 : fileEntries) - if (fe2.getUniqueName ().equals (partner1) - || fe2.getUniqueName ().equals (partner2)) - { - ((CatalogEntry) fe2).link ((CatalogEntry) fe); - ((CatalogEntry) fe).link ((CatalogEntry) fe2); - } - } - } - - // add up all the free and used sectors, and label DOS sectors while we're here - int lastDosSector = dosVTOCSector.maxSectors * 3; // first three tracks - for (DiskAddress da2 : disk) - { - int blockNo = da2.getBlock (); - if (blockNo < lastDosSector) // in the DOS region - { - if (freeBlocks.get (blockNo)) // according to the VTOC - ++freeSectors; - else - { - ++usedSectors; - if (sectorTypes[blockNo] == usedSector) - sectorTypes[blockNo] = dosSector; - } - } - else - { - if (stillAvailable (da2)) // free or used, ie not specifically labelled - ++freeSectors; - else - ++usedSectors; - } - - if (freeBlocks.get (blockNo) && !stillAvailable (da2)) - falsePositives++; - if (!freeBlocks.get (blockNo) && stillAvailable (da2)) - falseNegatives++; - } - - if (deletedFilesNode.getDepth () > 0) - { - rootNode.add (deletedFilesNode); - deletedFilesNode.setUserObject (getDeletedList ()); - makeNodeVisible (deletedFilesNode.getFirstLeaf ()); - } - - volumeNode.setUserObject (getCatalog ()); - makeNodeVisible (volumeNode.getFirstLeaf ()); - } - - public int getVolumeNo () - { - return volumeNo; - } - - @Override - public void setOriginalPath (Path path) - { - super.setOriginalPath (path); - - // this has already been set in the constructor - volumeNode.setUserObject (getCatalog ()); - } - - // Beagle Bros FRAMEUP disk only has one catalog block - // ARCBOOT.DSK has a catalog which starts at sector 0C - public static boolean isCorrectFormat (AppleDisk disk) - { - disk.setInterleave (0); - int catalogBlocks = checkFormat (disk); - - if (catalogBlocks > 3) - return true; - - if (disk.getSectorsPerTrack () <= 16) - { - disk.setInterleave (1); - int cb2 = checkFormat (disk); - if (cb2 > 3) - return true; - disk.setInterleave (2); - if (true) - { - int cb3 = checkFormat (disk); - if (cb3 > 3) - return true; - } - - if (catalogBlocks > 0) - { - disk.setInterleave (1); - return true; - } - - if (cb2 > 0) - return true; - } - - 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"; - case 0x42: - return "4.2"; - case 0x43: - return "4.3"; - default: - return "??"; - } - } - - public int getVersion () - { - return dosVTOCSector.dosVersion; - } - - private static int checkFormat (AppleDisk disk) - { - byte[] buffer = disk.readSector (0x11, 0x00); - - // DISCCOMMANDER.DSK uses track 0x17 for the catalog - // if (buffer[1] != 0x11) // first catalog track - // return 0; - - if (buffer[53] != 16 && buffer[53] != 13 && buffer[53] != 32) // sectors per track - { - return 0; - } - - // if (buffer[49] < -1 || buffer[49] > 1) // direction of next file save - // { - // System.out.println ("Bad direction : " + buffer[49]); - // // Visicalc data disk had 0xF8 - // // return 0; - // } - - int version = buffer[3] & 0xFF; - if (version > 0x43 && version != 0xFF) - { - System.out.printf ("Bad version : %02X%n", version); - return 0; - } - - return countCatalogBlocks (disk, buffer); - } - - private static int countCatalogBlocks (AppleDisk disk, byte[] buffer) - { - DiskAddress catalogStart = disk.getDiskAddress (buffer[1], buffer[2]); - DiskAddress da = disk.getDiskAddress (catalogStart.getBlock ()); - List catalogAddresses = new ArrayList<> (); - - do - { - if (!disk.isValidAddress (da)) - return 0; - - if (catalogAddresses.contains (da)) - { - System.out.println ("Catalog looping"); - return 0; - } - - buffer = disk.readSector (da); - if (!disk.isValidAddress (buffer[1], buffer[2])) - return 0; - - catalogAddresses.add (da); - - da = disk.getDiskAddress (buffer[1], buffer[2]); - - } while (da.getBlock () != 0); - - return catalogAddresses.size (); - } - - @Override - public String toString () - { - // StringBuffer text = new StringBuffer (dosVTOCSector.toString ()); - // return text.toString (); - StringBuffer text = new StringBuffer (); - - text.append ( - String.format ("DOS version ........... %s%n", dosVTOCSector.dosVersion)); - text.append ( - String.format ("Sectors per track ..... %d%n", dosVTOCSector.maxSectors)); - text.append (String.format ("Volume no ............. %d", volumeNo)); - - return text.toString (); - } - - @Override - public DataSource getFormattedSector (DiskAddress da) - { - SectorType type = sectorTypes[da.getBlock ()]; - if (type == vtocSector) - return dosVTOCSector; - if (da.getBlock () == 0) - return bootSector; - - byte[] buffer = disk.readSector (da); - String address = String.format ("%02X %02X", da.getTrack (), da.getSector ()); - - if (type == tsListSector) - return new DosTSListSector (getSectorFilename (da), disk, buffer, da); - if (type == catalogSector) - return new DosCatalogSector (this, disk, buffer, da); - if (type == dataSector) - return new DefaultSector ( - "Data Sector at " + address + " : " + getSectorFilename (da), disk, buffer, da); - if (type == dosSector) - return new DefaultSector ("DOS sector at " + address, disk, buffer, da); - return super.getFormattedSector (da); - } - - @Override - public List getFileSectors (int fileNo) - { - if (fileEntries.size () > 0 && fileEntries.size () > fileNo) - return fileEntries.get (fileNo).getSectors (); - return null; - } - - @Override - public AppleFileSource getCatalog () - { - String newLine = String.format ("%n"); - String line = "- --- --- ------------------------------ ----- -------------" - + " -- ---- -------------------" + newLine; - StringBuilder text = new StringBuilder (); - text.append (String.format ("Disk : %s%n%n", getDisplayPath ())); - text.append ("L Typ Len Name Addr" - + " Length TS Data Comment" + newLine); - text.append (line); - - for (AppleFileSource fileEntry : fileEntries) - text.append (((CatalogEntry) fileEntry).getDetails () + newLine); - - text.append (line); - text.append (String.format ( - " Free sectors: %3d " + "Used sectors: %3d Total sectors: %3d", - dosVTOCSector.freeSectors, dosVTOCSector.usedSectors, - (dosVTOCSector.freeSectors + dosVTOCSector.usedSectors))); - if (dosVTOCSector.freeSectors != freeSectors) - text.append (String.format ( - "%nActual: Free sectors: %3d " - + "Used sectors: %3d Total sectors: %3d", - freeSectors, usedSectors, (usedSectors + freeSectors))); - - String volumeText = volumeNo == 0 ? "" : "Side " + volumeNo + " "; - return new DefaultAppleFileSource (volumeText + "Volume " + dosVTOCSector.volume, - text.toString (), this); - } - - private AppleFileSource getDeletedList () - { - StringBuilder text = - new StringBuilder ("List of files that were deleted from this disk\n"); - - for (AppleFileSource afs : deletedFileEntries) - text.append (((DeletedCatalogEntry) afs).getDetails () + "\n"); - - return new DefaultAppleFileSource ("Deleted files", text.toString (), this); - } - - /* From http://apple2history.org/history/ah15/ - * - 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 - 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 - 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 - patched. - */ +package com.bytezone.diskbrowser.dos; + +import java.awt.Color; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.bytezone.diskbrowser.applefile.AppleFileSource; +import com.bytezone.diskbrowser.applefile.BootSector; +import com.bytezone.diskbrowser.disk.AbstractFormattedDisk; +import com.bytezone.diskbrowser.disk.AppleDisk; +import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; +import com.bytezone.diskbrowser.disk.DefaultSector; +import com.bytezone.diskbrowser.disk.Disk; +import com.bytezone.diskbrowser.disk.DiskAddress; +import com.bytezone.diskbrowser.disk.SectorType; +import com.bytezone.diskbrowser.gui.DataSource; + +// -----------------------------------------------------------------------------------// +public class DosDisk extends AbstractFormattedDisk +// -----------------------------------------------------------------------------------// +{ + private static final int ENTRY_SIZE = 35; + private static final int CATALOG_TRACK = 17; + private static final int VTOC_SECTOR = 0; + + final DosVTOCSector dosVTOCSector; + private final Color green = new Color (0, 200, 0); + private final DefaultMutableTreeNode volumeNode; + + private int freeSectors; + private int usedSectors; + private final int volumeNo; // for multi-volume disks + + public final SectorType vtocSector = new SectorType ("VTOC", Color.magenta); + public final SectorType catalogSector = new SectorType ("Catalog", green); + public final SectorType tsListSector = new SectorType ("TSList", Color.blue); + public final SectorType dataSector = new SectorType ("Data", Color.red); + public final SectorType dosSector = new SectorType ("DOS", Color.lightGray); + + protected List deletedFileEntries = new ArrayList<> (); + + enum FileType + { + Text, ApplesoftBasic, IntegerBasic, Binary, Relocatable, SS, AA, BB + } + + // ---------------------------------------------------------------------------------// + public DosDisk (Disk disk) + // ---------------------------------------------------------------------------------// + { + this (disk, 0); + } + + // ---------------------------------------------------------------------------------// + public DosDisk (Disk disk, int volumeNo) + // ---------------------------------------------------------------------------------// + { + super (disk); + + this.volumeNo = volumeNo; + + sectorTypesList.add (dosSector); + sectorTypesList.add (vtocSector); + sectorTypesList.add (catalogSector); + sectorTypesList.add (tsListSector); + sectorTypesList.add (dataSector); + + DiskAddress da = disk.getDiskAddress (0, 0); + byte[] sectorBuffer = disk.readSector (da); // Boot sector + bootSector = new BootSector (disk, sectorBuffer, "DOS", da); + + da = disk.getDiskAddress (CATALOG_TRACK, VTOC_SECTOR); + sectorBuffer = disk.readSector (da); // VTOC + dosVTOCSector = new DosVTOCSector (this, disk, sectorBuffer, da); + sectorTypes[da.getBlock ()] = vtocSector; + + DiskAddress catalogStart = disk.getDiskAddress (sectorBuffer[1], sectorBuffer[2]); + + if (dosVTOCSector.sectorSize != disk.getBlockSize ()) + System.out.println ("Invalid sector size : " + dosVTOCSector.sectorSize); + if (dosVTOCSector.maxSectors != disk.getSectorsPerTrack ()) + System.out.println ("Invalid sectors per track : " + dosVTOCSector.maxSectors); + + // sectorTypes[CATALOG_TRACK * dosVTOCSector.maxSectors] = vtocSector; + + // assert (maxTracks == disk.getTotalTracks ()); + // assert (dosVTOCSector.maxSectors == disk.getSectorsPerTrack ()); + // assert (sectorSize == disk.getBlockSize ()); HFSAssembler.dsk fails this + // assert (catalogStart.getTrack () == CATALOG_TRACK); + + // arcboot.dsk starts the catalog at 17/13 + // assert (catalogStart.getSector () == 15); + + // build list of CatalogEntry objects + DefaultMutableTreeNode rootNode = getCatalogTreeRoot (); + volumeNode = new DefaultMutableTreeNode (); + DefaultMutableTreeNode deletedFilesNode = new DefaultMutableTreeNode (); + rootNode.add (volumeNode); + + // flag the catalog sectors before any file mistakenly grabs them + da = disk.getDiskAddress (catalogStart.getBlock ()); + do + { + if (!disk.isValidAddress (da)) + break; + sectorBuffer = disk.readSector (da); + if (!disk.isValidAddress (sectorBuffer[1], sectorBuffer[2])) + break; + + // The first byte is officially unused, but it always seems to contain 0x00 or 0xFF + // See beautifulboot.dsk. + // if (sectorBuffer[0] != 0 && (sectorBuffer[0] & 0xFF) != 0xFF && false) + // { + // System.out + // .println ("Dos catalog sector buffer byte #0 invalid : " + sectorBuffer[0]); + // break; + // } + + sectorTypes[da.getBlock ()] = catalogSector; + + int track = sectorBuffer[1] & 0xFF; + int sector = sectorBuffer[2] & 0xFF; + if (!disk.isValidAddress (track, sector)) + break; + + da = disk.getDiskAddress (track, sector); + + } while (da.getBlock () != 0); + + // same loop, but now all the catalog sectors are properly flagged + da = disk.getDiskAddress (catalogStart.getBlock ()); + do + { + if (!disk.isValidAddress (da)) + break; + sectorBuffer = disk.readSector (da); + if (!disk.isValidAddress (sectorBuffer[1], sectorBuffer[2])) + break; + + for (int ptr = 11; ptr < 256; ptr += ENTRY_SIZE) + { + if (sectorBuffer[ptr] == 0) // empty slot, no more catalog entries + continue; + + byte[] entry = new byte[ENTRY_SIZE]; + System.arraycopy (sectorBuffer, ptr, entry, 0, ENTRY_SIZE); + int track = entry[0] & 0xFF; + boolean deletedFlag = (entry[0] & 0x80) != 0; + + if (deletedFlag) // deleted file + { + DeletedCatalogEntry deletedCatalogEntry = + new DeletedCatalogEntry (this, da, entry, dosVTOCSector.dosVersion); + deletedFileEntries.add (deletedCatalogEntry); + DefaultMutableTreeNode node = new DefaultMutableTreeNode (deletedCatalogEntry); + node.setAllowsChildren (false); + deletedFilesNode.add (node); + } + else + { + CatalogEntry catalogEntry = new CatalogEntry (this, da, entry); + fileEntries.add (catalogEntry); + DefaultMutableTreeNode node = new DefaultMutableTreeNode (catalogEntry); + node.setAllowsChildren (false); + volumeNode.add (node); + } + } + + 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; + + da = disk.getDiskAddress (sectorBuffer[1], sectorBuffer[2]); + + } while (da.getBlock () != 0); + + // link double hi-res files + for (AppleFileSource fe : fileEntries) + { + String name = fe.getUniqueName (); + if (name.endsWith (".AUX")) + { + String partner1 = name.substring (0, name.length () - 4); + String partner2 = partner1 + ".BIN"; + for (AppleFileSource fe2 : fileEntries) + if (fe2.getUniqueName ().equals (partner1) + || fe2.getUniqueName ().equals (partner2)) + { + ((CatalogEntry) fe2).link ((CatalogEntry) fe); + ((CatalogEntry) fe).link ((CatalogEntry) fe2); + } + } + } + + // add up all the free and used sectors, and label DOS sectors while we're here + int lastDosSector = dosVTOCSector.maxSectors * 3; // first three tracks + for (DiskAddress da2 : disk) + { + int blockNo = da2.getBlock (); + if (blockNo < lastDosSector) // in the DOS region + { + if (freeBlocks.get (blockNo)) // according to the VTOC + ++freeSectors; + else + { + ++usedSectors; + if (sectorTypes[blockNo] == usedSector) + sectorTypes[blockNo] = dosSector; + } + } + else + { + if (stillAvailable (da2)) // free or used, ie not specifically labelled + ++freeSectors; + else + ++usedSectors; + } + + if (freeBlocks.get (blockNo) && !stillAvailable (da2)) + falsePositives++; + if (!freeBlocks.get (blockNo) && stillAvailable (da2)) + falseNegatives++; + } + + if (deletedFilesNode.getDepth () > 0) + { + rootNode.add (deletedFilesNode); + deletedFilesNode.setUserObject (getDeletedList ()); + makeNodeVisible (deletedFilesNode.getFirstLeaf ()); + } + + volumeNode.setUserObject (getCatalog ()); + makeNodeVisible (volumeNode.getFirstLeaf ()); + } + + // ---------------------------------------------------------------------------------// + public int getVolumeNo () + // ---------------------------------------------------------------------------------// + { + return volumeNo; + } + + // ---------------------------------------------------------------------------------// + @Override + public void setOriginalPath (Path path) + // ---------------------------------------------------------------------------------// + { + super.setOriginalPath (path); + + // this has already been set in the constructor + volumeNode.setUserObject (getCatalog ()); + } + + // Beagle Bros FRAMEUP disk only has one catalog block + // ARCBOOT.DSK has a catalog which starts at sector 0C + // ---------------------------------------------------------------------------------// + public static boolean isCorrectFormat (AppleDisk disk) + // ---------------------------------------------------------------------------------// + { + disk.setInterleave (0); + int catalogBlocks = checkFormat (disk); + + if (catalogBlocks > 3) + return true; + + if (disk.getSectorsPerTrack () <= 16) + { + disk.setInterleave (1); + int cb2 = checkFormat (disk); + if (cb2 > 3) + return true; + disk.setInterleave (2); + if (true) + { + int cb3 = checkFormat (disk); + if (cb3 > 3) + return true; + } + + if (catalogBlocks > 0) + { + disk.setInterleave (1); + return true; + } + + if (cb2 > 0) + return true; + } + + 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"; + case 0x42: + return "4.2"; + case 0x43: + return "4.3"; + default: + return "??"; + } + } + + // ---------------------------------------------------------------------------------// + public int getVersion () + // ---------------------------------------------------------------------------------// + { + return dosVTOCSector.dosVersion; + } + + // ---------------------------------------------------------------------------------// + private static int checkFormat (AppleDisk disk) + // ---------------------------------------------------------------------------------// + { + byte[] buffer = disk.readSector (0x11, 0x00); + + // DISCCOMMANDER.DSK uses track 0x17 for the catalog + // if (buffer[1] != 0x11) // first catalog track + // return 0; + + if (buffer[53] != 16 && buffer[53] != 13 && buffer[53] != 32) // sectors per track + { + return 0; + } + + // if (buffer[49] < -1 || buffer[49] > 1) // direction of next file save + // { + // System.out.println ("Bad direction : " + buffer[49]); + // // Visicalc data disk had 0xF8 + // // return 0; + // } + + int version = buffer[3] & 0xFF; + if (version > 0x43 && version != 0xFF) + { + System.out.printf ("Bad version : %02X%n", version); + return 0; + } + + return countCatalogBlocks (disk, buffer); + } + + // ---------------------------------------------------------------------------------// + private static int countCatalogBlocks (AppleDisk disk, byte[] buffer) + // ---------------------------------------------------------------------------------// + { + DiskAddress catalogStart = disk.getDiskAddress (buffer[1], buffer[2]); + DiskAddress da = disk.getDiskAddress (catalogStart.getBlock ()); + List catalogAddresses = new ArrayList<> (); + + do + { + if (!disk.isValidAddress (da)) + return 0; + + if (catalogAddresses.contains (da)) + { + System.out.println ("Catalog looping"); + return 0; + } + + buffer = disk.readSector (da); + if (!disk.isValidAddress (buffer[1], buffer[2])) + return 0; + + catalogAddresses.add (da); + + da = disk.getDiskAddress (buffer[1], buffer[2]); + + } while (da.getBlock () != 0); + + return catalogAddresses.size (); + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + // StringBuffer text = new StringBuffer (dosVTOCSector.toString ()); + // return text.toString (); + StringBuffer text = new StringBuffer (); + + text.append ( + String.format ("DOS version ........... %s%n", dosVTOCSector.dosVersion)); + text.append ( + String.format ("Sectors per track ..... %d%n", dosVTOCSector.maxSectors)); + text.append (String.format ("Volume no ............. %d", volumeNo)); + + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + @Override + public DataSource getFormattedSector (DiskAddress da) + // ---------------------------------------------------------------------------------// + { + SectorType type = sectorTypes[da.getBlock ()]; + if (type == vtocSector) + return dosVTOCSector; + if (da.getBlock () == 0) + return bootSector; + + byte[] buffer = disk.readSector (da); + String address = String.format ("%02X %02X", da.getTrack (), da.getSector ()); + + if (type == tsListSector) + return new DosTSListSector (getSectorFilename (da), disk, buffer, da); + if (type == catalogSector) + return new DosCatalogSector (this, disk, buffer, da); + if (type == dataSector) + return new DefaultSector ( + "Data Sector at " + address + " : " + getSectorFilename (da), disk, buffer, da); + if (type == dosSector) + return new DefaultSector ("DOS sector at " + address, disk, buffer, da); + return super.getFormattedSector (da); + } + + // ---------------------------------------------------------------------------------// + @Override + public List getFileSectors (int fileNo) + // ---------------------------------------------------------------------------------// + { + if (fileEntries.size () > 0 && fileEntries.size () > fileNo) + return fileEntries.get (fileNo).getSectors (); + return null; + } + + // ---------------------------------------------------------------------------------// + @Override + public AppleFileSource getCatalog () + // ---------------------------------------------------------------------------------// + { + String newLine = String.format ("%n"); + String line = "- --- --- ------------------------------ ----- -------------" + + " -- ---- -------------------" + newLine; + StringBuilder text = new StringBuilder (); + text.append (String.format ("Disk : %s%n%n", getDisplayPath ())); + text.append ("L Typ Len Name Addr" + + " Length TS Data Comment" + newLine); + text.append (line); + + for (AppleFileSource fileEntry : fileEntries) + text.append (((CatalogEntry) fileEntry).getDetails () + newLine); + + text.append (line); + text.append (String.format ( + " Free sectors: %3d " + "Used sectors: %3d Total sectors: %3d", + dosVTOCSector.freeSectors, dosVTOCSector.usedSectors, + (dosVTOCSector.freeSectors + dosVTOCSector.usedSectors))); + if (dosVTOCSector.freeSectors != freeSectors) + text.append (String.format ( + "%nActual: Free sectors: %3d " + + "Used sectors: %3d Total sectors: %3d", + freeSectors, usedSectors, (usedSectors + freeSectors))); + + String volumeText = volumeNo == 0 ? "" : "Side " + volumeNo + " "; + return new DefaultAppleFileSource (volumeText + "Volume " + dosVTOCSector.volume, + text.toString (), this); + } + + // ---------------------------------------------------------------------------------// + private AppleFileSource getDeletedList () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = + new StringBuilder ("List of files that were deleted from this disk\n"); + + for (AppleFileSource afs : deletedFileEntries) + text.append (((DeletedCatalogEntry) afs).getDetails () + "\n"); + + return new DefaultAppleFileSource ("Deleted files", text.toString (), this); + } + + /* From http://apple2history.org/history/ah15/ + * + 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 + 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 + 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 + patched. + */ } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/dos/DosTSListSector.java b/src/com/bytezone/diskbrowser/dos/DosTSListSector.java index 1e861ee..fb7adb4 100755 --- a/src/com/bytezone/diskbrowser/dos/DosTSListSector.java +++ b/src/com/bytezone/diskbrowser/dos/DosTSListSector.java @@ -1,82 +1,92 @@ -package com.bytezone.diskbrowser.dos; - -import com.bytezone.diskbrowser.disk.AbstractSector; -import com.bytezone.diskbrowser.disk.Disk; -import com.bytezone.diskbrowser.disk.DiskAddress; -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class DosTSListSector extends AbstractSector -{ - private final String name; - - public DosTSListSector (String name, Disk disk, byte[] buffer, DiskAddress diskAddress) - { - super (disk, buffer, diskAddress); - this.name = name; - } - - public boolean isValid (DosDisk dosDisk) - { - // what is the count of blocks? does it match? this sector can't tell, there - // might be more than one TS list - - // validate the sector, throw an exception if invalid - for (int i = 12; i < buffer.length; i += 2) - { - DiskAddress da = getValidAddress (buffer, i); - if (da == null) - { - System.out.println ("Invalid sector address : null"); - break; // throw exception? - } - - if (da.getBlock () > 0 && dosDisk.stillAvailable (da)) - { - System.out.println ("Invalid sector address : " + da); - break; // throw exception? - } - } - return true; - } - - // this is in too many places - protected DiskAddress getValidAddress (byte[] buffer, int offset) - { - if (disk.isValidAddress (buffer[offset], buffer[offset + 1])) - return disk.getDiskAddress (buffer[offset], buffer[offset + 1]); - return null; - } - - @Override - public String createText () - { - DiskAddress da = disk.getDiskAddress (buffer[1], buffer[2]); - String msg = da.matches (diskAddress) ? " (circular reference)" : ""; - - StringBuilder text = getHeader ("TS List Sector : " + name); - addText (text, buffer, 0, 1, "Not used"); - addText (text, buffer, 1, 2, "Next TS list track/sector" + msg); - addText (text, buffer, 3, 2, "Not used"); - addTextAndDecimal (text, buffer, 5, 2, "Sector base number"); - addText (text, buffer, 7, 4, "Not used"); - addText (text, buffer, 11, 1, "Not used"); - - int sectorBase = HexFormatter.intValue (buffer[5], buffer[6]); - - for (int i = 12; i <= 255; i += 2) - { - if (buffer[i] == 0 && buffer[i + 1] == 0) - msg = ""; - else - { - String msg2 = buffer[i] == 0x40 ? " - track zero" : ""; - msg = String.format ("Track/sector of file sector %04X (%<,d)%s", - ((i - 12) / 2 + sectorBase), msg2); - } - addText (text, buffer, i, 2, msg); - } - - text.deleteCharAt (text.length () - 1); - return text.toString (); - } +package com.bytezone.diskbrowser.dos; + +import com.bytezone.diskbrowser.disk.AbstractSector; +import com.bytezone.diskbrowser.disk.Disk; +import com.bytezone.diskbrowser.disk.DiskAddress; +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class DosTSListSector extends AbstractSector +// -----------------------------------------------------------------------------------// +{ + private final String name; + + // ---------------------------------------------------------------------------------// + DosTSListSector (String name, Disk disk, byte[] buffer, DiskAddress diskAddress) + // ---------------------------------------------------------------------------------// + { + super (disk, buffer, diskAddress); + this.name = name; + } + + // ---------------------------------------------------------------------------------// + public boolean isValid (DosDisk dosDisk) + // ---------------------------------------------------------------------------------// + { + // what is the count of blocks? does it match? this sector can't tell, there + // might be more than one TS list + + // validate the sector, throw an exception if invalid + for (int i = 12; i < buffer.length; i += 2) + { + DiskAddress da = getValidAddress (buffer, i); + if (da == null) + { + System.out.println ("Invalid sector address : null"); + break; // throw exception? + } + + if (da.getBlock () > 0 && dosDisk.stillAvailable (da)) + { + System.out.println ("Invalid sector address : " + da); + break; // throw exception? + } + } + return true; + } + + // this is in too many places + // ---------------------------------------------------------------------------------// + protected DiskAddress getValidAddress (byte[] buffer, int offset) + // ---------------------------------------------------------------------------------// + { + if (disk.isValidAddress (buffer[offset], buffer[offset + 1])) + return disk.getDiskAddress (buffer[offset], buffer[offset + 1]); + return null; + } + + // ---------------------------------------------------------------------------------// + @Override + public String createText () + // ---------------------------------------------------------------------------------// + { + DiskAddress da = disk.getDiskAddress (buffer[1], buffer[2]); + String msg = da.matches (diskAddress) ? " (circular reference)" : ""; + + StringBuilder text = getHeader ("TS List Sector : " + name); + addText (text, buffer, 0, 1, "Not used"); + addText (text, buffer, 1, 2, "Next TS list track/sector" + msg); + addText (text, buffer, 3, 2, "Not used"); + addTextAndDecimal (text, buffer, 5, 2, "Sector base number"); + addText (text, buffer, 7, 4, "Not used"); + addText (text, buffer, 11, 1, "Not used"); + + int sectorBase = HexFormatter.intValue (buffer[5], buffer[6]); + + for (int i = 12; i <= 255; i += 2) + { + if (buffer[i] == 0 && buffer[i + 1] == 0) + msg = ""; + else + { + String msg2 = buffer[i] == 0x40 ? " - track zero" : ""; + msg = String.format ("Track/sector of file sector %04X (%<,d)%s", + ((i - 12) / 2 + sectorBase), msg2); + } + addText (text, buffer, i, 2, msg); + } + + text.deleteCharAt (text.length () - 1); + return text.toString (); + } } \ 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 5eace16..14fe378 100755 --- a/src/com/bytezone/diskbrowser/dos/DosVTOCSector.java +++ b/src/com/bytezone/diskbrowser/dos/DosVTOCSector.java @@ -1,290 +1,307 @@ -package com.bytezone.diskbrowser.dos; - -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; // 1, 2, 3 or 0x41, 0x42, 0x43... - int maxTSPairs; - int lastAllocTrack; - int direction; - int freeSectors; - int usedSectors; - int sectorSize; - int maxSectors; - int maxTracks; - - public DosVTOCSector (DosDisk parentDisk, Disk disk, byte[] buffer, - DiskAddress diskAddress) - { - super (disk, buffer, diskAddress); - - this.parentDisk = parentDisk; - dosVersion = buffer[3]; - volume = buffer[6] & 0xFF; - maxTSPairs = buffer[39]; - lastAllocTrack = buffer[48]; - direction = buffer[49]; - maxTracks = buffer[52] & 0xFF; - maxSectors = buffer[53] & 0xFF; - sectorSize = HexFormatter.intValue (buffer[54], buffer[55]); - flagSectors2 (); - } - - @Override - public String createText () - { - return dosVersion <= 3 ? createDosText () : createDos4Text (); - } - - private String createDos4Text () - { - StringBuilder text = getHeader ("DOS 4 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"); - String diskType = - buffer[7] == (byte) 0xC4 ? " = Data" : buffer[7] == (byte) 0xC2 ? " = Boot" : ""; - addText (text, buffer, 7, 1, "Volume type: " + (char) (buffer[7] & 0x7F) + diskType); - - 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, "VTOC Phase"); - - 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); - int firstSector = 0x38; - int max = maxTracks * 4 + firstSector; - for (int i = firstSector; i < max; i += 4) - { - String extra = ""; - if (i == firstSector && bootSectorEmpty) - extra = "(unusable)"; - else if (i == 124) - extra = "(VTOC and Catalog)"; - addText (text, buffer, i, 4, String.format ("Track %02X %s %s", - (i - firstSector) / 4, getBitmap (buffer, i), extra)); - } - - text.deleteCharAt (text.length () - 1); - - return text.toString (); - } - - private String createDosText () - { - StringBuilder text = getHeader ("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, 2, "Not used"); - addTextAndDecimal (text, buffer, 6, 1, "Diskette volume"); - addText (text, buffer, 7, 4, "Not used"); - addText (text, buffer, 11, 4, "Not used"); - addText (text, buffer, 15, 4, "Not used"); - addText (text, buffer, 19, 4, "Not used"); - addText (text, buffer, 23, 4, "Not used"); - addText (text, buffer, 27, 4, "Not used"); - addText (text, buffer, 31, 4, "Not used"); - addText (text, buffer, 35, 4, "Not used"); - addTextAndDecimal (text, buffer, 39, 1, "Maximum TS pairs"); - addText (text, buffer, 40, 4, "Not used"); - addText (text, buffer, 44, 4, "Not used"); - addTextAndDecimal (text, buffer, 48, 1, "Last allocated track"); - addText (text, buffer, 49, 1, "Direction to look when allocating the next file"); - addText (text, buffer, 50, 2, "Not used"); - addTextAndDecimal (text, buffer, 52, 1, "Maximum tracks"); - addTextAndDecimal (text, buffer, 53, 1, "Maximum sectors"); - addTextAndDecimal (text, buffer, 54, 2, "Bytes per sector"); - - boolean bootSectorEmpty = parentDisk.getDisk ().isSectorEmpty (0); - int firstSector = 0x38; - int max = maxTracks * 4 + firstSector; - for (int i = firstSector; i < max; i += 4) - { - String extra = ""; - if (i == firstSector && bootSectorEmpty) - extra = "(unusable)"; - String bits = getBitmap (buffer, i); - int track = (i - firstSector) / 4; - addText (text, buffer, i, 4, - String.format ("Track %02X %s %s", track, bits, extra)); - } - - text.deleteCharAt (text.length () - 1); - - return text.toString (); - } - - // private String getBitmap (byte left, byte right) - // { - // StringBuilder text = new StringBuilder (); - // - // int base = maxSectors == 13 ? 3 : 0; - // right >>= base; - // - // for (int i = base; i < 8; i++) - // { - // if ((right & 0x01) == 1) - // text.append ("."); - // else - // text.append ("X"); - // right >>= 1; - // } - // - // for (int i = 0; i < 8; i++) - // { - // if ((left & 0x01) == 1) - // text.append ("."); - // else - // text.append ("X"); - // left >>= 1; - // } - // - // return text.toString (); - // } - - private String getBitmap (byte[] buffer, int offset) - { - StringBuilder text = new StringBuilder (); - int value = HexFormatter.getLongBigEndian (buffer, offset); - - String bits = "0000000000000000000000000000000" + Integer.toBinaryString (value); - bits = bits.substring (bits.length () - 32); - bits = bits.substring (0, maxSectors); - bits = bits.replace ('0', 'X'); - bits = bits.replace ('1', '.'); - text.append (bits); - - return text.reverse ().toString (); - } - - private void flagSectors2 () - { - int firstSector = 0x38; - int max = maxTracks * 4 + firstSector; - for (int i = firstSector; i < max; i += 4) - { - int track = (i - firstSector) / 4; - String bits = getBitmap (buffer, i); - - // System.out.printf ("%08X %s%n", track, bits); - int blockNo = track * maxSectors; - char[] chars = bits.toCharArray (); - for (int sector = 0; sector < maxSectors; sector++) - { - // System.out.printf ("%3d %s%n", blockNo, chars[sector]); - if (chars[sector] == '.') - { - parentDisk.setSectorFree (blockNo, true); - ++freeSectors; - } - else - { - parentDisk.setSectorFree (blockNo, false); - ++usedSectors; - } - ++blockNo; - } - } - } - - // private void flagSectors () - // { - // int block = 0; - // int base = maxSectors == 13 ? 3 : 0; - // int firstSector = 0x38; - // int max = maxTracks * 4 + firstSector; - // for (int i = firstSector; i < max; i += 4) - // { - // block = check (buffer[i + 1], block, base); - // block = check (buffer[i], block, 0); - // } - // } - - // private int check (byte b, int block, int base) - // { - // b >>= base; - // for (int i = base; i < 8; i++) - // { - // if ((b & 0x01) == 1) - // { - // parentDisk.setSectorFree (block, true); - // ++freeSectors; - // } - // else - // { - // parentDisk.setSectorFree (block, false); - // ++usedSectors; - // } - // block++; - // b >>= 1; - // } - // 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 ("\nVolume : " + volume); - text.append ("\nMax TS pairs : " + maxTSPairs); - text.append ("\nLast allocated T : " + lastAllocTrack); - text.append ("\nDirection : " + direction); - - return text.toString (); - } +package com.bytezone.diskbrowser.dos; + +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; // 1, 2, 3 or 0x41, 0x42, 0x43... + int maxTSPairs; + int lastAllocTrack; + int direction; + int freeSectors; + int usedSectors; + int sectorSize; + int maxSectors; + int maxTracks; + + // ---------------------------------------------------------------------------------// + DosVTOCSector (DosDisk parentDisk, Disk disk, byte[] buffer, DiskAddress diskAddress) + // ---------------------------------------------------------------------------------// + { + super (disk, buffer, diskAddress); + + this.parentDisk = parentDisk; + dosVersion = buffer[3]; + volume = buffer[6] & 0xFF; + maxTSPairs = buffer[39]; + lastAllocTrack = buffer[48]; + direction = buffer[49]; + maxTracks = buffer[52] & 0xFF; + maxSectors = buffer[53] & 0xFF; + sectorSize = HexFormatter.intValue (buffer[54], buffer[55]); + flagSectors2 (); + } + + // ---------------------------------------------------------------------------------// + @Override + public String createText () + // ---------------------------------------------------------------------------------// + { + return dosVersion <= 3 ? createDosText () : createDos4Text (); + } + + // ---------------------------------------------------------------------------------// + private String createDos4Text () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = getHeader ("DOS 4 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"); + String diskType = + buffer[7] == (byte) 0xC4 ? " = Data" : buffer[7] == (byte) 0xC2 ? " = Boot" : ""; + addText (text, buffer, 7, 1, "Volume type: " + (char) (buffer[7] & 0x7F) + diskType); + + 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, "VTOC Phase"); + + 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); + int firstSector = 0x38; + int max = maxTracks * 4 + firstSector; + for (int i = firstSector; i < max; i += 4) + { + String extra = ""; + if (i == firstSector && bootSectorEmpty) + extra = "(unusable)"; + else if (i == 124) + extra = "(VTOC and Catalog)"; + addText (text, buffer, i, 4, String.format ("Track %02X %s %s", + (i - firstSector) / 4, getBitmap (buffer, i), extra)); + } + + text.deleteCharAt (text.length () - 1); + + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + private String createDosText () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = getHeader ("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, 2, "Not used"); + addTextAndDecimal (text, buffer, 6, 1, "Diskette volume"); + addText (text, buffer, 7, 4, "Not used"); + addText (text, buffer, 11, 4, "Not used"); + addText (text, buffer, 15, 4, "Not used"); + addText (text, buffer, 19, 4, "Not used"); + addText (text, buffer, 23, 4, "Not used"); + addText (text, buffer, 27, 4, "Not used"); + addText (text, buffer, 31, 4, "Not used"); + addText (text, buffer, 35, 4, "Not used"); + addTextAndDecimal (text, buffer, 39, 1, "Maximum TS pairs"); + addText (text, buffer, 40, 4, "Not used"); + addText (text, buffer, 44, 4, "Not used"); + addTextAndDecimal (text, buffer, 48, 1, "Last allocated track"); + addText (text, buffer, 49, 1, "Direction to look when allocating the next file"); + addText (text, buffer, 50, 2, "Not used"); + addTextAndDecimal (text, buffer, 52, 1, "Maximum tracks"); + addTextAndDecimal (text, buffer, 53, 1, "Maximum sectors"); + addTextAndDecimal (text, buffer, 54, 2, "Bytes per sector"); + + boolean bootSectorEmpty = parentDisk.getDisk ().isSectorEmpty (0); + int firstSector = 0x38; + int max = maxTracks * 4 + firstSector; + for (int i = firstSector; i < max; i += 4) + { + String extra = ""; + if (i == firstSector && bootSectorEmpty) + extra = "(unusable)"; + String bits = getBitmap (buffer, i); + int track = (i - firstSector) / 4; + addText (text, buffer, i, 4, + String.format ("Track %02X %s %s", track, bits, extra)); + } + + text.deleteCharAt (text.length () - 1); + + return text.toString (); + } + + // private String getBitmap (byte left, byte right) + // { + // StringBuilder text = new StringBuilder (); + // + // int base = maxSectors == 13 ? 3 : 0; + // right >>= base; + // + // for (int i = base; i < 8; i++) + // { + // if ((right & 0x01) == 1) + // text.append ("."); + // else + // text.append ("X"); + // right >>= 1; + // } + // + // for (int i = 0; i < 8; i++) + // { + // if ((left & 0x01) == 1) + // text.append ("."); + // else + // text.append ("X"); + // left >>= 1; + // } + // + // return text.toString (); + // } + + // ---------------------------------------------------------------------------------// + private String getBitmap (byte[] buffer, int offset) + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + int value = HexFormatter.getLongBigEndian (buffer, offset); + + String bits = "0000000000000000000000000000000" + Integer.toBinaryString (value); + bits = bits.substring (bits.length () - 32); + bits = bits.substring (0, maxSectors); + bits = bits.replace ('0', 'X'); + bits = bits.replace ('1', '.'); + text.append (bits); + + return text.reverse ().toString (); + } + + // ---------------------------------------------------------------------------------// + private void flagSectors2 () + // ---------------------------------------------------------------------------------// + { + int firstSector = 0x38; + int max = maxTracks * 4 + firstSector; + for (int i = firstSector; i < max; i += 4) + { + int track = (i - firstSector) / 4; + String bits = getBitmap (buffer, i); + + // System.out.printf ("%08X %s%n", track, bits); + int blockNo = track * maxSectors; + char[] chars = bits.toCharArray (); + for (int sector = 0; sector < maxSectors; sector++) + { + // System.out.printf ("%3d %s%n", blockNo, chars[sector]); + if (chars[sector] == '.') + { + parentDisk.setSectorFree (blockNo, true); + ++freeSectors; + } + else + { + parentDisk.setSectorFree (blockNo, false); + ++usedSectors; + } + ++blockNo; + } + } + } + + // private void flagSectors () + // { + // int block = 0; + // int base = maxSectors == 13 ? 3 : 0; + // int firstSector = 0x38; + // int max = maxTracks * 4 + firstSector; + // for (int i = firstSector; i < max; i += 4) + // { + // block = check (buffer[i + 1], block, base); + // block = check (buffer[i], block, 0); + // } + // } + + // private int check (byte b, int block, int base) + // { + // b >>= base; + // for (int i = base; i < 8; i++) + // { + // if ((b & 0x01) == 1) + // { + // parentDisk.setSectorFree (block, true); + // ++freeSectors; + // } + // else + // { + // parentDisk.setSectorFree (block, false); + // ++usedSectors; + // } + // block++; + // b >>= 1; + // } + // 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 ("\nVolume : " + volume); + text.append ("\nMax TS pairs : " + maxTSPairs); + text.append ("\nLast allocated T : " + lastAllocTrack); + text.append ("\nDirection : " + direction); + + return text.toString (); + } } \ No newline at end of file