From e911fae8309fcbf3eeac8695426324bf4399d1ff Mon Sep 17 00:00:00 2001 From: Denis Molony Date: Tue, 2 Aug 2016 20:37:27 +1000 Subject: [PATCH] new pascal Relocator --- .../diskbrowser/applefile/PascalCode.java | 111 ++-- .../applefile/PascalCodeStatement.java | 594 +++++++++--------- .../applefile/PascalConstants.java | 190 +++--- .../applefile/PascalProcedure.java | 309 ++++----- .../diskbrowser/applefile/PascalSegment.java | 42 +- .../diskbrowser/applefile/Relocator.java | 107 ++++ .../bytezone/diskbrowser/disk/AppleDisk.java | 1 + .../diskbrowser/disk/DiskFactory.java | 2 +- .../bytezone/diskbrowser/gui/DiskBrowser.java | 5 +- .../bytezone/diskbrowser/gui/WindowSaver.java | 20 +- .../diskbrowser/pascal/CatalogEntry.java | 15 +- .../diskbrowser/pascal/FileEntry.java | 25 +- .../diskbrowser/pascal/PascalDisk.java | 98 +-- .../diskbrowser/pascal/VolumeEntry.java | 17 +- 14 files changed, 850 insertions(+), 686 deletions(-) create mode 100644 src/com/bytezone/diskbrowser/applefile/Relocator.java diff --git a/src/com/bytezone/diskbrowser/applefile/PascalCode.java b/src/com/bytezone/diskbrowser/applefile/PascalCode.java index 6d82ab1..91d0151 100755 --- a/src/com/bytezone/diskbrowser/applefile/PascalCode.java +++ b/src/com/bytezone/diskbrowser/applefile/PascalCode.java @@ -4,66 +4,79 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import com.bytezone.diskbrowser.utilities.FileFormatException; import com.bytezone.diskbrowser.utilities.HexFormatter; -public class PascalCode extends AbstractFile implements PascalConstants, Iterable +public class PascalCode extends AbstractFile + implements PascalConstants, Iterable { - List segments = new ArrayList (16); - String codeName; - String comment; + List segments = new ArrayList (16); + String codeName; + String comment; - public static void print () - { - for (int i = 0; i < 216; i++) - System.out.printf ("%3d %d %3s %s%n", i + 128, PascalConstants.mnemonicSize[i], - PascalConstants.mnemonics[i], PascalConstants.descriptions[i]); - } + public static void print () + { + for (int i = 0; i < 216; i++) + System.out.printf ("%3d %d %3s %s%n", i + 128, PascalConstants.mnemonicSize[i], + PascalConstants.mnemonics[i], PascalConstants.descriptions[i]); + } - public PascalCode (String name, byte[] buffer) - { - super (name, buffer); - int nonameCounter = 0; + public PascalCode (String name, byte[] buffer) + { + super (name, buffer); + int nonameCounter = 0; - // Build segment list (up to 16 segments) - for (int i = 0; i < 16; i++) - { - codeName = HexFormatter.getString (buffer, 0x40 + i * 8, 8).trim (); - int size = HexFormatter.intValue (buffer[i * 4 + 2], buffer[i * 4 + 3]); - if (size > 0) - { - if (codeName.length () == 0) - codeName = ""; - segments.add (new PascalSegment (codeName, buffer, i)); - } - } - comment = HexFormatter.getPascalString (buffer, 0x1B0); - } + // Build segment list (up to 16 segments) + for (int i = 0; i < 16; i++) + { + codeName = HexFormatter.getString (buffer, 0x40 + i * 8, 8).trim (); + int size = HexFormatter.intValue (buffer[i * 4 + 2], buffer[i * 4 + 3]); + System.out.printf ("%s %s %d %n", HexFormatter.getHexString (buffer, i * 4, 4), + codeName, size); + if (size > 0) + { + if (codeName.length () == 0) + codeName = ""; + try + { + segments.add (new PascalSegment (codeName, buffer, i)); + } + catch (FileFormatException e) + { + System.out.println ("Bad segment"); + } + } + } + comment = HexFormatter.getPascalString (buffer, 0x1B0); + } - public String getText () - { - StringBuilder text = new StringBuilder (getHeader ()); + @Override + public String getText () + { + StringBuilder text = new StringBuilder (getHeader ()); - text.append ("Segment Dictionary\n==================\n\n"); + text.append ("Segment Dictionary\n==================\n\n"); - text.append ("Slot Addr Len Len Name Kind" - + " Text Seg# Mtyp Vers I/S\n"); - text.append ("---- ---- ----- ----- -------- ---------------" - + " ---- ---- ---- ---- ---\n"); + text.append ("Slot Addr Len Len Name Kind" + + " Text Seg# Mtyp Vers I/S\n"); + text.append ("---- ---- ----- ----- -------- ---------------" + + " ---- ---- ---- ---- ---\n"); - for (PascalSegment segment : segments) - text.append (segment.toText () + "\n"); - text.append ("\nComment : " + comment + "\n\n"); + for (PascalSegment segment : segments) + text.append (segment.toText () + "\n"); + text.append ("\nComment : " + comment + "\n\n"); - return text.toString (); - } + return text.toString (); + } - private String getHeader () - { - return "Name : " + name + "\n\n"; - } + private String getHeader () + { + return "Name : " + name + "\n\n"; + } - public Iterator iterator () - { - return segments.iterator (); - } + @Override + public Iterator iterator () + { + return segments.iterator (); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/applefile/PascalCodeStatement.java b/src/com/bytezone/diskbrowser/applefile/PascalCodeStatement.java index 49b86fc..f3dbb7b 100755 --- a/src/com/bytezone/diskbrowser/applefile/PascalCodeStatement.java +++ b/src/com/bytezone/diskbrowser/applefile/PascalCodeStatement.java @@ -7,323 +7,331 @@ import com.bytezone.diskbrowser.utilities.HexFormatter; public class PascalCodeStatement implements PascalConstants { - private static final String[] compValue = - { "invalid", "", "REAL", "", "STR", "", "BOOL", "", "POWR", "", "BYT", "", "WORD" }; + private static final String[] compValue = + { "invalid", "", "REAL", "", "STR", "", "BOOL", "", "POWR", "", "BYT", "", "WORD" }; - int length; - int val; - int p1, p2, p3; - String mnemonic; - String extras = ""; - String description; - String text; - int ptr; // temp - byte[] buffer; - boolean jumpTarget; - List jumps = new ArrayList (); + int length; + int val; + int p1, p2, p3; + String mnemonic; + String extras = ""; + String description; + String text; + int ptr; // temp + byte[] buffer; + boolean jumpTarget; + List jumps = new ArrayList (); - public PascalCodeStatement (byte[] buffer, int ptr, int procPtr) - { - this.ptr = ptr; - this.buffer = buffer; - length = 1; - val = buffer[ptr] & 0xFF; - if (val <= 127) - { - mnemonic = "SLDC"; - extras = "#" + val; - description = "Short load constant - push #" + val; - } - else if (val >= 248) - { - mnemonic = "SIND"; - extras = "#" + (val - 248); - description = "Short index load - push word *ToS + #" + (val - 248); - } - else if (val >= 232) - { - mnemonic = "SLDO"; - extras = "#" + (val - 231); - description = "Short load global - push BASE + #" + (val - 231); - } - else if (val >= 216) - { - mnemonic = "SLDL"; - extras = "#" + (val - 215); - description = "Short load local - push MP + #" + (val - 215); - } - else - { - mnemonic = mnemonics[val - 128]; - description = descriptions[val - 128]; + public PascalCodeStatement (byte[] buffer, int ptr, int procPtr) + { + this.ptr = ptr; + this.buffer = buffer; + length = 1; + val = buffer[ptr] & 0xFF; + if (val <= 127) + { + mnemonic = "SLDC"; + extras = "#" + val; + description = "Short load constant - push #" + val; + } + else if (val >= 248) + { + mnemonic = "SIND"; + extras = "#" + (val - 248); + description = "Short index load - push word *ToS + #" + (val - 248); + } + else if (val >= 232) + { + mnemonic = "SLDO"; + extras = "#" + (val - 231); + description = "Short load global - push BASE + #" + (val - 231); + } + else if (val >= 216) + { + mnemonic = "SLDL"; + extras = "#" + (val - 215); + description = "Short load local - push MP + #" + (val - 215); + } + else + { + mnemonic = mnemonics[val - 128]; + description = descriptions[val - 128]; - length = mnemonicSize[val - 128]; - if (length != 1) - { - switch (val) - { - // W1, W2, W3, - word aligned case jump - case 172: //XJP - int padding = (ptr % 2) == 0 ? 1 : 0; - p1 = getWord (buffer, ptr + padding + 1); - p2 = getWord (buffer, ptr + padding + 3); - p3 = getWord (buffer, ptr + padding + 5); - length = (p2 - p1 + 1) * 2 + 7 + padding; - setParameters (p1, p2, String.format ("%04X", p3)); - int v = p1; - int min = ptr + padding + 7; - int max = min + (p2 - p1) * 2; - for (int i = min; i <= max; i += 2) - { - jumps.add (new Jump (i, i - HexFormatter.intValue (buffer[i], buffer[i + 1]), v++)); - } - break; + length = mnemonicSize[val - 128]; + if (length != 1) + { + switch (val) + { + // W1, W2, W3,
- word aligned case jump + case 172: //XJP + int padding = (ptr % 2) == 0 ? 1 : 0; + p1 = getWord (buffer, ptr + padding + 1); + p2 = getWord (buffer, ptr + padding + 3); + p3 = getWord (buffer, ptr + padding + 5); + length = (p2 - p1 + 1) * 2 + 7 + padding; + setParameters (p1, p2, String.format ("%04X", p3)); + int v = p1; + int min = ptr + padding + 7; + int max = min + (p2 - p1) * 2; + for (int i = min; i <= max; i += 2) + { + jumps.add (new Jump (i, + i - HexFormatter.intValue (buffer[i], buffer[i + 1]), v++)); + } + break; - // UB, - word aligned - case 179: //LDC - p1 = buffer[ptr + 1] & 0xFF; - padding = ptr % 2 == 0 ? 0 : 1; - length = p1 * 2 + padding + 2; - setParameters (p1); - break; + // UB, - word aligned + case 179: //LDC + p1 = buffer[ptr + 1] & 0xFF; + padding = ptr % 2 == 0 ? 0 : 1; + length = p1 * 2 + padding + 2; + setParameters (p1); + break; - // UB, - case 166: // LSA - case 208: // LPA - p1 = buffer[ptr + 1] & 0xFF; - length = p1 + 2; - if (val == 166) - { - text = HexFormatter.getPascalString (buffer, ptr + 1); - description += ": " + text; - } - break; + // UB, + case 166: // LSA + case 208: // LPA + p1 = buffer[ptr + 1] & 0xFF; + length = p1 + 2; + if (val == 166) + { + text = HexFormatter.getPascalString (buffer, ptr + 1); + description += ": " + text; + } + break; - // W - case 199: // LDCI - p1 = getWord (buffer, ptr + 1); - setParameters (p1); - break; + // W + case 199: // LDCI + p1 = getWord (buffer, ptr + 1); + setParameters (p1); + break; - // B - case 162: // INC - case 163: // IND - case 164: // IXA - case 165: // LAO - case 168: // MOV - case 169: // LDO - case 171: // SRO - case 198: // LLA - case 202: // LDL - case 204: // STL - case 213: // BPT - length = getLengthOfB (buffer[ptr + 1]) + 1; - p1 = getValueOfB (buffer, ptr + 1, length - 1); - setParameters (p1); - break; + // B + case 162: // INC + case 163: // IND + case 164: // IXA + case 165: // LAO + case 168: // MOV + case 169: // LDO + case 171: // SRO + case 198: // LLA + case 202: // LDL + case 204: // STL + case 213: // BPT + length = getLengthOfB (buffer[ptr + 1]) + 1; + p1 = getValueOfB (buffer, ptr + 1, length - 1); + setParameters (p1); + break; - // DB, B or UB, B - case 157: // LDE - case 167: // LAE - case 178: // LDA - case 182: // LOD - case 184: // STR - case 209: // STE - length = getLengthOfB (buffer[ptr + 2]) + 2; - p1 = buffer[ptr + 1] & 0xFF; - p2 = getValueOfB (buffer, ptr + 2, length - 2); - setParameters (p1, p2); - break; + // DB, B or UB, B + case 157: // LDE + case 167: // LAE + case 178: // LDA + case 182: // LOD + case 184: // STR + case 209: // STE + length = getLengthOfB (buffer[ptr + 2]) + 2; + p1 = buffer[ptr + 1] & 0xFF; + p2 = getValueOfB (buffer, ptr + 2, length - 2); + setParameters (p1, p2); + break; - // UB1, UB2 - case 192: // IXP - case 205: // CXP - p1 = buffer[ptr + 1] & 0xFF; - p2 = buffer[ptr + 2] & 0xFF; - setParameters (p1, p2); - break; + // UB1, UB2 + case 192: // IXP + case 205: // CXP + p1 = buffer[ptr + 1] & 0xFF; + p2 = buffer[ptr + 2] & 0xFF; + setParameters (p1, p2); + break; - // SB or DB - case 161: // FJP - case 173: // RNP - case 185: // UJP - case 193: // RBP - case 211: // EFJ - case 212: // NFJ - p1 = buffer[ptr + 1]; - if (val == 173 || val == 193) // return from procedure - setParameters (p1); - else if (p1 < 0) - { - // look up jump table entry - int address = procPtr + p1; - int ptr2 = address - ((buffer[address + 1] & 0xFF) * 256 + (buffer[address] & 0xFF)); - extras = String.format ("$%04X", ptr2); - jumps.add (new Jump (ptr, ptr2)); - } - else - { - int address = ptr + length + p1; - extras = String.format ("$%04X", address); - jumps.add (new Jump (ptr, address)); - } - break; + // SB or DB + case 161: // FJP + case 173: // RNP + case 185: // UJP + case 193: // RBP + case 211: // EFJ + case 212: // NFJ + p1 = buffer[ptr + 1]; + if (val == 173 || val == 193) // return from procedure + setParameters (p1); + else if (p1 < 0) + { + // look up jump table entry + int address = procPtr + p1; + int ptr2 = address + - ((buffer[address + 1] & 0xFF) * 256 + (buffer[address] & 0xFF)); + extras = String.format ("$%04X", ptr2); + jumps.add (new Jump (ptr, ptr2)); + } + else + { + int address = ptr + length + p1; + extras = String.format ("$%04X", address); + jumps.add (new Jump (ptr, address)); + } + break; - // UB - case 160: // AOJ - case 170: // SAS - case 174: // CIP - case 188: // LDM - case 189: // STM - case 194: // CBP - case 206: // CLP - case 207: // CGP - p1 = buffer[ptr + 1] & 0xFF; - setParameters (p1); - break; + // UB + case 160: // AOJ + case 170: // SAS + case 174: // CIP + case 188: // LDM + case 189: // STM + case 194: // CBP + case 206: // CLP + case 207: // CGP + p1 = buffer[ptr + 1] & 0xFF; + setParameters (p1); + break; - // CSP - case 158: - p1 = buffer[ptr + 1]; - description = "Call standard procedure - " + CSP[p1]; - break; + // CSP + case 158: + p1 = buffer[ptr + 1] & 0xFF; + if (p1 < CSP.length) + description = "Call standard procedure - " + CSP[p1]; + else + description = "Call standard procedure - index out of bounds"; + break; - // Non-integer comparisons - case 175: - case 176: - case 177: - case 180: - case 181: - case 183: - p1 = buffer[ptr + 1]; // 2/4/6/8/10/12 - if (p1 < 0 || p1 >= compValue.length) - { - System.out.printf ("%d %d %d%n", val, p1, ptr); - mnemonic += "******************************"; - break; - } - mnemonic += compValue[p1]; - if (p1 == 10 || p1 == 12) - { - length = getLengthOfB (buffer[ptr + 2]) + 2; - p2 = getValueOfB (buffer, ptr + 2, length - 2); - setParameters (p2); - } - break; + // Non-integer comparisons + case 175: + case 176: + case 177: + case 180: + case 181: + case 183: + p1 = buffer[ptr + 1] & 0xFF; // 2/4/6/8/10/12 + if (p1 < 0 || p1 >= compValue.length) + { + System.out.printf ("%d %d %d%n", val, p1, ptr); + mnemonic += "******************************"; + break; + } + mnemonic += compValue[p1]; + if (p1 == 10 || p1 == 12) + { + length = getLengthOfB (buffer[ptr + 2]) + 2; + p2 = getValueOfB (buffer, ptr + 2, length - 2); + setParameters (p2); + } + break; - default: - System.out.println ("Forgot : " + val); - } - } - } - } + default: + System.out.println ("Forgot : " + val); + } + } + } + } - private int getWord (byte[] buffer, int ptr) - { - return (buffer[ptr + 1] & 0xFF) * 256 + (buffer[ptr] & 0xFF); - } + private int getWord (byte[] buffer, int ptr) + { + return (buffer[ptr + 1] & 0xFF) * 256 + (buffer[ptr] & 0xFF); + } - private int getLengthOfB (byte b) - { - return (b & 0x80) == 0x80 ? 2 : 1; - } + private int getLengthOfB (byte b) + { + return (b & 0x80) == 0x80 ? 2 : 1; + } - private int getValueOfB (byte[] buffer, int ptr, int length) - { - if (length == 2) - return (buffer[ptr] & 0x7F) * 256 + (buffer[ptr + 1] & 0xFF); - return buffer[ptr] & 0xFF; - } + private int getValueOfB (byte[] buffer, int ptr, int length) + { + if (length == 2) + return (buffer[ptr] & 0x7F) * 256 + (buffer[ptr + 1] & 0xFF); + return buffer[ptr] & 0xFF; + } - private void setParameters (int p1) - { - description = description.replaceFirst (":1", p1 + ""); - extras = "#" + p1; - } + private void setParameters (int p1) + { + description = description.replaceFirst (":1", p1 + ""); + extras = "#" + p1; + } - private void setParameters (int p1, int p2) - { - setParameters (p1); - extras += ", #" + p2; - description = description.replaceFirst (":2", p2 + ""); - } + private void setParameters (int p1, int p2) + { + setParameters (p1); + extras += ", #" + p2; + description = description.replaceFirst (":2", p2 + ""); + } - private void setParameters (int p1, int p2, String p3) - { - setParameters (p1, p2); - description = description.replaceFirst (":3", p3); - } + private void setParameters (int p1, int p2, String p3) + { + setParameters (p1, p2); + description = description.replaceFirst (":3", p3); + } - public String toString () - { - String hex = getHex (buffer, ptr, length > 4 ? 4 : length); - StringBuilder text = new StringBuilder (); - text.append (String.format ("%2s%05X: %-11s %-6s %-8s %s%n", jumpTarget ? "->" : "", ptr, - hex, mnemonic, extras, description)); - if (length > 4) - { - int bytesLeft = length - 4; - int jmp = 0; - int p = ptr + 4; - while (bytesLeft > 0) - { - String line = getHex (buffer, p, (bytesLeft > 4) ? 4 : bytesLeft); - text.append (" " + line); - if (jumps.size () > 0) - { - if (jmp < jumps.size ()) - text.append (" " + jumps.get (jmp++)); - if (jmp < jumps.size ()) - text.append (" " + jumps.get (jmp++)); - } - text.append ("\n"); - bytesLeft -= 4; - p += 4; - } - } - return text.toString (); - } + @Override + public String toString () + { + String hex = getHex (buffer, ptr, length > 4 ? 4 : length); + StringBuilder text = new StringBuilder (); + text.append (String.format ("%2s%05X: %-11s %-6s %-8s %s%n", + jumpTarget ? "->" : "", ptr, hex, mnemonic, extras, + description)); + if (length > 4) + { + int bytesLeft = length - 4; + int jmp = 0; + int p = ptr + 4; + while (bytesLeft > 0) + { + String line = getHex (buffer, p, (bytesLeft > 4) ? 4 : bytesLeft); + text.append (" " + line); + if (jumps.size () > 0) + { + if (jmp < jumps.size ()) + text.append (" " + jumps.get (jmp++)); + if (jmp < jumps.size ()) + text.append (" " + jumps.get (jmp++)); + } + text.append ("\n"); + bytesLeft -= 4; + p += 4; + } + } + return text.toString (); + } - private String getHex (byte[] buffer, int offset, int length) - { - if ((offset + length) >= buffer.length) - { - System.out.println ("too many"); - return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; - } - StringBuilder text = new StringBuilder (); - for (int i = 0; i < length; i++) - text.append (String.format ("%02X ", buffer[offset + i])); - if (text.length () > 0) - text.deleteCharAt (text.length () - 1); - return text.toString (); - } + private String getHex (byte[] buffer, int offset, int length) + { + if ((offset + length) >= buffer.length) + { + System.out.println ("too many"); + return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + } + StringBuilder text = new StringBuilder (); + for (int i = 0; i < length; i++) + text.append (String.format ("%02X ", buffer[offset + i])); + if (text.length () > 0) + text.deleteCharAt (text.length () - 1); + return text.toString (); + } - class Jump - { - int addressFrom; - int addressTo; - boolean caseJump; - int caseValue; + class Jump + { + int addressFrom; + int addressTo; + boolean caseJump; + int caseValue; - public Jump (int addressFrom, int addressTo) - { - this.addressFrom = addressFrom; - this.addressTo = addressTo; - } + public Jump (int addressFrom, int addressTo) + { + this.addressFrom = addressFrom; + this.addressTo = addressTo; + } - public Jump (int addressFrom, int addressTo, int value) - { - this (addressFrom, addressTo); - this.caseValue = value; - this.caseJump = true; - } + public Jump (int addressFrom, int addressTo, int value) + { + this (addressFrom, addressTo); + this.caseValue = value; + this.caseJump = true; + } - public String toString () - { - if (caseJump) - return String.format ("%3d: %04X", caseValue, addressTo); - return String.format ("%04X", addressTo); - } - } + @Override + public String toString () + { + if (caseJump) + return String.format ("%3d: %04X", caseValue, addressTo); + return String.format ("%04X", addressTo); + } + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/applefile/PascalConstants.java b/src/com/bytezone/diskbrowser/applefile/PascalConstants.java index 02433b6..241bb7f 100755 --- a/src/com/bytezone/diskbrowser/applefile/PascalConstants.java +++ b/src/com/bytezone/diskbrowser/applefile/PascalConstants.java @@ -2,117 +2,91 @@ package com.bytezone.diskbrowser.applefile; public interface PascalConstants { - static String[] mnemonics = - { "ABI", "ABR", "ADI", "ADR", "LAND", "DIF", "DVI", "DVR", "CHK", "FLO", "FLT", - "INN", "INT", "LOR", "MODI", "MPI", "MPR", "NGI", "NGR", "LNOT", "SRS", "SBI", - "SBR", "SGS", "SQI", "SQR", "STO", "IXS", "UNI", "LDE", "CSP", "LDCN", "ADJ", - "FJP", "INC", "IND", "IXA", "LAO", "LSA", "LAE", "MOV", "LDO", "SAS", "SRO", "XJP", - "RNP", "CIP", "EQU", "GEQ", "GRT", "LDA", "LDC", "LEQ", "LES", "LOD", "NEQ", "STR", - "UJP", "LDP", "STP", "LDM", "STM", "LDB", "STB", "IXP", "RBP", "CBP", "EQUI", - "GEQI", "GRTI", "LLA", "LDCI", "LEQI", "LESI", "LDL", "NEQI", "STL", "CXP", "CLP", - "CGP", "LPA", "STE", "???", "EFJ", "NFJ", "BPT", "XIT", "NOP" }; + static String[] mnemonics = + { "ABI", "ABR", "ADI", "ADR", "LAND", "DIF", "DVI", "DVR", "CHK", "FLO", "FLT", + "INN", "INT", "LOR", "MODI", "MPI", "MPR", "NGI", "NGR", "LNOT", "SRS", "SBI", + "SBR", "SGS", "SQI", "SQR", "STO", "IXS", "UNI", "LDE", "CSP", "LDCN", "ADJ", + "FJP", "INC", "IND", "IXA", "LAO", "LSA", "LAE", "MOV", "LDO", "SAS", "SRO", + "XJP", "RNP", "CIP", "EQU", "GEQ", "GRT", "LDA", "LDC", "LEQ", "LES", "LOD", + "NEQ", "STR", "UJP", "LDP", "STP", "LDM", "STM", "LDB", "STB", "IXP", "RBP", + "CBP", "EQUI", "GEQI", "GRTI", "LLA", "LDCI", "LEQI", "LESI", "LDL", "NEQI", + "STL", "CXP", "CLP", "CGP", "LPA", "STE", "???", "EFJ", "NFJ", "BPT", "XIT", + "NOP" }; - static int[] mnemonicSize = - // - // 128 - 155 - // 156 - 183 - // 184 - 211 - // 212 - 239 - // 240 - 255 + static int[] mnemonicSize = + // + // 128 - 155 + // 156 - 183 + // 184 - 211 + // 212 - 239 + // 240 - 255 - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 3, 2, 1, 2, 2, 2, 2, 2, 2, 0, 3, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 3, 0, 2, 2, 3, 2, - 3, 2, 1, 1, 2, 2, 1, 1, 3, 2, 2, 1, 1, 1, 2, 3, 1, 1, 2, 1, 2, 3, 2, 2, 0, 3, 1, 2, - 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 2, 1, 2, 2, 2, 2, 2, 2, 0, 3, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 3, 0, 2, 2, + 3, 2, 3, 2, 1, 1, 2, 2, 1, 1, 3, 2, 2, 1, 1, 1, 2, 3, 1, 1, 2, 1, 2, 3, 2, 2, 0, + 3, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - static String[] descriptions = - { - "Absolute value of integer - push ABS(ToS)", - "Absolute value of real - push abs((real)ToS)", - "Add integers (tos + tos-1)", - "Add reals - push ToS + ToS-1", - "Logical AND", - "Set difference - push difference of sets ToS-1 and ToS", - "Divide integers - push ToS-1 / ToS", - "Divide reals - push ToS-1 / ToS", - "Check subrange bounds - assert ToS-1 <= ToS-2 <= ToS, pop ToS, pop ToS-1", - "Float next-to-ToS - push integer ToS-1 after converting to a real", - "Float ToS - push integer ToS after converting to a float", - "Set Membership - if int ToS-1 is in set ToS, push true, else push false", - "Set Intersection - push TOS AND TOS-1", - "Logical OR", - "Modulo integers - push ToS-1 % ToS", - "Multiply TOS by TOS-1", - "Multiply reals - push ToS-1 * ToS", - "Negate Integer - push two's complement of ToS", - "Negate real - push -((real)ToS)", - "Logical Not - push one's complement of ToS", - "Build a subrange set", - "Subtract Integers push ToS-1 - ToS", - "Subtract reals - push ToS-1 - ToS", - "Build a singleton set", - "Square integer - push ToS ^ 2", - "Square real - push ToS ^ 2", - "Store indirect word - store ToS into word pointed to by ToS-1", - "Index string array - push &(*ToS-1 + ToS)", - "Set union - push union of sets ToS OR ToS-1", - "Load extended word - push word at segment :1+:2", - "Call Standard Procedure #:1 - ", - "Load Constant NIL", - "Adjust set", - "Jump if ToS false", - "Increment field ptr - push ToS+:1", - "Static index and load word", - "Compute word pointer from ToS-1 + ToS * :1 words", - "Load Global - push (BASE+:1)", - "Load constant string address", - "Load extended address - push address of word at segment :1+:2", - "Move words - transfer :1 words from *ToS to *ToS-1", - "Load Global Word - push BASE+:1", - "String Assign", - "Store TOS into BASE+:1", - "Case Jump - :1::2, Error: :3", - "Return from non-base procedure (pass :1 words)", - "Call intermediate procedure #:1", - "ToS-1 == ToS", - "ToS-1 >= ToS", - "ToS-1 > ToS", - "Load Intermediate Address - push :1th activation record +:2 bytes", - "Load multi-word constant - :1 words", - "ToS-1 <= ToS", - "ToS-1 < ToS", - "Load Intermediate Word - push :1th activation record +:2 bytes", - "ToS-1 <> ToS", - "Store intermediate word - store TOS into :2, traverse :1", - "Unconditional jump", - "Load Packed Field - push *ToS", - "Store into packed field", - "Load multiple words - push block of unsigned bytes at *ToS", - "Store multiple words - store block of UB at ToS to *ToS-1", - "Load Byte - index the byte pointer ToS-1 by integer index ToS and push that byte", - "Store Byte - index the byte pointer ToS-2 by integer index ToS-1 and move ToS to that location", - "Index packed array - do complicated stuff with :1 and :2", - "Return from base procedure (pass :1 words)", - "Call Base Procedure :1 at lex level -1 or 0", "Compare Integer : ToS-1 = ToS", - "Compare Integer : TOS-1 >= TOS", "Compare Integer : TOS-1 > ToS", - "Load Local Address - push MP+:1", "Load Word - push #:1", - "Compare Integer : TOS-1 <= TOS", "Compare Integer : TOS-1 < ToS", - "Load Local Word - push MP+:1", "Compare Integer : TOS-1 <> TOS", - "Store Local Word - store ToS into MP+:1", - "Call external procedure #:2 in segment #:1", "Call local procedure #:1", - "Call global procedure #:1", "Load a packed array - use :1 and :2", - "Store extended word - store ToS into word at segment :1+:2", "210 ", - "Equal false jump - jump :1 if ToS-1 <> ToS", - "Not equal false jump - jump :1 if ToS-1 == ToS", - "Breakpoint - not used (does NOP)", "Exit OS - cold boot", "No-op" }; + static String[] descriptions = + { "Absolute value of integer - push ABS(ToS)", + "Absolute value of real - push abs((real)ToS)", "Add integers (tos + tos-1)", + "Add reals - push ToS + ToS-1", "Logical AND", + "Set difference - push difference of sets ToS-1 and ToS", + "Divide integers - push ToS-1 / ToS", "Divide reals - push ToS-1 / ToS", + "Check subrange bounds - assert ToS-1 <= ToS-2 <= ToS, pop ToS, pop ToS-1", + "Float next-to-ToS - push integer ToS-1 after converting to a real", + "Float ToS - push integer ToS after converting to a float", + "Set Membership - if int ToS-1 is in set ToS, push true, else push false", + "Set Intersection - push TOS AND TOS-1", "Logical OR", + "Modulo integers - push ToS-1 % ToS", "Multiply TOS by TOS-1", + "Multiply reals - push ToS-1 * ToS", + "Negate Integer - push two's complement of ToS", + "Negate real - push -((real)ToS)", "Logical Not - push one's complement of ToS", + "Build a subrange set", "Subtract Integers push ToS-1 - ToS", + "Subtract reals - push ToS-1 - ToS", "Build a singleton set", + "Square integer - push ToS ^ 2", "Square real - push ToS ^ 2", + "Store indirect word - store ToS into word pointed to by ToS-1", + "Index string array - push &(*ToS-1 + ToS)", + "Set union - push union of sets ToS OR ToS-1", + "Load extended word - push word at segment :1+:2", + "Call Standard Procedure #:1 - ", "Load Constant NIL", "Adjust set", + "Jump if ToS false", "Increment field ptr - push ToS+:1", + "Static index and load word", "Compute word pointer from ToS-1 + ToS * :1 words", + "Load Global - push (BASE+:1)", "Load constant string address", + "Load extended address - push address of word at segment :1+:2", + "Move words - transfer :1 words from *ToS to *ToS-1", + "Load Global Word - push BASE+:1", "String Assign", "Store TOS into BASE+:1", + "Case Jump - :1::2, Error: :3", "Return from non-base procedure (pass :1 words)", + "Call intermediate procedure #:1", "ToS-1 == ToS", "ToS-1 >= ToS", "ToS-1 > ToS", + "Load Intermediate Address - push :1th activation record +:2 bytes", + "Load multi-word constant - :1 words", "ToS-1 <= ToS", "ToS-1 < ToS", + "Load Intermediate Word - push :1th activation record +:2 bytes", "ToS-1 <> ToS", + "Store intermediate word - store TOS into :2, traverse :1", "Unconditional jump", + "Load Packed Field - push *ToS", "Store into packed field", + "Load multiple words - push block of unsigned bytes at *ToS", + "Store multiple words - store block of UB at ToS to *ToS-1", + "Load Byte - index the byte pointer ToS-1 by integer index ToS and push that byte", + "Store Byte - index the byte pointer ToS-2 by integer index ToS-1 and move ToS to that location", + "Index packed array - do complicated stuff with :1 and :2", + "Return from base procedure (pass :1 words)", + "Call Base Procedure :1 at lex level -1 or 0", "Compare Integer : ToS-1 = ToS", + "Compare Integer : TOS-1 >= TOS", "Compare Integer : TOS-1 > ToS", + "Load Local Address - push MP+:1", "Load Word - push #:1", + "Compare Integer : TOS-1 <= TOS", "Compare Integer : TOS-1 < ToS", + "Load Local Word - push MP+:1", "Compare Integer : TOS-1 <> TOS", + "Store Local Word - store ToS into MP+:1", + "Call external procedure #:2 in segment #:1", "Call local procedure #:1", + "Call global procedure #:1", "Load a packed array - use :1 and :2", + "Store extended word - store ToS into word at segment :1+:2", "210 ", + "Equal false jump - jump :1 if ToS-1 <> ToS", + "Not equal false jump - jump :1 if ToS-1 == ToS", + "Breakpoint - not used (does NOP)", "Exit OS - cold boot", "No-op" }; - static String[] CSP = - { "000", "NEW", "MVL", "MVR", "EXIT", "", "", "IDS", "TRS", "TIM", "FLC", "SCN", "", - "", "", "", "", "", "", "", "", "021", "TNC", "RND", "", "", "", "", "", "", "", - "MRK", "RLS", "33", "34", "POT", "36", "37", "38", "39", "40" }; + static String[] CSP = + { "000", "NEW", "MVL", "MVR", "EXIT", "", "", "IDS", "TRS", "TIM", "FLC", "SCN", "", + "", "", "", "", "", "", "", "", "021", "TNC", "RND", "", "", "", "", "", "", "", + "MRK", "RLS", "33", "34", "POT", "36", "37", "38", "39", "40" }; - static String[] SegmentKind = - { "Linked", "HostSeg", "SegProc", "UnitSeg", "SeprtSeg", "UnlinkedIntrins", - "LinkedIntrins", "DataSeg" }; + static String[] SegmentKind = { "Linked", "HostSeg", "SegProc", "UnitSeg", "SeprtSeg", + "UnlinkedIntrins", "LinkedIntrins", "DataSeg" }; } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/applefile/PascalProcedure.java b/src/com/bytezone/diskbrowser/applefile/PascalProcedure.java index de3e74f..bac1641 100755 --- a/src/com/bytezone/diskbrowser/applefile/PascalProcedure.java +++ b/src/com/bytezone/diskbrowser/applefile/PascalProcedure.java @@ -8,168 +8,183 @@ import com.bytezone.diskbrowser.utilities.HexFormatter; public class PascalProcedure { - // all procedures have these fields - byte[] buffer; - int procOffset; - int offset; - int slot; - boolean valid; + // all procedures have these fields + byte[] buffer; + int procOffset; + int offset; + int slot; + boolean valid; - // only valid procedures have these fields - int procedureNo; - int procLevel; - int codeStart; - int codeEnd; - int parmSize; - int dataSize; - List statements = new ArrayList (); - AssemblerProgram assembler; - int jumpTable = -8; + // only valid procedures have these fields + int procedureNo; + int procLevel; + int codeStart; + int codeEnd; + int parmSize; + int dataSize; + List statements = new ArrayList (); + AssemblerProgram assembler; + int jumpTable = -8; - public PascalProcedure (byte[] buffer, int slot) - { - this.buffer = buffer; - this.slot = slot; - int p = buffer.length - 2 - slot * 2; - offset = HexFormatter.intValue (buffer[p], buffer[p + 1]); - procOffset = p - offset; - valid = procOffset > 0; + public PascalProcedure (byte[] buffer, int slot) + { + this.buffer = buffer; + this.slot = slot; + int p = buffer.length - 2 - slot * 2; + offset = HexFormatter.intValue (buffer[p], buffer[p + 1]); + procOffset = p - offset; + valid = procOffset > 0; - if (valid) - { - procedureNo = buffer[procOffset] & 0xFF; - procLevel = buffer[procOffset + 1]; - codeStart = HexFormatter.intValue (buffer[procOffset - 2], buffer[procOffset - 1]); - codeEnd = HexFormatter.intValue (buffer[procOffset - 4], buffer[procOffset - 3]); - parmSize = HexFormatter.intValue (buffer[procOffset - 6], buffer[procOffset - 5]); - dataSize = HexFormatter.intValue (buffer[procOffset - 8], buffer[procOffset - 7]); - } - } + if (valid) + { + procedureNo = buffer[procOffset] & 0xFF; + procLevel = buffer[procOffset + 1]; + codeStart = HexFormatter.intValue (buffer[procOffset - 2], buffer[procOffset - 1]); + codeEnd = HexFormatter.intValue (buffer[procOffset - 4], buffer[procOffset - 3]); + parmSize = HexFormatter.intValue (buffer[procOffset - 6], buffer[procOffset - 5]); + dataSize = HexFormatter.intValue (buffer[procOffset - 8], buffer[procOffset - 7]); + } + } - private void decode () - { - if (statements.size () > 0 || assembler != null) - return; - int ptr = procOffset - codeStart - 2; - int max = procOffset + jumpTable; + private void decode () + { + if (statements.size () > 0 || assembler != null) + return; + int ptr = procOffset - codeStart - 2; + int max = procOffset + jumpTable; - if (codeEnd == 0) - { - int len = codeStart + jumpTable + 2; - if (len > 0) - { - byte[] asmBuf = new byte[len]; - System.arraycopy (buffer, ptr, asmBuf, 0, len); - assembler = new AssemblerProgram ("Proc", asmBuf, ptr); - } - return; - } + if (codeEnd == 0) + { + int len = codeStart + jumpTable + 2; + if (len > 0) + { + byte[] asmBuf = new byte[len]; + System.arraycopy (buffer, ptr, asmBuf, 0, len); + assembler = new AssemblerProgram ("Proc", asmBuf, ptr); + } + return; + } - while (ptr < max) - { - PascalCodeStatement cs = new PascalCodeStatement (buffer, ptr, procOffset); - if (cs.length <= 0) - { - System.out.println ("error - length <= 0 : " + cs); - break; - } - statements.add (cs); - if (cs.val == 185 || cs.val == 161) - if (cs.p1 < jumpTable) - { - jumpTable = cs.p1; - max = procOffset + jumpTable; - } - ptr += cs.length; - } + while (ptr < max) + { + System.out.printf ("ptr:%d, max:%d, buf:%d %n", ptr, max, buffer.length); + if (ptr >= buffer.length || ptr < 0) + { + System.out.println ("Ptr outside buffer"); + break; + } + PascalCodeStatement cs = new PascalCodeStatement (buffer, ptr, procOffset); + if (cs.length <= 0) + { + System.out.println ("error - length <= 0 : " + cs); + break; + } + statements.add (cs); + if (cs.val == 185 || cs.val == 161) + if (cs.p1 < jumpTable) + { + jumpTable = cs.p1; + max = procOffset + jumpTable; + } + ptr += cs.length; + } - // Tidy up left-over bytes at the end - if (statements.size () > 1) - { - PascalCodeStatement lastStatement = statements.get (statements.size () - 1); - PascalCodeStatement secondLastStatement = statements.get (statements.size () - 2); - if (lastStatement.val == 0 - && (secondLastStatement.val == 0xD6 || secondLastStatement.val == 0xC1 || secondLastStatement.val == 0xAD)) - statements.remove (statements.size () - 1); - } + // Tidy up left-over bytes at the end + if (statements.size () > 1) + { + PascalCodeStatement lastStatement = statements.get (statements.size () - 1); + PascalCodeStatement secondLastStatement = statements.get (statements.size () - 2); + if (lastStatement.val == 0 && (secondLastStatement.val == 0xD6 + || secondLastStatement.val == 0xC1 || secondLastStatement.val == 0xAD)) + statements.remove (statements.size () - 1); + } - // Mark statements that are jump targets - int actualEnd = procOffset - codeEnd - 4; - for (PascalCodeStatement cs : statements) - { - if (cs.ptr == actualEnd) - { - cs.jumpTarget = true; - continue; - } - for (Jump cj : cs.jumps) - for (PascalCodeStatement cs2 : statements) - if (cs2.ptr == cj.addressTo) - { - cs2.jumpTarget = true; - break; - } - } - } + // Mark statements that are jump targets + int actualEnd = procOffset - codeEnd - 4; + for (PascalCodeStatement cs : statements) + { + if (cs.ptr == actualEnd) + { + cs.jumpTarget = true; + continue; + } + for (Jump cj : cs.jumps) + for (PascalCodeStatement cs2 : statements) + if (cs2.ptr == cj.addressTo) + { + cs2.jumpTarget = true; + break; + } + } + } - public List extractStrings () - { - decode (); - List strings = new ArrayList (); - for (PascalCodeStatement cs : statements) - if (cs.val == 166) - strings.add (cs); - return strings; - } + public List extractStrings () + { + decode (); + List strings = new ArrayList (); + for (PascalCodeStatement cs : statements) + if (cs.val == 166) + strings.add (cs); + return strings; + } - public String toString () - { - if (!valid) - return ""; - decode (); + @Override + public String toString () + { + if (!valid) + return ""; + decode (); - StringBuilder text = new StringBuilder ("\nProcedure Header\n================\n\n"); + StringBuilder text = new StringBuilder ("\nProcedure Header\n================\n\n"); - if (false) - text.append (HexFormatter.format (buffer, procOffset + jumpTable, 2 - jumpTable) + "\n\n"); + if (false) + text.append (HexFormatter.format (buffer, procOffset + jumpTable, 2 - jumpTable) + + "\n\n"); - text.append (String.format ("Level.......%5d %02X%n", procLevel, procLevel & 0xFF)); - text.append (String.format ("Proc no.....%5d %02X%n", procedureNo, procedureNo)); - text.append (String.format ("Code entry..%5d %04X (%04X - %04X = %04X)%n", codeStart, - codeStart, (procOffset - 2), codeStart, (procOffset - codeStart - 2))); - text.append (String.format ("Code exit...%5d %04X", codeEnd, codeEnd)); - if (codeEnd > 0) - text.append (String.format (" (%04X - %04X = %04X)%n", (procOffset - 4), codeEnd, - (procOffset - codeEnd - 4))); - else - text.append (String.format ("%n")); - text.append (String.format ("Parm size...%5d %04X%n", parmSize, parmSize)); - text.append (String.format ("Data size...%5d %04X%n%n", dataSize, dataSize)); + text.append (String.format ("Level.......%5d %02X%n", procLevel, + procLevel & 0xFF)); + text.append (String.format ("Proc no.....%5d %02X%n", procedureNo, procedureNo)); + text.append (String.format ("Code entry..%5d %04X (%04X - %04X = %04X)%n", + codeStart, codeStart, (procOffset - 2), codeStart, + (procOffset - codeStart - 2))); + text.append (String.format ("Code exit...%5d %04X", codeEnd, codeEnd)); + if (codeEnd > 0) + text.append (String.format (" (%04X - %04X = %04X)%n", (procOffset - 4), codeEnd, + (procOffset - codeEnd - 4))); + else + text.append (String.format ("%n")); + text.append (String.format ("Parm size...%5d %04X%n", parmSize, parmSize)); + text.append (String.format ("Data size...%5d %04X%n%n", dataSize, dataSize)); - text.append ("Procedure Code\n==============\n\n"); + text.append ("Procedure Code\n==============\n\n"); - int ptr = procOffset - codeStart - 2; - if (false) - text.append (HexFormatter.format (buffer, ptr, codeStart + jumpTable + 2) + "\n\n"); + int ptr = procOffset - codeStart - 2; + if (false) + text.append (HexFormatter.format (buffer, ptr, codeStart + jumpTable + 2) + "\n\n"); - if (codeEnd == 0) - text.append (assembler.getAssembler () + "\n"); - else - { - for (PascalCodeStatement cs : statements) - text.append (cs); + if (codeEnd == 0) + { + if (assembler != null) + text.append (assembler.getAssembler () + "\n"); + else + text.append ("Null assembler in PascalProcedure"); + } + else + { + for (PascalCodeStatement cs : statements) + text.append (cs); - if (jumpTable < -8 && false) - { - text.append ("\nJump table:\n"); - for (int i = procOffset + jumpTable; i < procOffset - 8; i += 2) - { - ptr = i - ((buffer[i + 1] & 0xFF) * 256 + (buffer[i] & 0xFF)); - text.append (String.format ("%05X : %02X %02X --> %04X%n", i, buffer[i], buffer[i + 1], - ptr)); - } - } - } - return text.toString (); - } + if (jumpTable < -8 && false) + { + text.append ("\nJump table:\n"); + for (int i = procOffset + jumpTable; i < procOffset - 8; i += 2) + { + ptr = i - ((buffer[i + 1] & 0xFF) * 256 + (buffer[i] & 0xFF)); + text.append (String.format ("%05X : %02X %02X --> %04X%n", i, buffer[i], + buffer[i + 1], ptr)); + } + } + } + return text.toString (); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/applefile/PascalSegment.java b/src/com/bytezone/diskbrowser/applefile/PascalSegment.java index 90ce86c..8331db2 100755 --- a/src/com/bytezone/diskbrowser/applefile/PascalSegment.java +++ b/src/com/bytezone/diskbrowser/applefile/PascalSegment.java @@ -33,19 +33,22 @@ public class PascalSegment extends AbstractFile implements PascalConstants this.size = HexFormatter.intValue (fullBuffer[seq * 4 + 2], fullBuffer[seq * 4 + 3]); this.segmentNoHeader = fullBuffer[0x100 + seq * 2]; - segKind = - HexFormatter.intValue (fullBuffer[0xC0 + seq * 2], fullBuffer[0xC0 + seq * 2 + 1]); - textAddress = - HexFormatter.intValue (fullBuffer[0xE0 + seq * 2], fullBuffer[0xE0 + seq * 2 + 1]); + segKind = HexFormatter.intValue (fullBuffer[0xC0 + seq * 2], + fullBuffer[0xC0 + seq * 2 + 1]); + textAddress = HexFormatter.intValue (fullBuffer[0xE0 + seq * 2], + fullBuffer[0xE0 + seq * 2 + 1]); int flags = fullBuffer[0x101 + seq * 2] & 0xFF; machineType = flags & 0x0F; version = (flags & 0xD0) >> 5; - intrinsSegs1 = - HexFormatter.intValue (fullBuffer[0x120 + seq * 4], fullBuffer[0x120 + seq * 4 + 1]); + intrinsSegs1 = HexFormatter.intValue (fullBuffer[0x120 + seq * 4], + fullBuffer[0x120 + seq * 4 + 1]); intrinsSegs2 = HexFormatter.intValue (fullBuffer[0x120 + seq * 4 + 2], fullBuffer[0x120 + seq * 4 + 3]); int offset = blockNo * 512; + // System.out.printf ("Seq:%d, block:%d, size:%d, seg:%d, kind:%d, address:%d %n", seq, + // blockNo, size, segmentNoHeader, segKind, textAddress); + // System.out.println (HexFormatter.format (fullBuffer)); if (offset < fullBuffer.length) { buffer = new byte[size]; // replaces this.buffer with the segment buffer only @@ -57,11 +60,12 @@ public class PascalSegment extends AbstractFile implements PascalConstants System.out.printf ("Zero segment header in %s seq %d%n", name, seq); else if (segmentNoBody != segmentNoHeader) System.out.println ("Segment number mismatch : " + segmentNoBody + " / " - + segmentNoHeader); + + segmentNoHeader); } else { - System.out.println ("Error in blocksize for pascal disk"); + System.out.printf ("Error in blocksize %,d > %,d for pascal disk%n", offset, + fullBuffer.length); throw new FileFormatException ("Error in PascalSegment"); } } @@ -76,10 +80,10 @@ public class PascalSegment extends AbstractFile implements PascalConstants public String toText () { - return String.format ( - " %2d %02X %04X %,6d %-8s %-15s %3d %3d %d %d %d %d", - slot, blockNo, size, size, name, SegmentKind[segKind], textAddress, - segmentNoHeader, machineType, version, intrinsSegs1, intrinsSegs2); + return String + .format (" %2d %02X %04X %,6d %-8s %-15s %3d %3d %d %d %d %d", + slot, blockNo, size, size, name, SegmentKind[segKind], textAddress, + segmentNoHeader, machineType, version, intrinsSegs1, intrinsSegs2); } @Override @@ -91,9 +95,9 @@ public class PascalSegment extends AbstractFile implements PascalConstants StringBuilder text = new StringBuilder (); String title = "Segment - " + name; text.append (title + "\n" - + "===============================".substring (0, title.length ()) + "\n\n"); + + "===============================".substring (0, title.length ()) + "\n\n"); String warning = - segmentNoBody == segmentNoHeader ? "" : " (" + segmentNoHeader + " in header)"; + segmentNoBody == segmentNoHeader ? "" : " (" + segmentNoHeader + " in header)"; text.append (String.format ("Address........ %02X%n", blockNo)); text.append (String.format ("Length......... %04X%n", buffer.length)); text.append (String.format ("Machine type... %d%n", machineType)); @@ -116,11 +120,12 @@ public class PascalSegment extends AbstractFile implements PascalConstants int address = size - procedure.slot * 2 - 2; text.append (String.format ( " %2d %04X %3d %04X %04X %04X " - + "%04X (%04X - %04X = %04X)%n", + + "%04X (%04X - %04X = %04X)%n", procedure.procedureNo, procedure.offset, procedure.procLevel, procedure.codeStart, - procedure.codeEnd, procedure.parmSize, procedure.dataSize, - address, procedure.offset, procedure.procOffset)); + procedure.codeEnd, procedure.parmSize, + procedure.dataSize, address, procedure.offset, + procedure.procOffset)); } else text.append (String.format (" %2d %04X%n", procedure.slot, procedure.offset)); @@ -131,7 +136,8 @@ public class PascalSegment extends AbstractFile implements PascalConstants { List strings = pp.extractStrings (); for (PascalCodeStatement cs : strings) - text.append (String.format (" %2d %04X %s%n", pp.procedureNo, cs.ptr, cs.text)); + text.append (String.format (" %2d %04X %s%n", pp.procedureNo, cs.ptr, + cs.text)); } for (PascalProcedure procedure : procedures) diff --git a/src/com/bytezone/diskbrowser/applefile/Relocator.java b/src/com/bytezone/diskbrowser/applefile/Relocator.java new file mode 100644 index 0000000..3362eb0 --- /dev/null +++ b/src/com/bytezone/diskbrowser/applefile/Relocator.java @@ -0,0 +1,107 @@ +package com.bytezone.diskbrowser.applefile; + +import java.util.ArrayList; +import java.util.List; + +import com.bytezone.diskbrowser.utilities.HexFormatter; + +public class Relocator extends AbstractFile +{ + private final int checkByte; + private final List diskRecords = new ArrayList (); + + public Relocator (String name, byte[] buffer) + { + super (name, buffer); + + checkByte = HexFormatter.intValue (buffer[0], buffer[1]); + + int ptr = 2; // skip checkByte + + while (buffer[ptr] != 0) + { + DiskRecord diskRecord = new DiskRecord (buffer, ptr); + diskRecords.add (diskRecord); + ptr += diskRecord.size (); + } + } + + @Override + public String getText () + { + StringBuilder text = new StringBuilder (); + + text.append ("Pascal Relocator\n\n"); + text.append (String.format ("Check byte..... %04X%n%n", checkByte)); + + for (DiskRecord diskRecord : diskRecords) + { + text.append (diskRecord); + text.append ("\n"); + } + + return text.toString (); + } + + private class DiskRecord + { + int diskNumber; + int diskSegments; + List segments = new ArrayList (); + + public DiskRecord (byte[] buffer, int ptr) + { + diskNumber = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]); + diskSegments = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 4]); + + ptr += 4; + for (int i = 0; i < diskSegments; i++) + { + segments.add (new Segment (buffer, ptr)); + ptr += 6; + } + } + + int size () + { + return 4 + segments.size () * 6; + } + + @Override + public String toString () + { + StringBuilder text = new StringBuilder (); + + text.append (String.format ("Disk number.... %04X%n", diskNumber)); + text.append (String.format ("Segments....... %04X%n%n", diskSegments)); + text.append ("Segment Logical Physical Length\n"); + + int count = 1; + for (Segment segment : segments) + text.append (String.format (" %02X %s %n", count++, segment)); + + return text.toString (); + } + } + + private class Segment + { + int logicalBlock; + int physicalBlock; + int segmentLength; + + public Segment (byte[] buffer, int ptr) + { + logicalBlock = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]); + physicalBlock = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]); + segmentLength = HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]); + } + + @Override + public String toString () + { + return String.format (" %04X %04X %04X", logicalBlock, physicalBlock, + segmentLength); + } + } +} \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/disk/AppleDisk.java b/src/com/bytezone/diskbrowser/disk/AppleDisk.java index 2e39f63..056233b 100755 --- a/src/com/bytezone/diskbrowser/disk/AppleDisk.java +++ b/src/com/bytezone/diskbrowser/disk/AppleDisk.java @@ -384,6 +384,7 @@ public class AppleDisk implements Disk if (!isValidAddress (block)) { System.out.println ("Invalid block : " + block); + // assert false; return null; // return new AppleDiskAddress (this, 0); this was looping 26/07/2016 } diff --git a/src/com/bytezone/diskbrowser/disk/DiskFactory.java b/src/com/bytezone/diskbrowser/disk/DiskFactory.java index a7fe6b0..5daeac7 100755 --- a/src/com/bytezone/diskbrowser/disk/DiskFactory.java +++ b/src/com/bytezone/diskbrowser/disk/DiskFactory.java @@ -20,7 +20,7 @@ import com.bytezone.diskbrowser.wizardry.WizardryScenarioDisk; public class DiskFactory { - private static boolean debug = false; + private static boolean debug = true; private DiskFactory () { diff --git a/src/com/bytezone/diskbrowser/gui/DiskBrowser.java b/src/com/bytezone/diskbrowser/gui/DiskBrowser.java index 7a72c6f..0c230c3 100755 --- a/src/com/bytezone/diskbrowser/gui/DiskBrowser.java +++ b/src/com/bytezone/diskbrowser/gui/DiskBrowser.java @@ -15,7 +15,6 @@ import com.bytezone.common.State; public class DiskBrowser extends JFrame implements DiskSelectionListener, QuitListener { private static final String windowTitle = "Apple ][ Disk Browser"; - // private static final String PREFS_FULL_SCREEN = "full screen"; private final Preferences prefs = Preferences.userNodeForPackage (this.getClass ()); private WindowSaver windowSaver; @@ -127,9 +126,6 @@ public class DiskBrowser extends JFrame implements DiskSelectionListener, QuitLi pack (); - // prefs.addPreferenceChangeListener (catalogPanel); - // prefs.addPreferenceChangeListener (dataPanel); - // restore the menuHandler items before they are referenced quitAction.restore (); @@ -164,6 +160,7 @@ public class DiskBrowser extends JFrame implements DiskSelectionListener, QuitLi @Override public void quit (Preferences preferences) { + windowSaver = new WindowSaver (prefs, this, "DiskBrowser"); windowSaver.saveWindow (); } diff --git a/src/com/bytezone/diskbrowser/gui/WindowSaver.java b/src/com/bytezone/diskbrowser/gui/WindowSaver.java index 7b718a1..51aa26a 100644 --- a/src/com/bytezone/diskbrowser/gui/WindowSaver.java +++ b/src/com/bytezone/diskbrowser/gui/WindowSaver.java @@ -1,5 +1,6 @@ package com.bytezone.diskbrowser.gui; +import java.awt.Dimension; import java.util.prefs.Preferences; import javax.swing.JFrame; @@ -23,6 +24,8 @@ public class WindowSaver prefs.putInt (key + "Y", frame.getY ()); prefs.putInt (key + "Height", frame.getHeight ()); prefs.putInt (key + "Width", frame.getWidth ()); + System.out.printf ("Saving x:%d, y:%d, w:%d, h:%d%n", frame.getX (), frame.getY (), + frame.getWidth (), frame.getHeight ()); } public boolean restoreWindow () @@ -32,19 +35,24 @@ public class WindowSaver int height = prefs.getInt (key + "Height", -1); int width = prefs.getInt (key + "Width", -1); + Dimension screen = java.awt.Toolkit.getDefaultToolkit ().getScreenSize (); + if (width < 0) // nothing to restore { + frame.setLocation (100, 100); + frame.setSize (1000, 600); frame.setLocationRelativeTo (null); // centre - // frame.centerOnScreen (); + System.out.printf ("Creating x:%d, y:%d, w:%d, h:%d%n", x, y, width, height); return false; } - // frame.setX (x); - // frame.setY (y); - // frame.setHeight (height); - // frame.setWidth (width); - frame.setLocation (x, y); + System.out.printf ("w:%d, sw:%f%n", width, screen.getWidth ()); + if (width > screen.getWidth () - 15) + width = (int) (screen.getWidth () - 15); + frame.setSize (width, height); + frame.setLocation (x, y); + System.out.printf ("Restoring x:%d, y:%d, w:%d, h:%d%n", x, y, width, height); return true; } diff --git a/src/com/bytezone/diskbrowser/pascal/CatalogEntry.java b/src/com/bytezone/diskbrowser/pascal/CatalogEntry.java index 6fa80a5..32fe787 100644 --- a/src/com/bytezone/diskbrowser/pascal/CatalogEntry.java +++ b/src/com/bytezone/diskbrowser/pascal/CatalogEntry.java @@ -14,11 +14,12 @@ import com.bytezone.diskbrowser.utilities.HexFormatter; abstract class CatalogEntry implements AppleFileSource { protected final PascalDisk parent; - String name; + protected final String name; int firstBlock; int lastBlock; // block AFTER last used block int fileType; GregorianCalendar date; + int bytesUsedInLastBlock; List blocks = new ArrayList (); AbstractFile file; @@ -28,13 +29,21 @@ abstract class CatalogEntry implements AppleFileSource firstBlock = HexFormatter.intValue (buffer[0], buffer[1]); lastBlock = HexFormatter.intValue (buffer[2], buffer[3]); - // fileType = HexFormatter.intValue (buffer[4], buffer[5]); - fileType = buffer[4] & 0x0F; + fileType = HexFormatter.intValue (buffer[4], buffer[5]); + // fileType = buffer[4] & 0x0F; name = HexFormatter.getPascalString (buffer, 6); + bytesUsedInLastBlock = HexFormatter.intValue (buffer[16], buffer[17]); Disk disk = parent.getDisk (); for (int i = firstBlock; i < lastBlock; i++) + { + if (i >= 280) + { + System.out.printf ("CatalogEntry: block >= 280%n"); + break; + } blocks.add (disk.getDiskAddress (i)); + } } @Override diff --git a/src/com/bytezone/diskbrowser/pascal/FileEntry.java b/src/com/bytezone/diskbrowser/pascal/FileEntry.java index f931af2..9b80ed2 100644 --- a/src/com/bytezone/diskbrowser/pascal/FileEntry.java +++ b/src/com/bytezone/diskbrowser/pascal/FileEntry.java @@ -15,6 +15,10 @@ class FileEntry extends CatalogEntry date = HexFormatter.getPascalDate (buffer, 24); for (int i = firstBlock; i < lastBlock; i++) + { + if (i >= 280) + break; + switch (fileType) { case 2: @@ -46,6 +50,7 @@ class FileEntry extends CatalogEntry parent.sectorTypes[i] = parent.dataSector; break; } + } } @Override @@ -58,30 +63,32 @@ class FileEntry extends CatalogEntry switch (fileType) { - case 3: - file = new PascalText (name, buffer); - break; - case 2: file = new PascalCode (name, buffer); break; + case 3: + file = new PascalText (name, buffer); + break; + case 4: file = new PascalInfo (name, buffer); break; - case 0: // volume - break; - case 5: // data if (name.equals ("SYSTEM.CHARSET")) file = new Charset (name, buffer); - else if (name.equals ("WT")) // only testing - file = new WizardryTitle (name, buffer); + // else if (name.equals ("WT")) // only testing + // file = new WizardryTitle (name, buffer); + else if (name.equals ("SYSTEM.RELOC")) + file = new Relocator (name, buffer); else file = new DefaultAppleFile (name, buffer); break; + case 0: // volume + break; + default: // unknown file = new DefaultAppleFile (name, buffer); } diff --git a/src/com/bytezone/diskbrowser/pascal/PascalDisk.java b/src/com/bytezone/diskbrowser/pascal/PascalDisk.java index f6ee376..4815c6f 100755 --- a/src/com/bytezone/diskbrowser/pascal/PascalDisk.java +++ b/src/com/bytezone/diskbrowser/pascal/PascalDisk.java @@ -3,6 +3,7 @@ package com.bytezone.diskbrowser.pascal; import java.awt.Color; import java.text.DateFormat; import java.util.ArrayList; +import java.util.GregorianCalendar; import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; @@ -19,11 +20,11 @@ public class PascalDisk extends AbstractFormattedDisk { static final int CATALOG_ENTRY_SIZE = 26; private final DateFormat df = DateFormat.getDateInstance (DateFormat.SHORT); - private final VolumeEntry volume; + private final VolumeEntry volumeEntry; private final PascalCatalogSector diskCatalogSector; final String[] fileTypes = - { "Volume", "Xdsk", "Code", "Text", "Info", "Data", "Graf", "Foto", "SecureDir" }; + { "Volume", "Xdsk", "Code", "Text", "Info", "Data", "Graf", "Foto", "SecureDir" }; SectorType diskBootSector = new SectorType ("Boot", Color.lightGray); SectorType catalogSector = new SectorType ("Catalog", Color.magenta); @@ -56,7 +57,7 @@ public class PascalDisk extends AbstractFormattedDisk byte[] data = new byte[CATALOG_ENTRY_SIZE]; System.arraycopy (buffer, 0, data, 0, CATALOG_ENTRY_SIZE); - volume = new VolumeEntry (this, data); + volumeEntry = new VolumeEntry (this, data); for (int i = 0; i < 2; i++) if (!disk.isSectorEmpty (i)) @@ -69,7 +70,7 @@ public class PascalDisk extends AbstractFormattedDisk freeBlocks.set (i, true); List sectors = new ArrayList (); - for (int i = 2; i < volume.lastBlock; i++) + for (int i = 2; i < volumeEntry.lastBlock; i++) { DiskAddress da = disk.getDiskAddress (i); if (!disk.isSectorEmpty (da)) @@ -82,34 +83,34 @@ public class PascalDisk extends AbstractFormattedDisk diskCatalogSector = new PascalCatalogSector (disk, buffer, sectors); DefaultMutableTreeNode root = getCatalogTreeRoot (); - DefaultMutableTreeNode volumeNode = new DefaultMutableTreeNode (volume); + DefaultMutableTreeNode volumeNode = new DefaultMutableTreeNode (volumeEntry); root.add (volumeNode); // read the catalog List addresses = new ArrayList (); - for (int i = 2; i < volume.lastBlock; i++) + for (int i = 2; i < volumeEntry.lastBlock; i++) addresses.add (disk.getDiskAddress (i)); buffer = disk.readSectors (addresses); // loop through each catalog entry (what if there are deleted files?) - for (int i = 1; i <= volume.totalFiles; i++) + for (int i = 1; i <= volumeEntry.totalFiles; i++) { int ptr = i * CATALOG_ENTRY_SIZE; data = new byte[CATALOG_ENTRY_SIZE]; System.arraycopy (buffer, ptr, data, 0, CATALOG_ENTRY_SIZE); - FileEntry fe = new FileEntry (this, data); - fileEntries.add (fe); - DefaultMutableTreeNode node = new DefaultMutableTreeNode (fe); + FileEntry fileEntry = new FileEntry (this, data); + fileEntries.add (fileEntry); + DefaultMutableTreeNode node = new DefaultMutableTreeNode (fileEntry); - if (fe.fileType == 2) // PascalCode + if (fileEntry.fileType == 2) // PascalCode { node.setAllowsChildren (true); - PascalCode pc = (PascalCode) fe.getDataSource (); - for (PascalSegment ps : pc) + PascalCode pascalCode = (PascalCode) fileEntry.getDataSource (); + for (PascalSegment pascalSegment : pascalCode) { - DefaultMutableTreeNode segmentNode = - new DefaultMutableTreeNode (new PascalCodeObject (this, ps, fe.firstBlock)); + DefaultMutableTreeNode segmentNode = new DefaultMutableTreeNode ( + new PascalCodeObject (this, pascalSegment, fileEntry.firstBlock)); node.add (segmentNode); segmentNode.setAllowsChildren (false); } @@ -118,7 +119,7 @@ public class PascalDisk extends AbstractFormattedDisk node.setAllowsChildren (false); volumeNode.add (node); - for (int j = fe.firstBlock; j < fe.lastBlock; j++) + for (int j = fileEntry.firstBlock; j < fileEntry.lastBlock; j++) freeBlocks.set (j, false); } @@ -128,9 +129,10 @@ public class PascalDisk extends AbstractFormattedDisk public static boolean isCorrectFormat (AppleDisk disk, boolean debug) { - disk.setInterleave (1); + disk.setInterleave (1); // should only ever be Prodos if (checkFormat (disk, debug)) return true; + disk.setInterleave (0); if (checkFormat (disk, debug)) return true; @@ -141,8 +143,8 @@ public class PascalDisk extends AbstractFormattedDisk public static boolean checkFormat (AppleDisk disk, boolean debug) { byte[] buffer = disk.readSector (2); - if (debug) - System.out.println (HexFormatter.format (buffer)); + // if (debug) + // System.out.println (HexFormatter.format (buffer)); int nameLength = HexFormatter.intValue (buffer[6]); if (nameLength < 1 || nameLength > 7) { @@ -166,6 +168,14 @@ public class PascalDisk extends AbstractFormattedDisk return false; // will only work for floppies! } + int blocks = HexFormatter.intValue (buffer[14], buffer[15]); + if (blocks > 280) + { + if (debug) + System.out.printf ("Blocks > 280: %d%n", blocks); + // return false; + } + List addresses = new ArrayList (); for (int i = 2; i < to; i++) addresses.add (disk.getDiskAddress (i)); @@ -185,27 +195,21 @@ public class PascalDisk extends AbstractFormattedDisk for (int i = 1; i <= files; i++) { int ptr = i * 26; - int a = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]); - int b = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]); - int c = HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]); - if (b < a) + int firstBlock = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]); + int lastBlock = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]); + int kind = HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]); + if (lastBlock < firstBlock) return false; - if (c == 0) + if (kind == 0) return false; nameLength = HexFormatter.intValue (buffer[ptr + 6]); if (nameLength < 1 || nameLength > 15) return false; + int lastByte = HexFormatter.intValue (buffer[ptr + 22], buffer[ptr + 23]); + GregorianCalendar date = HexFormatter.getPascalDate (buffer, 24); if (debug) - System.out.printf ("%4d %4d %d %s%n", a, b, c, - new String (buffer, ptr + 7, nameLength)); - } - - int blocks = HexFormatter.intValue (buffer[14], buffer[15]); - if (blocks > 280) - { - if (debug) - System.out.printf ("Blocks > 280: %d%n", blocks); - return false; + System.out.printf ("%4d %4d %d %-15s %d %s%n", firstBlock, lastBlock, kind, + new String (buffer, ptr + 7, nameLength), lastByte, date); } return true; @@ -254,13 +258,16 @@ public class PascalDisk extends AbstractFormattedDisk { String newLine = String.format ("%n"); String newLine2 = newLine + newLine; - String line = "---- --------------- ---- -------- ------- ---- ----" + newLine; - String date = volume.date == null ? "--" : df.format (volume.date.getTime ()); + String line = + "---- --------------- ---- -------- ------- ---- ----" + newLine; + String date = + volumeEntry.date == null ? "--" : df.format (volumeEntry.date.getTime ()); StringBuilder text = new StringBuilder (); text.append ("Disk : " + disk.getFile ().getAbsolutePath () + newLine2); - text.append ("Volume : " + volume.name + newLine); + text.append ("Volume : " + volumeEntry.name + newLine); text.append ("Date : " + date + newLine2); - text.append ("Blks Name Type Date Length Frst Last" + newLine); + text.append ("Blks Name Type Date Length Frst Last" + + newLine); text.append (line); int usedBlocks = 6; @@ -271,14 +278,15 @@ public class PascalDisk extends AbstractFormattedDisk usedBlocks += size; date = ce.date == null ? "--" : df.format (ce.date.getTime ()); int bytes = (size - 1) * 512 + ce.bytesUsedInLastBlock; - text.append (String.format (" %3d %-15s %s %8s %,8d $%03X $%03X%n", size, - ce.name, fileTypes[ce.fileType], date, bytes, ce.firstBlock, - ce.lastBlock)); + text.append (String.format ("%4d %-15s %s %8s %,8d $%03X $%03X%n", size, + ce.name, fileTypes[ce.fileType], date, bytes, + ce.firstBlock, ce.lastBlock)); } text.append (line); - text.append (String.format ("Blocks free : %3d Blocks used : %3d Total blocks : %3d%n", - (volume.totalBlocks - usedBlocks), usedBlocks, - volume.totalBlocks)); - return new DefaultAppleFileSource (volume.name, text.toString (), this); + text.append (String.format ( + "Blocks free : %3d Blocks used : %3d Total blocks : %3d%n", + (volumeEntry.totalBlocks - usedBlocks), usedBlocks, + volumeEntry.totalBlocks)); + return new DefaultAppleFileSource (volumeEntry.name, text.toString (), this); } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/pascal/VolumeEntry.java b/src/com/bytezone/diskbrowser/pascal/VolumeEntry.java index e6d39da..28853da 100644 --- a/src/com/bytezone/diskbrowser/pascal/VolumeEntry.java +++ b/src/com/bytezone/diskbrowser/pascal/VolumeEntry.java @@ -8,15 +8,26 @@ class VolumeEntry extends CatalogEntry { final int totalFiles; final int totalBlocks; + final int block1; // first block on the disk (usually 0) + final int lastDirectoryBlock; // (plus 1) (usually 6) + final int recordType; // 0 = directory + final int nameLength; + final String name; public VolumeEntry (PascalDisk parent, byte[] buffer) { super (parent, buffer); - totalBlocks = HexFormatter.intValue (buffer[14], buffer[15]); + block1 = HexFormatter.intValue (buffer[0], buffer[1]); // 0 + lastDirectoryBlock = HexFormatter.intValue (buffer[2], buffer[3]); // 6 + recordType = HexFormatter.intValue (buffer[4], buffer[5]); // 0 + nameLength = buffer[6] & 0xFF; + name = HexFormatter.getPascalString (buffer, 6); // 06-0D + totalBlocks = HexFormatter.intValue (buffer[14], buffer[15]); // 280 totalFiles = HexFormatter.intValue (buffer[16], buffer[17]); - firstBlock = HexFormatter.intValue (buffer[18], buffer[19]); - date = HexFormatter.getPascalDate (buffer, 20); + firstBlock = HexFormatter.intValue (buffer[18], buffer[19]); // 0 + date = HexFormatter.getPascalDate (buffer, 20); // 2 bytes + // bytes 0x16 - 0x19 are unused } @Override