diff --git a/src/com/bytezone/diskbrowser/applefile/AbstractFile.java b/src/com/bytezone/diskbrowser/applefile/AbstractFile.java index 93ec273..0c3c869 100755 --- a/src/com/bytezone/diskbrowser/applefile/AbstractFile.java +++ b/src/com/bytezone/diskbrowser/applefile/AbstractFile.java @@ -106,7 +106,6 @@ public abstract class AbstractFile implements DataSource public JComponent getComponent () // ---------------------------------------------------------------------------------// { - JPanel panel = new JPanel (); - return panel; + return new JPanel (); } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/prodos/ProdosDirectory.java b/src/com/bytezone/diskbrowser/applefile/ProdosDirectory.java similarity index 67% rename from src/com/bytezone/diskbrowser/prodos/ProdosDirectory.java rename to src/com/bytezone/diskbrowser/applefile/ProdosDirectory.java index cc5faf4..9b07202 100755 --- a/src/com/bytezone/diskbrowser/prodos/ProdosDirectory.java +++ b/src/com/bytezone/diskbrowser/applefile/ProdosDirectory.java @@ -1,19 +1,25 @@ -package com.bytezone.diskbrowser.prodos; +package com.bytezone.diskbrowser.applefile; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; -import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.disk.FormattedDisk; +import com.bytezone.diskbrowser.prodos.DirectoryHeader; +import com.bytezone.diskbrowser.prodos.ProdosConstants; +import com.bytezone.diskbrowser.prodos.ProdosDisk; import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.Utility; // -----------------------------------------------------------------------------------// -class ProdosDirectory extends AbstractFile implements ProdosConstants +public class ProdosDirectory extends AbstractFile implements ProdosConstants // -----------------------------------------------------------------------------------// { + static final DateTimeFormatter df = DateTimeFormatter.ofPattern ("d-LLL-yy"); + static final DateTimeFormatter tf = DateTimeFormatter.ofPattern ("H:mm"); + static final String UNDERLINE = "--------------------------------------------------\n"; + private static final String NO_DATE = ""; - private static final String newLine = String.format ("%n"); - private static final String newLine2 = newLine + newLine; private final ProdosDisk parentFD; private final int totalBlocks; @@ -21,8 +27,8 @@ class ProdosDirectory extends AbstractFile implements ProdosConstants private final int usedBlocks; // ---------------------------------------------------------------------------------// - ProdosDirectory (FormattedDisk parent, String name, byte[] buffer, int totalBlocks, - int freeBlocks, int usedBlocks) + public ProdosDirectory (FormattedDisk parent, String name, byte[] buffer, + int totalBlocks, int freeBlocks, int usedBlocks) // ---------------------------------------------------------------------------------// { super (name, buffer); @@ -38,8 +44,38 @@ class ProdosDirectory extends AbstractFile implements ProdosConstants public String getText () // ---------------------------------------------------------------------------------// { - StringBuffer text = new StringBuffer (); - text.append ("File : " + parentFD.getDisplayPath () + newLine2); + if (showDebugText) + return getDebugText (); + else + return getDirectoryText (); + } + + // ---------------------------------------------------------------------------------// + private String getDebugText () + // ---------------------------------------------------------------------------------// + { + List directoryHeaders = parentFD.getDirectoryHeaders (); + StringBuilder text = new StringBuilder (); + + for (DirectoryHeader directoryHeader : directoryHeaders) + { + text.append (UNDERLINE); + text.append (directoryHeader.getText ()); + text.append ("\n"); + text.append (UNDERLINE); + directoryHeader.listFileEntries (text); + } + + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + private String getDirectoryText () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + text.append ("File : " + parentFD.getDisplayPath () + "\n\n"); for (int i = 0; i < buffer.length; i += ENTRY_SIZE) { int storageType = (buffer[i] & 0xF0) >> 4; @@ -56,9 +92,9 @@ class ProdosDirectory extends AbstractFile implements ProdosConstants case VOLUME_HEADER: case SUBDIRECTORY_HEADER: String root = storageType == VOLUME_HEADER ? "/" : ""; - text.append (root + filename + newLine2); + text.append (root + filename + "\n\n"); text.append (" NAME TYPE BLOCKS " - + "MODIFIED CREATED ENDFILE SUBTYPE" + newLine2); + + "MODIFIED CREATED ENDFILE SUBTYPE" + "\n\n"); break; case FREE: @@ -74,13 +110,13 @@ class ProdosDirectory extends AbstractFile implements ProdosConstants LocalDateTime createdDate = Utility.getAppleDate (buffer, i + 24); LocalDateTime modifiedDate = Utility.getAppleDate (buffer, i + 33); - String dateC = createdDate == null ? NO_DATE - : createdDate.format (ProdosDisk.df).toUpperCase (); - String dateM = modifiedDate == null ? NO_DATE - : modifiedDate.format (ProdosDisk.df).toUpperCase (); + String dateC = + createdDate == null ? NO_DATE : createdDate.format (df).toUpperCase (); + String dateM = + modifiedDate == null ? NO_DATE : modifiedDate.format (df).toUpperCase (); - String timeC = createdDate == null ? "" : createdDate.format (ProdosDisk.tf); - String timeM = modifiedDate == null ? "" : modifiedDate.format (ProdosDisk.tf); + String timeC = createdDate == null ? "" : createdDate.format (tf); + String timeM = modifiedDate == null ? "" : modifiedDate.format (tf); int eof = Utility.intValue (buffer[i + 21], buffer[i + 22], buffer[i + 23]); int fileType = buffer[i + 16] & 0xFF; @@ -102,7 +138,7 @@ class ProdosDirectory extends AbstractFile implements ProdosConstants break; case FILE_TYPE_AWP: - aux = Utility.intValue (buffer[i + 32], buffer[i + 31]); // backwards! + aux = Utility.intValue (buffer[i + 32], buffer[i + 31]); // backwards! if (aux != 0) filename = convert (filename, aux); break; @@ -117,12 +153,14 @@ class ProdosDirectory extends AbstractFile implements ProdosConstants break; default: - text.append (" 0 && recType <= 0xDF) { - System.out.printf ("Const: %02X%n", recType); - System.out.println (HexFormatter.format (buffer, ptr, recType + 1, ptr)); + if (debug) + { + System.out.printf ("Const: %02X%n", recType); + System.out.println (HexFormatter.format (buffer, ptr, recType + 1, ptr)); + } ptr += recType + 1; continue; } - System.out.printf ("%02X ", recType); + if (debug) + System.out.printf ("%02X ", recType); + switch (recType) { case 0x00: // END - System.out.println ("END"); + if (debug) + System.out.println ("END"); break; case 0xE0: // ALIGN - System.out.printf ("ALIGN:%n"); + if (debug) + System.out.printf ("ALIGN:%n"); break; case 0xE1: // ORG - System.out.printf ("ORG:%n"); + if (debug) + System.out.printf ("ORG:%n"); break; case 0xE2: // RELOC @@ -115,8 +126,9 @@ public class SegmentHeader int bitShift = buffer[ptr + 2] & 0xFF; int segmentOffset = Utility.getLong (buffer, ptr + 3); int value = Utility.getLong (buffer, ptr + 7); - System.out.printf ("RELOC: %02X %02X %08X %08X%n", bytesRelocated, bitShift, - segmentOffset, value); + if (debug) + System.out.printf ("RELOC: %02X %02X %08X %08X%n", bytesRelocated, bitShift, + segmentOffset, value); ptr += 11; continue; @@ -127,72 +139,88 @@ public class SegmentHeader int fileNo = Utility.getWord (buffer, ptr + 7); int segNo = Utility.getWord (buffer, ptr + 9); int subroutineOffset = Utility.getLong (buffer, ptr + 11); - System.out.printf ("INTERSEG: %02X %02X %08X %04X %04X %08X%n", count1, count2, - operandOffset, fileNo, segNo, subroutineOffset); + if (debug) + System.out.printf ("INTERSEG: %02X %02X %08X %04X %04X %08X%n", count1, + count2, operandOffset, fileNo, segNo, subroutineOffset); ptr += 15; break; case 0xE4: // USING - System.out.printf ("USING:%n"); + if (debug) + System.out.printf ("USING:%n"); break; case 0xE5: // STRONG - System.out.printf ("STRONG:%n"); + if (debug) + System.out.printf ("STRONG:%n"); break; case 0xE6: // GLOBAL - System.out.printf ("GLOBAL:%n"); + if (debug) + System.out.printf ("GLOBAL:%n"); break; case 0xE7: // GEQU - System.out.printf ("GEQU:%n"); + if (debug) + System.out.printf ("GEQU:%n"); break; case 0xE8: // MEM - System.out.printf ("MEM:%n"); + if (debug) + System.out.printf ("MEM:%n"); break; case 0xEB: // EXPR - System.out.printf ("EXPR:%n"); + if (debug) + System.out.printf ("EXPR:%n"); break; case 0xEC: // ZEXPR - System.out.printf ("ZEXPR:%n"); + if (debug) + System.out.printf ("ZEXPR:%n"); break; case 0xED: // BEXPR - System.out.printf ("BEXPR:%n"); + if (debug) + System.out.printf ("BEXPR:%n"); break; case 0xEE: // RELEXPR - System.out.printf ("RELEXPR:%n"); + if (debug) + System.out.printf ("RELEXPR:%n"); break; case 0xEF: // LOCAL - System.out.printf ("LOCAL:%n"); + if (debug) + System.out.printf ("LOCAL:%n"); break; case 0xF0: // EQU String label = HexFormatter.getPascalString (buffer, ptr + 1); - System.out.printf ("EQU: %s%n", label); + if (debug) + System.out.printf ("EQU: %s%n", label); break; case 0xF1: // DS - System.out.printf ("DS:%n"); + if (debug) + System.out.printf ("DS:%n"); break; case 0xF2: // LCONST int constLength = Utility.getLong (buffer, ptr + 1); - System.out.printf ("Const: %04X%n", constLength); + if (debug) + System.out.printf ("Const: %04X%n", constLength); ptr += constLength + 5; continue; case 0xF3: // LEXPR - System.out.printf ("LEXPR:%n"); + if (debug) + System.out.printf ("LEXPR:%n"); break; case 0xF4: // ENTRY - System.out.printf ("ENTRY:%n"); + if (debug) + System.out.printf ("ENTRY:%n"); break; case 0xF5: // cRELOC @@ -200,8 +228,9 @@ public class SegmentHeader int cBitShift = buffer[ptr + 2] & 0xFF; int cSegmentOffset = Utility.getWord (buffer, ptr + 3); int cValue = Utility.getWord (buffer, ptr + 5); - System.out.printf ("cRELOC: %02X %02X %08X %08X%n", cBytesRelocated, cBitShift, - cSegmentOffset, cValue); + if (debug) + System.out.printf ("cRELOC: %02X %02X %08X %08X%n", cBytesRelocated, + cBitShift, cSegmentOffset, cValue); ptr += 7; continue; @@ -211,15 +240,17 @@ public class SegmentHeader int cOperandOffset = Utility.getWord (buffer, ptr + 3); int cSegNo = buffer[ptr + 5] & 0xFF; int cSubroutineOffset = Utility.getWord (buffer, ptr + 6); - System.out.printf ("cINTERSEG: %02X %02X %04X %02X %04X%n", cCount1, cCount2, - cOperandOffset, cSegNo, cSubroutineOffset); + if (debug) + System.out.printf ("cINTERSEG: %02X %02X %04X %02X %04X%n", cCount1, cCount2, + cOperandOffset, cSegNo, cSubroutineOffset); ptr += 8; continue; case 0xF7: // SUPER int superLength = Utility.getLong (buffer, ptr + 1); int recordType = buffer[ptr + 5] & 0xFF; - System.out.printf ("Super type %02X%n", recordType); + if (debug) + System.out.printf ("Super type %02X%n", recordType); ptr += superLength + 5; continue; @@ -228,7 +259,8 @@ public class SegmentHeader break; } - System.out.println (); + if (debug) + System.out.println (); break; } } @@ -258,33 +290,18 @@ public class SegmentHeader kindPrivate = (segAttr & 0x40) != 0; kindStatic = (segAttr & 0x80) == 0; - switch (segType) + kindWhereText = switch (segType) { - case 0: - kindWhereText = "Code Segment"; - break; - case 1: - kindWhereText = "Data Segment"; - break; - case 2: - kindWhereText = "Jump Table Segment"; - break; - case 4: - kindWhereText = "Pathname Segment"; - break; - case 8: - kindWhereText = "Library Dictionary Segment"; - break; - case 0x10: - kindWhereText = "Initialization Segment"; - break; - case 0x11: - kindWhereText = "Absolute Bank Segment"; - break; - case 0x12: - kindWhereText = "Direct Page / Stack Segment"; - break; - } + case 0x00 -> "Code Segment"; + case 0x01 -> "Data Segment"; + case 0x02 -> "Jump Table Segment"; + case 0x04 -> "Pathname Segment"; + case 0x08 -> "Library Dictionary Segment"; + case 0x10 -> "Initialization Segment"; + case 0x11 -> "Absolute Bank Segment"; + case 0x12 -> "Direct Page / Stack Segment"; + default -> "Unknown"; + }; } // ---------------------------------------------------------------------------------// diff --git a/src/com/bytezone/diskbrowser/disk/DiskFactory.java b/src/com/bytezone/diskbrowser/disk/DiskFactory.java index 618fc89..92ba1ce 100755 --- a/src/com/bytezone/diskbrowser/disk/DiskFactory.java +++ b/src/com/bytezone/diskbrowser/disk/DiskFactory.java @@ -169,15 +169,11 @@ public class DiskFactory suffix = "dsk"; compressed = true; } - catch (IOException e) + catch (Exception e) { e.printStackTrace (); return null; } - catch (FileFormatException e) - { - return null; - } } FormattedDisk disk = null; diff --git a/src/com/bytezone/diskbrowser/gui/TextPreferences.java b/src/com/bytezone/diskbrowser/gui/TextPreferences.java index 021c134..89fe7c5 100644 --- a/src/com/bytezone/diskbrowser/gui/TextPreferences.java +++ b/src/com/bytezone/diskbrowser/gui/TextPreferences.java @@ -6,6 +6,7 @@ public class TextPreferences { public boolean showTextOffsets; public boolean showHeader = true; + public boolean merlinFormat = true; // ---------------------------------------------------------------------------------// @Override @@ -15,7 +16,8 @@ public class TextPreferences StringBuilder text = new StringBuilder (); text.append (String.format ("Show offsets .......... %s%n", showTextOffsets)); - text.append (String.format ("Show header ........... %s", showHeader)); + text.append (String.format ("Show header ........... %s%n", showHeader)); + text.append (String.format ("Show .S as Merlin ..... %s", merlinFormat)); return text.toString (); } diff --git a/src/com/bytezone/diskbrowser/prodos/CatalogEntry.java b/src/com/bytezone/diskbrowser/prodos/CatalogEntry.java index 2c479ae..8ac21ab 100755 --- a/src/com/bytezone/diskbrowser/prodos/CatalogEntry.java +++ b/src/com/bytezone/diskbrowser/prodos/CatalogEntry.java @@ -18,6 +18,9 @@ abstract class CatalogEntry implements AppleFileSource Disk disk; ProdosDisk parentDisk; + int blockNo; + int entryNo; + String name; int storageType; @@ -30,11 +33,13 @@ abstract class CatalogEntry implements AppleFileSource DirectoryHeader parentDirectory; // ---------------------------------------------------------------------------------// - CatalogEntry (ProdosDisk parentDisk, byte[] entryBuffer) + CatalogEntry (ProdosDisk parentDisk, byte[] entryBuffer, int blockNo, int entryNo) // ---------------------------------------------------------------------------------// { this.parentDisk = parentDisk; this.disk = parentDisk.getDisk (); + this.blockNo = blockNo; + this.entryNo = entryNo; name = HexFormatter.getString (entryBuffer, 1, entryBuffer[0] & 0x0F); storageType = (entryBuffer[0] & 0xF0) >> 4; @@ -45,6 +50,20 @@ abstract class CatalogEntry implements AppleFileSource access = entryBuffer[30] & 0xFF; } + // ---------------------------------------------------------------------------------// + public String getName () + // ---------------------------------------------------------------------------------// + { + return name; + } + + // ---------------------------------------------------------------------------------// + public String getText () + // ---------------------------------------------------------------------------------// + { + return String.format ("%04X:%02X %-15s %02X", blockNo, entryNo, name, storageType); + } + // ---------------------------------------------------------------------------------// @Override public String getUniqueName () diff --git a/src/com/bytezone/diskbrowser/prodos/DirectoryHeader.java b/src/com/bytezone/diskbrowser/prodos/DirectoryHeader.java index 03c8f1f..a20a872 100755 --- a/src/com/bytezone/diskbrowser/prodos/DirectoryHeader.java +++ b/src/com/bytezone/diskbrowser/prodos/DirectoryHeader.java @@ -3,7 +3,7 @@ package com.bytezone.diskbrowser.prodos; import com.bytezone.diskbrowser.utilities.Utility; // -----------------------------------------------------------------------------------// -abstract class DirectoryHeader extends CatalogEntry +public abstract class DirectoryHeader extends CatalogEntry // -----------------------------------------------------------------------------------// { final int entryLength; @@ -11,13 +11,55 @@ abstract class DirectoryHeader extends CatalogEntry final int fileCount; // ---------------------------------------------------------------------------------// - DirectoryHeader (ProdosDisk parentDisk, byte[] entryBuffer) + DirectoryHeader (ProdosDisk parentDisk, byte[] entryBuffer, int blockNo, int entryNo) // ---------------------------------------------------------------------------------// { - super (parentDisk, entryBuffer); + super (parentDisk, entryBuffer, blockNo, entryNo); entryLength = entryBuffer[31] & 0xFF; entriesPerBlock = entryBuffer[32] & 0xFF; fileCount = Utility.intValue (entryBuffer[33], entryBuffer[34]); } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + return String.format ("%s %04X", super.getText (), fileCount); + } + + // ---------------------------------------------------------------------------------// + public void listFileEntries (StringBuilder text) + // ---------------------------------------------------------------------------------// + { + int blockNo = this.blockNo; + + do + { + byte[] buffer = disk.readBlock (blockNo); + int ptr = 4; + int entryNo = 1; + for (int i = 0; i < 13; i++) + { + int nameLength = buffer[ptr] & 0x0F; + int storageType = (buffer[ptr] & 0xF0) >>> 4; + if (nameLength > 0 && storageType < 0x0E) + { + String name = new String (buffer, ptr + 1, nameLength); + int blocksUsed = Utility.intValue (buffer[ptr + 0x13], buffer[ptr + 0x14]); + int fileType = buffer[ptr + 0x10] & 0xFF; + int keyPointer = Utility.intValue (buffer[ptr + 0x11], buffer[ptr + 0x12]); + int headerPointer = Utility.intValue (buffer[ptr + 0x25], buffer[ptr + 0x26]); + text.append (String.format ("%04X:%02X %-15s %02X %04X %02X %04X %04X%n", + blockNo, entryNo, name, storageType, blocksUsed, fileType, keyPointer, + headerPointer)); + } + ptr += 0x27; + ++entryNo; + } + + blockNo = Utility.intValue (buffer[2], buffer[3]); + } while (blockNo != 0); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/prodos/FileEntry.java b/src/com/bytezone/diskbrowser/prodos/FileEntry.java index b55bd64..28bf058 100755 --- a/src/com/bytezone/diskbrowser/prodos/FileEntry.java +++ b/src/com/bytezone/diskbrowser/prodos/FileEntry.java @@ -28,6 +28,7 @@ import com.bytezone.diskbrowser.applefile.MerlinSource; import com.bytezone.diskbrowser.applefile.ObjectModule; import com.bytezone.diskbrowser.applefile.OriginalHiResImage; import com.bytezone.diskbrowser.applefile.PascalArea; +import com.bytezone.diskbrowser.applefile.ProdosDirectory; import com.bytezone.diskbrowser.applefile.QuickDrawFont; import com.bytezone.diskbrowser.applefile.SHRPictureFile1; import com.bytezone.diskbrowser.applefile.SHRPictureFile2; @@ -69,10 +70,10 @@ class FileEntry extends CatalogEntry implements ProdosConstants // ---------------------------------------------------------------------------------// FileEntry (ProdosDisk fDisk, byte[] entryBuffer, DirectoryHeader parent, - int parentBlock) + int parentBlock, int entryNo) // ---------------------------------------------------------------------------------// { - super (fDisk, entryBuffer); + super (fDisk, entryBuffer, parentBlock, entryNo); assert parent != null; this.parentDirectory = parent; @@ -547,6 +548,7 @@ class FileEntry extends CatalogEntry implements ProdosConstants file = new ErrorMessageFile (name, buffer, e); e.printStackTrace (); } + return file; } diff --git a/src/com/bytezone/diskbrowser/prodos/ProdosDisk.java b/src/com/bytezone/diskbrowser/prodos/ProdosDisk.java index 546e5c9..8246825 100755 --- a/src/com/bytezone/diskbrowser/prodos/ProdosDisk.java +++ b/src/com/bytezone/diskbrowser/prodos/ProdosDisk.java @@ -1,5 +1,7 @@ package com.bytezone.diskbrowser.prodos; +import static com.bytezone.diskbrowser.prodos.ProdosConstants.ENTRY_SIZE; + import java.awt.Color; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -29,7 +31,6 @@ public class ProdosDisk extends AbstractFormattedDisk { static ProdosPreferences prodosPreferences; // set by MenuHandler - // final DateFormat df = DateFormat.getInstance (); static final DateTimeFormatter df = DateTimeFormatter.ofPattern ("d-LLL-yy"); static final DateTimeFormatter tf = DateTimeFormatter.ofPattern ("H:mm"); @@ -119,7 +120,7 @@ public class ProdosDisk extends AbstractFormattedDisk sectorTypes[block] = currentSectorType; int max = disk.getBlockSize () - ProdosConstants.ENTRY_SIZE; - for (int ptr = 4; ptr < max; ptr += ProdosConstants.ENTRY_SIZE) + for (int ptr = 4, entryNo = 0; ptr < max; ptr += ENTRY_SIZE, entryNo++) { int storageType = (sectorBuffer[ptr] & 0xF0) >> 4; if (storageType == 0) // deleted or unused @@ -145,7 +146,7 @@ public class ProdosDisk extends AbstractFormattedDisk break; case ProdosConstants.SUBDIRECTORY_HEADER: - localHeader = new SubDirectoryHeader (this, entry, parent); + localHeader = new SubDirectoryHeader (this, entry, parent, block); headerEntries.add (localHeader); currentSectorType = subcatalogSector; if (!disk.isBlockEmpty (block)) @@ -153,7 +154,8 @@ public class ProdosDisk extends AbstractFormattedDisk break; case ProdosConstants.SUBDIRECTORY: - FileEntry fileEntry = new FileEntry (this, entry, localHeader, block); + FileEntry fileEntry = + new FileEntry (this, entry, localHeader, block, entryNo); fileEntries.add (fileEntry); DefaultMutableTreeNode directoryNode = new DefaultMutableTreeNode (fileEntry); directoryNode.setAllowsChildren (true); @@ -166,7 +168,7 @@ public class ProdosDisk extends AbstractFormattedDisk case ProdosConstants.TREE: case ProdosConstants.PASCAL_ON_PROFILE: case ProdosConstants.GSOS_EXTENDED_FILE: - fileEntry = new FileEntry (this, entry, localHeader, block); + fileEntry = new FileEntry (this, entry, localHeader, block, entryNo); fileEntries.add (fileEntry); DefaultMutableTreeNode node = new DefaultMutableTreeNode (fileEntry); node.setAllowsChildren (false); @@ -200,13 +202,6 @@ public class ProdosDisk extends AbstractFormattedDisk } } - // ---------------------------------------------------------------------------------// - // public boolean isReservedAddress (int blockNo) - // // ---------------------------------------------------------------------------------// - // { - // return false; - // } - // ---------------------------------------------------------------------------------// public static boolean isCorrectFormat (AppleDisk disk) // ---------------------------------------------------------------------------------// @@ -242,6 +237,13 @@ public class ProdosDisk extends AbstractFormattedDisk return true; } + // ---------------------------------------------------------------------------------// + public List getDirectoryHeaders () + // ---------------------------------------------------------------------------------// + { + return headerEntries; + } + // ---------------------------------------------------------------------------------// VolumeDirectoryHeader getVolumeDirectoryHeader () // ---------------------------------------------------------------------------------// @@ -255,6 +257,7 @@ public class ProdosDisk extends AbstractFormattedDisk { if (fileNo == 0) return volumeDirectoryHeader.getDataSource (); + return fileEntries.get (fileNo - 1).getDataSource (); } diff --git a/src/com/bytezone/diskbrowser/prodos/SubDirectoryHeader.java b/src/com/bytezone/diskbrowser/prodos/SubDirectoryHeader.java index 6f6df06..fdbc300 100755 --- a/src/com/bytezone/diskbrowser/prodos/SubDirectoryHeader.java +++ b/src/com/bytezone/diskbrowser/prodos/SubDirectoryHeader.java @@ -4,22 +4,27 @@ import java.util.List; import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.gui.DataSource; -import com.bytezone.diskbrowser.utilities.Utility; +import com.bytezone.diskbrowser.utilities.Utility;; // -----------------------------------------------------------------------------------// -class SubDirectoryHeader extends DirectoryHeader +public class SubDirectoryHeader extends DirectoryHeader // -----------------------------------------------------------------------------------// { private final int parentPointer; private final int parentSequence; private final int parentSize; + private final int blockNo; + // ---------------------------------------------------------------------------------// - SubDirectoryHeader (ProdosDisk parentDisk, byte[] entryBuffer, FileEntry parent) + SubDirectoryHeader (ProdosDisk parentDisk, byte[] entryBuffer, FileEntry parent, + int blockNo) // ---------------------------------------------------------------------------------// { - super (parentDisk, entryBuffer); + super (parentDisk, entryBuffer, blockNo, 1); + this.parentDirectory = parent.parentDirectory; + this.blockNo = blockNo; parentPointer = Utility.intValue (entryBuffer[35], entryBuffer[36]); parentSequence = entryBuffer[37] & 0xFF; @@ -46,6 +51,22 @@ class SubDirectoryHeader extends DirectoryHeader return null; } + // ---------------------------------------------------------------------------------// + public int getBlockNo () + // ---------------------------------------------------------------------------------// + { + return blockNo; + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + return String.format ("%s %04X:%02X", super.getText (), parentPointer, + parentSequence); + } + // ---------------------------------------------------------------------------------// @Override public String toString () diff --git a/src/com/bytezone/diskbrowser/prodos/VolumeDirectoryHeader.java b/src/com/bytezone/diskbrowser/prodos/VolumeDirectoryHeader.java index 8615f01..d12e365 100755 --- a/src/com/bytezone/diskbrowser/prodos/VolumeDirectoryHeader.java +++ b/src/com/bytezone/diskbrowser/prodos/VolumeDirectoryHeader.java @@ -1,14 +1,17 @@ package com.bytezone.diskbrowser.prodos; +import static com.bytezone.diskbrowser.prodos.ProdosConstants.BLOCK_SIZE; + import java.util.ArrayList; import java.util.List; +import com.bytezone.diskbrowser.applefile.ProdosDirectory; import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.gui.DataSource; import com.bytezone.diskbrowser.utilities.Utility; // -----------------------------------------------------------------------------------// -class VolumeDirectoryHeader extends DirectoryHeader +public class VolumeDirectoryHeader extends DirectoryHeader // -----------------------------------------------------------------------------------// { protected final int bitMapBlock; @@ -21,15 +24,12 @@ class VolumeDirectoryHeader extends DirectoryHeader VolumeDirectoryHeader (ProdosDisk parentDisk, byte[] entryBuffer) // ---------------------------------------------------------------------------------// { - super (parentDisk, entryBuffer); + super (parentDisk, entryBuffer, 2, 1); bitMapBlock = Utility.unsignedShort (entryBuffer, 35); totalBlocks = Utility.unsignedShort (entryBuffer, 37); - // if (totalBlocks == 0xFFFF || totalBlocks == 0x7FFF) - // totalBlocks = (int) disk.getFile ().length () / 4096 * 8;// ignore extra bytes - - totalBitMapBlocks = (totalBlocks - 1) / 512 + 1; + totalBitMapBlocks = (totalBlocks - 1) / BLOCK_SIZE + 1; int block = 2; do @@ -90,7 +90,7 @@ class VolumeDirectoryHeader extends DirectoryHeader { byte[] buf = disk.readBlock (block); blockList.add (buf); - block = Utility.intValue (buf[2], buf[3]); // next block + block = Utility.intValue (buf[2], buf[3]); // next block } while (block > 0); byte[] fullBuffer = new byte[blockList.size () * 507]; @@ -100,6 +100,7 @@ class VolumeDirectoryHeader extends DirectoryHeader System.arraycopy (bfr, 4, fullBuffer, offset, 507); offset += 507; } + return new ProdosDirectory (parentDisk, name, fullBuffer, totalBlocks, freeBlocks, usedBlocks); } @@ -114,6 +115,14 @@ class VolumeDirectoryHeader extends DirectoryHeader return sectors; } + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + return String.format ("%s %04X %02X", super.getText (), totalBlocks, bitMapBlock); + } + // ---------------------------------------------------------------------------------// @Override public String toString () diff --git a/src/com/bytezone/diskbrowser/prodos/write/DirectoryHeader.java b/src/com/bytezone/diskbrowser/prodos/write/DirectoryHeader.java index a872e2d..e0facc2 100644 --- a/src/com/bytezone/diskbrowser/prodos/write/DirectoryHeader.java +++ b/src/com/bytezone/diskbrowser/prodos/write/DirectoryHeader.java @@ -14,6 +14,7 @@ import java.time.LocalDateTime; public class DirectoryHeader // -----------------------------------------------------------------------------------// { + static final String UNDERLINE = "--------------------------------------------"; ProdosDisk disk; byte[] buffer; int ptr; @@ -70,6 +71,49 @@ public class DirectoryHeader writeShort (buffer, ptr + 0x21, fileCount); } + // ---------------------------------------------------------------------------------// + void list () + // ---------------------------------------------------------------------------------// + { + System.out.println (UNDERLINE); + System.out.println (toText ()); + System.out.println (UNDERLINE); + + int blockNo = ptr / BLOCK_SIZE; + + do + { + int offset = blockNo * BLOCK_SIZE; + int ptr = offset + 4; + for (int i = 0; i < ENTRIES_PER_BLOCK; i++) + { + int storageType = (buffer[ptr] & 0xF0) >>> 4; + int nameLength = buffer[ptr] & 0x0F; + if (nameLength != 0 && storageType < 0x0E) + { + FileEntry fileEntry = new FileEntry (disk, buffer, ptr); + fileEntry.read (); + System.out.println (fileEntry.toText ()); + } + + ptr += ENTRY_SIZE; + } + blockNo = readShort (buffer, offset + 2); + } while (blockNo > 0); + System.out.println (); + } + + // ---------------------------------------------------------------------------------// + String toText () + // ---------------------------------------------------------------------------------// + { + int block = ptr / BLOCK_SIZE; + int entry = ((ptr % BLOCK_SIZE) - 4) / 39 + 1; + + return String.format ("%04X:%02X %-15s %02X %04X", block, entry, fileName, + storageType, fileCount); + } + // ---------------------------------------------------------------------------------// @Override public String toString () diff --git a/src/com/bytezone/diskbrowser/prodos/write/FileEntry.java b/src/com/bytezone/diskbrowser/prodos/write/FileEntry.java index fba6112..cbc28fe 100644 --- a/src/com/bytezone/diskbrowser/prodos/write/FileEntry.java +++ b/src/com/bytezone/diskbrowser/prodos/write/FileEntry.java @@ -309,6 +309,17 @@ public class FileEntry return indexBlock; } + // ---------------------------------------------------------------------------------// + String toText () + // ---------------------------------------------------------------------------------// + { + int block = ptr / BLOCK_SIZE; + int entry = ((ptr % BLOCK_SIZE) - 4) / 39 + 1; + + return String.format ("%04X:%02X %-15s %02X %04X %02X %04X %04X", block, entry, + fileName, storageType, blocksUsed, fileType, keyPointer, headerPointer); + } + // ---------------------------------------------------------------------------------// @Override public String toString () diff --git a/src/com/bytezone/diskbrowser/prodos/write/ProdosDisk.java b/src/com/bytezone/diskbrowser/prodos/write/ProdosDisk.java index 458610b..a21c39d 100644 --- a/src/com/bytezone/diskbrowser/prodos/write/ProdosDisk.java +++ b/src/com/bytezone/diskbrowser/prodos/write/ProdosDisk.java @@ -14,10 +14,10 @@ import java.io.IOException; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.BitSet; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.TreeMap; // -----------------------------------------------------------------------------------// public class ProdosDisk @@ -38,7 +38,7 @@ public class ProdosDisk private final byte[] bootSector = new byte[BLOCK_SIZE]; private VolumeDirectoryHeader volumeDirectoryHeader; - private Map subdirectoryHeaders = new HashMap<> (); + private Map subdirectoryHeaders = new TreeMap<> (); private List paths = new ArrayList<> (); // ---------------------------------------------------------------------------------// @@ -126,9 +126,11 @@ public class ProdosDisk throws DiskFullException, VolumeCatalogFullException // ---------------------------------------------------------------------------------// { + if (path.isBlank ()) + throw new IllegalArgumentException ("Path is empty"); + // save path for verification paths.add (path); - System.out.printf ("Path: %s%n", path); // split the full path into an array of subdirectories and a file name String[] subdirectories; @@ -249,13 +251,23 @@ public class ProdosDisk { for (SubdirectoryHeader subdirectoryHeader : subdirectoryHeaders.values ()) { - System.out.printf ("%-35s%n", subdirectoryHeader.fileName); + // System.out.printf ("%-35s%n", subdirectoryHeader.fileName); FileEntry fileEntry = subdirectoryHeader.getParentFileEntry (); if (!fileEntry.fileName.equals (subdirectoryHeader.fileName)) - System.out.println ("fail"); + System.out.printf ("fail: %s%n", subdirectoryHeader.fileName); } } + // ---------------------------------------------------------------------------------// + void display () + // ---------------------------------------------------------------------------------// + { + volumeDirectoryHeader.list (); + + for (SubdirectoryHeader subdirectoryHeader : subdirectoryHeaders.values ()) + subdirectoryHeader.list (); + } + // ---------------------------------------------------------------------------------// public void close () // ---------------------------------------------------------------------------------// @@ -278,7 +290,8 @@ public class ProdosDisk } System.out.println (); } - verify (); + // verify (); + // display (); } // ---------------------------------------------------------------------------------// diff --git a/src/com/bytezone/diskbrowser/prodos/write/SubdirectoryHeader.java b/src/com/bytezone/diskbrowser/prodos/write/SubdirectoryHeader.java index fb0ab21..da8fce2 100644 --- a/src/com/bytezone/diskbrowser/prodos/write/SubdirectoryHeader.java +++ b/src/com/bytezone/diskbrowser/prodos/write/SubdirectoryHeader.java @@ -2,7 +2,6 @@ package com.bytezone.diskbrowser.prodos.write; import static com.bytezone.diskbrowser.prodos.ProdosConstants.BLOCK_SIZE; import static com.bytezone.diskbrowser.prodos.ProdosConstants.ENTRY_SIZE; -import static com.bytezone.diskbrowser.prodos.write.ProdosDisk.UNDERLINE; import static com.bytezone.diskbrowser.utilities.Utility.readShort; import static com.bytezone.diskbrowser.utilities.Utility.writeShort; @@ -92,6 +91,14 @@ public class SubdirectoryHeader extends DirectoryHeader buffer[ptr + 0x26] = parentEntryLength; } + // ---------------------------------------------------------------------------------// + @Override + String toText () + // ---------------------------------------------------------------------------------// + { + return String.format ("%s %04X:%02X", super.toText (), parentPointer, parentEntry); + } + // ---------------------------------------------------------------------------------// @Override public String toString () diff --git a/src/com/bytezone/diskbrowser/prodos/write/VolumeDirectoryHeader.java b/src/com/bytezone/diskbrowser/prodos/write/VolumeDirectoryHeader.java index b691c26..b900bfe 100644 --- a/src/com/bytezone/diskbrowser/prodos/write/VolumeDirectoryHeader.java +++ b/src/com/bytezone/diskbrowser/prodos/write/VolumeDirectoryHeader.java @@ -1,6 +1,5 @@ package com.bytezone.diskbrowser.prodos.write; -import static com.bytezone.diskbrowser.prodos.write.ProdosDisk.UNDERLINE; import static com.bytezone.diskbrowser.utilities.Utility.readShort; import static com.bytezone.diskbrowser.utilities.Utility.writeShort; @@ -42,6 +41,14 @@ public class VolumeDirectoryHeader extends DirectoryHeader writeShort (buffer, ptr + 0x25, totalBlocks); } + // ---------------------------------------------------------------------------------// + @Override + String toText () + // ---------------------------------------------------------------------------------// + { + return String.format ("%-29s %04X %04X", super.toText (), totalBlocks, bitMapPointer); + } + // ---------------------------------------------------------------------------------// @Override public String toString () diff --git a/src/com/bytezone/diskbrowser/utilities/LZW2.java b/src/com/bytezone/diskbrowser/utilities/LZW2.java index 6cc33f2..59ff129 100644 --- a/src/com/bytezone/diskbrowser/utilities/LZW2.java +++ b/src/com/bytezone/diskbrowser/utilities/LZW2.java @@ -44,7 +44,8 @@ class LZW2 extends LZW setBuffer (buffer, ptr); // prepare to read n-bit integers byte[] lzwBuffer = undoLZW (rleLength); - assert (chunkLength - 4) == bytesRead (); + if ((chunkLength - 4) != bytesRead ()) + System.out.printf ("Invalid chunk length%n"); if (rleLength == TRACK_LENGTH) // no run length encoding chunks.add (lzwBuffer); diff --git a/src/com/bytezone/diskbrowser/utilities/MasterHeader.java b/src/com/bytezone/diskbrowser/utilities/MasterHeader.java index e736257..bcacc27 100644 --- a/src/com/bytezone/diskbrowser/utilities/MasterHeader.java +++ b/src/com/bytezone/diskbrowser/utilities/MasterHeader.java @@ -47,7 +47,9 @@ class MasterHeader reserved = Utility.getWord (buffer, ptr + 30); eof = Utility.getLong (buffer, ptr + 38); - assert reserved == 0; + // assert reserved == 0; + // if (reserved != 0) + // System.out.printf ("Reserved for zero, actual: %02X%n", reserved); byte[] crcBuffer = new byte[40]; System.arraycopy (buffer, ptr + 8, crcBuffer, 0, crcBuffer.length); @@ -87,6 +89,7 @@ class MasterHeader text.append (String.format ("Created ........ %s%n", created.format ())); text.append (String.format ("Modified ....... %s%n", modified.format ())); text.append (String.format ("Version ........ %,d%n", version)); + text.append (String.format ("Reserved ....... %016X%n", reserved)); text.append (String.format ("Master EOF ..... %,d", eof)); return text.toString (); diff --git a/src/com/bytezone/diskbrowser/utilities/NuFX.java b/src/com/bytezone/diskbrowser/utilities/NuFX.java index c5526b4..1e93568 100644 --- a/src/com/bytezone/diskbrowser/utilities/NuFX.java +++ b/src/com/bytezone/diskbrowser/utilities/NuFX.java @@ -118,6 +118,12 @@ public class NuFX if (record.hasFile ()) { String fileName = volumeName.convert (record.getFileName ()); + if (!record.isValidFileSystem ()) + { + System.out.printf ("File %s is file system %s%n", fileName, + record.getFileSystemName ()); + continue; + } // int fileSize = record.getFileSize (); byte fileType = (byte) record.getFileType (); int eof = record.getUncompressedSize (); diff --git a/src/com/bytezone/diskbrowser/utilities/Record.java b/src/com/bytezone/diskbrowser/utilities/Record.java index 8a512e9..f762d57 100644 --- a/src/com/bytezone/diskbrowser/utilities/Record.java +++ b/src/com/bytezone/diskbrowser/utilities/Record.java @@ -86,6 +86,13 @@ class Record fileName = ""; } + // ---------------------------------------------------------------------------------// + boolean isValidFileSystem () + // ---------------------------------------------------------------------------------// + { + return fileSystemID <= 4 || fileSystemID == 8; + } + // ---------------------------------------------------------------------------------// int getAttributes () // ---------------------------------------------------------------------------------// @@ -198,6 +205,13 @@ class Record return fileSystemID; } + // ---------------------------------------------------------------------------------// + String getFileSystemName () + // ---------------------------------------------------------------------------------// + { + return fileSystems[fileSystemID]; + } + // ---------------------------------------------------------------------------------// int getFileSize () // ---------------------------------------------------------------------------------// diff --git a/src/com/bytezone/diskbrowser/utilities/Thread.java b/src/com/bytezone/diskbrowser/utilities/Thread.java index 85130e4..8760931 100644 --- a/src/com/bytezone/diskbrowser/utilities/Thread.java +++ b/src/com/bytezone/diskbrowser/utilities/Thread.java @@ -52,7 +52,8 @@ class Thread { case 0: // uncompressed break; - case 1: // Huffman Squeeze + case 1: // Huffman Squeeze - see archivers folder + System.out.printf ("Huffman squeeze"); break; case 2: // Dynamic LZW/1 lzw = new LZW1 (data);