From f78dce5d058600491d7bb32c95b9089b786e9cdc Mon Sep 17 00:00:00 2001 From: Denis Molony Date: Sun, 12 Jul 2020 12:46:18 +1000 Subject: [PATCH] Some OMF, initial DiskCopy 4.2 --- .../applefile/FileSystemTranslator.java | 9 + .../diskbrowser/applefile/ObjectModule.java | 50 +++ .../diskbrowser/applefile/SegmentHeader.java | 356 ++++++++++++++++++ .../bytezone/diskbrowser/disk/AppleDisk.java | 14 +- .../diskbrowser/disk/DiskFactory.java | 51 ++- .../diskbrowser/disk/PrefixDiskCopy.java | 54 +++ .../diskbrowser/prodos/FileEntry.java | 3 +- .../diskbrowser/utilities/Utility.java | 15 +- 8 files changed, 540 insertions(+), 12 deletions(-) create mode 100644 src/com/bytezone/diskbrowser/applefile/ObjectModule.java create mode 100644 src/com/bytezone/diskbrowser/applefile/SegmentHeader.java create mode 100644 src/com/bytezone/diskbrowser/disk/PrefixDiskCopy.java diff --git a/src/com/bytezone/diskbrowser/applefile/FileSystemTranslator.java b/src/com/bytezone/diskbrowser/applefile/FileSystemTranslator.java index aee35b8..e0aaf9a 100644 --- a/src/com/bytezone/diskbrowser/applefile/FileSystemTranslator.java +++ b/src/com/bytezone/diskbrowser/applefile/FileSystemTranslator.java @@ -2,14 +2,18 @@ package com.bytezone.diskbrowser.applefile; import com.bytezone.diskbrowser.utilities.HexFormatter; +// -----------------------------------------------------------------------------------// public class FileSystemTranslator extends AbstractFile +// -----------------------------------------------------------------------------------// { private final String text1; private final String text2; private final String text3; private final String text4; + // ---------------------------------------------------------------------------------// public FileSystemTranslator (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// { super (name, buffer); @@ -20,10 +24,15 @@ public class FileSystemTranslator extends AbstractFile text3 = HexFormatter.getPascalString (buffer, 0xFC + len1 + 1); int len2 = buffer[0xFC + len1 + 1] & 0xFF; text4 = HexFormatter.getPascalString (buffer, 0xFC + len1 + len2 + 4); + + SegmentHeader segmentHeader = new SegmentHeader (buffer, 0); + System.out.println (segmentHeader); } + // ---------------------------------------------------------------------------------// @Override public String getText () + // ---------------------------------------------------------------------------------// { StringBuilder text = new StringBuilder ("Name : " + name + "\n\n"); diff --git a/src/com/bytezone/diskbrowser/applefile/ObjectModule.java b/src/com/bytezone/diskbrowser/applefile/ObjectModule.java new file mode 100644 index 0000000..7ccfbc2 --- /dev/null +++ b/src/com/bytezone/diskbrowser/applefile/ObjectModule.java @@ -0,0 +1,50 @@ +package com.bytezone.diskbrowser.applefile; + +import java.util.ArrayList; +import java.util.List; + +import com.bytezone.diskbrowser.utilities.Utility; + +// -----------------------------------------------------------------------------------// +public class ObjectModule extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + List segmentHeaders = new ArrayList<> (); + + // ---------------------------------------------------------------------------------// + public ObjectModule (String name, byte[] buffer, int auxType) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + + int ptr = 0; + + while (ptr < buffer.length - 4) + { + int byteCount = Utility.getLong (buffer, ptr); + if (byteCount == 0) + break; + + segmentHeaders.add (new SegmentHeader (buffer, ptr)); + ptr += byteCount; + } + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder ("Name : " + name + "\n\n"); + + text.append ("Object Module\n\n"); + + for (SegmentHeader segmentHeader : segmentHeaders) + { + text.append (segmentHeader); + text.append ("\n"); + } + + return text.toString (); + } +} diff --git a/src/com/bytezone/diskbrowser/applefile/SegmentHeader.java b/src/com/bytezone/diskbrowser/applefile/SegmentHeader.java new file mode 100644 index 0000000..640b3ce --- /dev/null +++ b/src/com/bytezone/diskbrowser/applefile/SegmentHeader.java @@ -0,0 +1,356 @@ +package com.bytezone.diskbrowser.applefile; + +import com.bytezone.diskbrowser.utilities.HexFormatter; +import com.bytezone.diskbrowser.utilities.Utility; + +// -----------------------------------------------------------------------------------// +public class SegmentHeader +// -----------------------------------------------------------------------------------// +{ + int bytecnt; + int resspc; + int length; + int kind1; + + String kindWhereText; + boolean kindReload; + boolean kindAbsoluteBank; + boolean kindSpecialMemory; + boolean kindPosIndependent; + boolean kindPrivate; + boolean kindStatic; + + int lablen; + int numlen; + int version; + int banksize; + int kind2; + int unused; + int org; + int align; + int numsex; + int lcbank; + int segnum; + int entry; + int dispname; + int dispdata; + String loadname; + String segname; + + // ---------------------------------------------------------------------------------// + public SegmentHeader (byte[] buffer, int offset) + // ---------------------------------------------------------------------------------// + { + bytecnt = Utility.getLong (buffer, offset); + resspc = Utility.getLong (buffer, offset + 4); + length = Utility.getLong (buffer, offset + 8); + + kind1 = buffer[offset + 12] & 0xFF; + + lablen = buffer[offset + 13] & 0xFF; + numlen = buffer[offset + 14] & 0xFF; + version = buffer[offset + 15] & 0xFF; + + banksize = Utility.getLong (buffer, offset + 16); + kind2 = Utility.getWord (buffer, offset + 20); + unused = Utility.getWord (buffer, offset + 22); + org = Utility.getLong (buffer, offset + 24); + align = Utility.getLong (buffer, offset + 28); + + numsex = buffer[offset + 32] & 0xFF; + lcbank = buffer[offset + 33] & 0xFF; + + segnum = Utility.getWord (buffer, offset + 34); + + entry = Utility.getLong (buffer, offset + 36); + + dispname = Utility.getWord (buffer, offset + 40); + dispdata = Utility.getWord (buffer, offset + 42); + + decodeKind (); + + if (buffer[offset + dispname] == 0) + loadname = ""; + else + loadname = new String (buffer, offset + dispname, 10); + + if (lablen == 0) + segname = HexFormatter.getPascalString (buffer, offset + dispname + 10); + else + segname = "not finished"; + + System.out.println (this); + + int ptr = offset + dispdata; + while (true) + { + int recType = buffer[ptr] & 0xFF; + // System.out.printf ("%04X = %02X%n", ptr, recType); + + if (recType > 0 && recType <= 0xDF) + { + 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); + switch (recType) + { + case 0x00: // END + System.out.println ("END"); + break; + + case 0xE0: // ALIGN + System.out.printf ("ALIGN:%n"); + break; + + case 0xE1: // ORG + System.out.printf ("ORG:%n"); + break; + + case 0xE2: // RELOC + int bytesRelocated = buffer[ptr + 1] & 0xFF; + 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); + ptr += 11; + continue; + + case 0xE3: // INTERSEG + int count1 = buffer[ptr + 1] & 0xFF; + int count2 = buffer[ptr + 2] & 0xFF; + int operandOffset = Utility.getLong (buffer, ptr + 3); + 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); + ptr += 15; + break; + + case 0xE4: // USING + System.out.printf ("USING:%n"); + break; + + case 0xE5: // STRONG + System.out.printf ("STRONG:%n"); + break; + + case 0xE6: // GLOBAL + System.out.printf ("GLOBAL:%n"); + break; + + case 0xE7: // GEQU + System.out.printf ("GEQU:%n"); + break; + + case 0xE8: // MEM + System.out.printf ("MEM:%n"); + break; + + case 0xEB: // EXPR + System.out.printf ("EXPR:%n"); + break; + + case 0xEC: // ZEXPR + System.out.printf ("ZEXPR:%n"); + break; + + case 0xED: // BEXPR + System.out.printf ("BEXPR:%n"); + break; + + case 0xEE: // RELEXPR + System.out.printf ("RELEXPR:%n"); + break; + + case 0xEF: // LOCAL + System.out.printf ("LOCAL:%n"); + break; + + case 0xF0: // EQU + String label = HexFormatter.getPascalString (buffer, ptr + 1); + System.out.printf ("EQU: %s%n", label); + break; + + case 0xF1: // DS + System.out.printf ("DS:%n"); + break; + + case 0xF2: // LCONST + int constLength = Utility.getLong (buffer, ptr + 1); + System.out.printf ("Const: %04X%n", constLength); + ptr += constLength + 5; + continue; + + case 0xF3: // LEXPR + System.out.printf ("LEXPR:%n"); + break; + + case 0xF4: // ENTRY + System.out.printf ("ENTRY:%n"); + break; + + case 0xF5: // cRELOC + int cBytesRelocated = buffer[ptr + 1] & 0xFF; + 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); + ptr += 7; + continue; + + case 0xF6: // cINTERSEG + int cCount1 = buffer[ptr + 1] & 0xFF; + int cCount2 = buffer[ptr + 2] & 0xFF; + 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); + 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); + ptr += superLength + 5; + continue; + + default: + System.out.printf ("Unknown record type: %02X%n", recType); + break; + } + + System.out.println (); + break; + } + } + + // ---------------------------------------------------------------------------------// + private void decodeKind () + // ---------------------------------------------------------------------------------// + { + int segType; + int segAttr; + + if (version < 2) // 8 bits + { + segType = kind1 & 0x1F; + segAttr = kind1 & 0xE0; + } + else // 16 bits + { + segType = kind2 & 0x001F; + segAttr = kind2 >>> 8; + } + + kindReload = (segAttr & 0x04) != 0; + kindAbsoluteBank = (segAttr & 0x08) != 0; + kindSpecialMemory = (segAttr & 0x10) == 0; + kindPosIndependent = (segAttr & 0x20) != 0; + kindPrivate = (segAttr & 0x40) != 0; + kindStatic = (segAttr & 0x80) == 0; + + 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; + } + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + text.append (String.format ("Byte count ......... %08X%n", bytecnt)); + text.append (String.format ("Reserved space ..... %08X%n", resspc)); + text.append (String.format ("Length ............. %08X%n", length)); + + text.append (String.format ("Kind v1 ............ %02X%n", kind1)); + if (version < 2) + { + text.append (String.format (" Type ............. %s%n", kindWhereText)); + text.append ( + String.format (" Position ind ..... %s%n", kindPosIndependent ? "Yes" : "No")); + text.append ( + String.format (" Private .......... %s%n", kindPrivate ? "Yes" : "No")); + text.append ( + String.format (" Static/Dynamic ... %s%n", kindStatic ? "Static" : "Dynamic")); + } + + text.append (String.format ("Label length ....... %02X%n", lablen)); + text.append (String.format ("Number length ...... %02X%n", numlen)); + text.append (String.format ("Version ............ %02X%n", version)); + + text.append (String.format ("Bank size .......... %08X%n", banksize)); + text.append (String.format ("Kind v2 ............ %04X%n", kind2)); + + if (version >= 2) + { + text.append (String.format (" Type ............. %s%n", kindWhereText)); + text.append ( + String.format (" Reload ........... %s%n", kindReload ? "Yes" : "No")); + text.append ( + String.format (" Absolute Bank .... %s%n", kindAbsoluteBank ? "Yes" : "No")); + text.append ( + String.format (" Special Memory ... %s%n", kindSpecialMemory ? "Yes" : "No")); + text.append ( + String.format (" Position ind ..... %s%n", kindPosIndependent ? "Yes" : "No")); + text.append ( + String.format (" Private .......... %s%n", kindPrivate ? "Yes" : "No")); + text.append ( + String.format (" Static/Dynamic ... %s%n", kindStatic ? "Static" : "Dynamic")); + } + + text.append (String.format ("Unused ............. %04X%n", unused)); + text.append (String.format ("Org ................ %08X%n", org)); + text.append (String.format ("Align .............. %08X%n", align)); + + text.append (String.format ("Number sex ......... %02X%n", numsex)); + text.append (String.format ("LC Bank ............ %02X%n", lcbank)); + + text.append (String.format ("Segment number ..... %04X%n", segnum)); + + text.append (String.format ("Entry .............. %08X%n", entry)); + + text.append (String.format ("Disp name .......... %04X%n", dispname)); + text.append (String.format ("Disp data .......... %04X%n", dispdata)); + + text.append (String.format ("Load name .......... %s%n", loadname)); + text.append (String.format ("Segment name ....... %s%n", segname)); + + return text.toString (); + } +} diff --git a/src/com/bytezone/diskbrowser/disk/AppleDisk.java b/src/com/bytezone/diskbrowser/disk/AppleDisk.java index 0c772dd..8f7f25b 100755 --- a/src/com/bytezone/diskbrowser/disk/AppleDisk.java +++ b/src/com/bytezone/diskbrowser/disk/AppleDisk.java @@ -140,6 +140,18 @@ public class AppleDisk implements Disk this.trackSize = sectors * sectorSize; } } + else if ("img".equals (suffix)) + { + PrefixDiskCopy prefixDiskCopy = new PrefixDiskCopy (buffer); + + blocks = prefixDiskCopy.getBlocks (); + this.sectorSize = 512; + this.trackSize = 8 * sectorSize; + skip = 0x54; + + tracks = blocks / 8; // change parameter! + sectors = 8; // change parameter! + } else if (suffix.equalsIgnoreCase ("HDV") || (suffix.equalsIgnoreCase ("po") && tracks > 50)) // ULTIMATE APPLE1 CFFA 3.5.po { @@ -278,7 +290,7 @@ public class AppleDisk implements Disk private byte[] getPrefix (File path) // ---------------------------------------------------------------------------------// { - byte[] buffer = new byte[64]; + byte[] buffer = new byte[0x54]; try (BufferedInputStream file = new BufferedInputStream (new FileInputStream (path))) { file.read (buffer); diff --git a/src/com/bytezone/diskbrowser/disk/DiskFactory.java b/src/com/bytezone/diskbrowser/disk/DiskFactory.java index f2c4ddb..25ab8f4 100755 --- a/src/com/bytezone/diskbrowser/disk/DiskFactory.java +++ b/src/com/bytezone/diskbrowser/disk/DiskFactory.java @@ -184,12 +184,12 @@ public class DiskFactory if (prodosDisk != null) return prodosDisk; - disk2 = check2mgDisk (file); - if (disk2 != null) + disk = check2mgDisk (file); + if (disk != null) { if (compressed) - disk2.setOriginalPath (originalPath); - return disk2; + disk.setOriginalPath (originalPath); + return disk; } AppleDisk appleDisk = new AppleDisk (file, (int) file.length () / 4096, 8); @@ -200,18 +200,25 @@ public class DiskFactory { if (debug) System.out.println (" ** 2mg **"); - disk2 = check2mgDisk (file); - if (disk2 != null) + disk = check2mgDisk (file); + if (disk != null) { if (compressed) - disk2.setOriginalPath (originalPath); - return disk2; + disk.setOriginalPath (originalPath); + return disk; } AppleDisk appleDisk = new AppleDisk (file, (int) file.length () / 4096, 8); return new DataDisk (appleDisk); } + if (suffix.equals ("img")) + { + disk = checkDiskCopyDisk (file); + if (disk != null) + return disk; + } + // Toolkit.do = 143488 if (((suffix.equals ("po") || suffix.equals ("dsk") || suffix.equals ("do")) && file.length () > 143360)) @@ -699,7 +706,6 @@ public class DiskFactory catch (Exception e) { e.printStackTrace (); - // System.out.println (e); } if (debug) System.out.println ("Not a 2mg disk"); @@ -707,6 +713,33 @@ public class DiskFactory return null; } + // ---------------------------------------------------------------------------------// + private static FormattedDisk checkDiskCopyDisk (File file) + // ---------------------------------------------------------------------------------// + { + if (debug) + System.out.println ("Checking DiskCopy disk"); + + try + { + AppleDisk disk = new AppleDisk (file, 0, 0); + if (disk.getTotalBlocks () > 0) + { + if (ProdosDisk.isCorrectFormat (disk)) + return new ProdosDisk (disk); + } + } + catch (Exception e) + { + e.printStackTrace (); + } + + if (debug) + System.out.println ("Not a DiskCopy disk"); + + return null; + } + // ---------------------------------------------------------------------------------// private static FormattedDisk checkPascalDisk (AppleDisk disk) // ---------------------------------------------------------------------------------// diff --git a/src/com/bytezone/diskbrowser/disk/PrefixDiskCopy.java b/src/com/bytezone/diskbrowser/disk/PrefixDiskCopy.java new file mode 100644 index 0000000..9b7cc2c --- /dev/null +++ b/src/com/bytezone/diskbrowser/disk/PrefixDiskCopy.java @@ -0,0 +1,54 @@ +package com.bytezone.diskbrowser.disk; + +import com.bytezone.diskbrowser.utilities.HexFormatter; +import com.bytezone.diskbrowser.utilities.Utility; + +// -----------------------------------------------------------------------------------// +public class PrefixDiskCopy +// -----------------------------------------------------------------------------------// +{ + private String name; + private int dataSize; + private int tagSize; + private int encoding; + private int format; + private int id; + + // ---------------------------------------------------------------------------------// + public PrefixDiskCopy (byte[] buffer) + // ---------------------------------------------------------------------------------// + { + int nameLength = buffer[0] * 0xFF; + if (nameLength < 1 || nameLength > 0x3F) + name = HexFormatter.getPascalString (buffer, 0); + dataSize = Utility.getLongBigEndian (buffer, 0x40); + tagSize = Utility.getLongBigEndian (buffer, 0x44); + encoding = buffer[0x50] & 0xFF; + format = buffer[0x51] & 0xFF; + id = Utility.getWordBigEndian (buffer, 0x52); + } + + // ---------------------------------------------------------------------------------// + int getBlocks () + // ---------------------------------------------------------------------------------// + { + return dataSize / 512; + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + text.append (String.format ("Name : %s%n", name)); + text.append (String.format ("Data size : %08X (%<,d)%n", dataSize)); + text.append (String.format ("Tag size : %08X (%<,d)%n", tagSize)); + text.append (String.format ("Encoding : %02X%n", encoding)); + text.append (String.format ("Format : %02X%n", format)); + text.append (String.format ("ID : %04X%n", id)); + + return text.toString (); + } +} diff --git a/src/com/bytezone/diskbrowser/prodos/FileEntry.java b/src/com/bytezone/diskbrowser/prodos/FileEntry.java index d39ecf1..cca612a 100755 --- a/src/com/bytezone/diskbrowser/prodos/FileEntry.java +++ b/src/com/bytezone/diskbrowser/prodos/FileEntry.java @@ -23,6 +23,7 @@ import com.bytezone.diskbrowser.applefile.IconFile; import com.bytezone.diskbrowser.applefile.IntegerBasicProgram; import com.bytezone.diskbrowser.applefile.LodeRunner; 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.QuickDrawFont; @@ -433,7 +434,7 @@ class FileEntry extends CatalogEntry implements ProdosConstants break; case FILE_TYPE_IIGS_APPLICATION: - file = new AssemblerProgram (name, buffer, auxType); + file = new ObjectModule (name, exactBuffer, auxType); break; case FILE_TYPE_IIGS_DEVICE_DRIVER: diff --git a/src/com/bytezone/diskbrowser/utilities/Utility.java b/src/com/bytezone/diskbrowser/utilities/Utility.java index d9f163d..d918f9e 100644 --- a/src/com/bytezone/diskbrowser/utilities/Utility.java +++ b/src/com/bytezone/diskbrowser/utilities/Utility.java @@ -18,7 +18,7 @@ public class Utility // -----------------------------------------------------------------------------------// { public static final List suffixes = - Arrays.asList ("po", "dsk", "do", "hdv", "2mg", "v2d", "d13", "sdk", "woz"); + Arrays.asList ("po", "dsk", "do", "hdv", "2mg", "v2d", "d13", "sdk", "woz", "img"); // ---------------------------------------------------------------------------------// public static boolean test (Graphics2D g) @@ -92,6 +92,19 @@ public class Utility return val; } + // ---------------------------------------------------------------------------------// + public static int getWordBigEndian (byte[] buffer, int ptr) + // ---------------------------------------------------------------------------------// + { + int val = 0; + for (int i = 0; i < 2; i++) + { + val <<= 8; + val += buffer[ptr + i] & 0xFF; + } + return val; + } + // ---------------------------------------------------------------------------------// public static int unsignedShort (byte[] buffer, int ptr) // ---------------------------------------------------------------------------------//