new pascal Relocator

This commit is contained in:
Denis Molony 2016-08-02 20:37:27 +10:00
parent cf833ab7d7
commit e911fae830
14 changed files with 850 additions and 686 deletions

View File

@ -4,66 +4,79 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import com.bytezone.diskbrowser.utilities.FileFormatException;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
public class PascalCode extends AbstractFile implements PascalConstants, Iterable<PascalSegment> public class PascalCode extends AbstractFile
implements PascalConstants, Iterable<PascalSegment>
{ {
List<PascalSegment> segments = new ArrayList<PascalSegment> (16); List<PascalSegment> segments = new ArrayList<PascalSegment> (16);
String codeName; String codeName;
String comment; String comment;
public static void print () public static void print ()
{ {
for (int i = 0; i < 216; i++) for (int i = 0; i < 216; i++)
System.out.printf ("%3d %d %3s %s%n", i + 128, PascalConstants.mnemonicSize[i], System.out.printf ("%3d %d %3s %s%n", i + 128, PascalConstants.mnemonicSize[i],
PascalConstants.mnemonics[i], PascalConstants.descriptions[i]); PascalConstants.mnemonics[i], PascalConstants.descriptions[i]);
} }
public PascalCode (String name, byte[] buffer) public PascalCode (String name, byte[] buffer)
{ {
super (name, buffer); super (name, buffer);
int nonameCounter = 0; int nonameCounter = 0;
// Build segment list (up to 16 segments) // Build segment list (up to 16 segments)
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
codeName = HexFormatter.getString (buffer, 0x40 + i * 8, 8).trim (); codeName = HexFormatter.getString (buffer, 0x40 + i * 8, 8).trim ();
int size = HexFormatter.intValue (buffer[i * 4 + 2], buffer[i * 4 + 3]); int size = HexFormatter.intValue (buffer[i * 4 + 2], buffer[i * 4 + 3]);
if (size > 0) System.out.printf ("%s %s %d %n", HexFormatter.getHexString (buffer, i * 4, 4),
{ codeName, size);
if (codeName.length () == 0) if (size > 0)
codeName = "<NULL" + nonameCounter++ + ">"; {
segments.add (new PascalSegment (codeName, buffer, i)); if (codeName.length () == 0)
} codeName = "<NULL" + nonameCounter++ + ">";
} try
comment = HexFormatter.getPascalString (buffer, 0x1B0); {
} segments.add (new PascalSegment (codeName, buffer, i));
}
catch (FileFormatException e)
{
System.out.println ("Bad segment");
}
}
}
comment = HexFormatter.getPascalString (buffer, 0x1B0);
}
public String getText () @Override
{ public String getText ()
StringBuilder text = new StringBuilder (getHeader ()); {
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.append ("Slot Addr Len Len Name Kind"
+ " Text Seg# Mtyp Vers I/S\n"); + " Text Seg# Mtyp Vers I/S\n");
text.append ("---- ---- ----- ----- -------- ---------------" text.append ("---- ---- ----- ----- -------- ---------------"
+ " ---- ---- ---- ---- ---\n"); + " ---- ---- ---- ---- ---\n");
for (PascalSegment segment : segments) for (PascalSegment segment : segments)
text.append (segment.toText () + "\n"); text.append (segment.toText () + "\n");
text.append ("\nComment : " + comment + "\n\n"); text.append ("\nComment : " + comment + "\n\n");
return text.toString (); return text.toString ();
} }
private String getHeader () private String getHeader ()
{ {
return "Name : " + name + "\n\n"; return "Name : " + name + "\n\n";
} }
public Iterator<PascalSegment> iterator () @Override
{ public Iterator<PascalSegment> iterator ()
return segments.iterator (); {
} return segments.iterator ();
}
} }

View File

@ -7,323 +7,331 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
public class PascalCodeStatement implements PascalConstants public class PascalCodeStatement implements PascalConstants
{ {
private static final String[] compValue = private static final String[] compValue =
{ "invalid", "", "REAL", "", "STR", "", "BOOL", "", "POWR", "", "BYT", "", "WORD" }; { "invalid", "", "REAL", "", "STR", "", "BOOL", "", "POWR", "", "BYT", "", "WORD" };
int length; int length;
int val; int val;
int p1, p2, p3; int p1, p2, p3;
String mnemonic; String mnemonic;
String extras = ""; String extras = "";
String description; String description;
String text; String text;
int ptr; // temp int ptr; // temp
byte[] buffer; byte[] buffer;
boolean jumpTarget; boolean jumpTarget;
List<Jump> jumps = new ArrayList<Jump> (); List<Jump> jumps = new ArrayList<Jump> ();
public PascalCodeStatement (byte[] buffer, int ptr, int procPtr) public PascalCodeStatement (byte[] buffer, int ptr, int procPtr)
{ {
this.ptr = ptr; this.ptr = ptr;
this.buffer = buffer; this.buffer = buffer;
length = 1; length = 1;
val = buffer[ptr] & 0xFF; val = buffer[ptr] & 0xFF;
if (val <= 127) if (val <= 127)
{ {
mnemonic = "SLDC"; mnemonic = "SLDC";
extras = "#" + val; extras = "#" + val;
description = "Short load constant - push #" + val; description = "Short load constant - push #" + val;
} }
else if (val >= 248) else if (val >= 248)
{ {
mnemonic = "SIND"; mnemonic = "SIND";
extras = "#" + (val - 248); extras = "#" + (val - 248);
description = "Short index load - push word *ToS + #" + (val - 248); description = "Short index load - push word *ToS + #" + (val - 248);
} }
else if (val >= 232) else if (val >= 232)
{ {
mnemonic = "SLDO"; mnemonic = "SLDO";
extras = "#" + (val - 231); extras = "#" + (val - 231);
description = "Short load global - push BASE + #" + (val - 231); description = "Short load global - push BASE + #" + (val - 231);
} }
else if (val >= 216) else if (val >= 216)
{ {
mnemonic = "SLDL"; mnemonic = "SLDL";
extras = "#" + (val - 215); extras = "#" + (val - 215);
description = "Short load local - push MP + #" + (val - 215); description = "Short load local - push MP + #" + (val - 215);
} }
else else
{ {
mnemonic = mnemonics[val - 128]; mnemonic = mnemonics[val - 128];
description = descriptions[val - 128]; description = descriptions[val - 128];
length = mnemonicSize[val - 128]; length = mnemonicSize[val - 128];
if (length != 1) if (length != 1)
{ {
switch (val) switch (val)
{ {
// W1, W2, W3, <table> - word aligned case jump // W1, W2, W3, <table> - word aligned case jump
case 172: //XJP case 172: //XJP
int padding = (ptr % 2) == 0 ? 1 : 0; int padding = (ptr % 2) == 0 ? 1 : 0;
p1 = getWord (buffer, ptr + padding + 1); p1 = getWord (buffer, ptr + padding + 1);
p2 = getWord (buffer, ptr + padding + 3); p2 = getWord (buffer, ptr + padding + 3);
p3 = getWord (buffer, ptr + padding + 5); p3 = getWord (buffer, ptr + padding + 5);
length = (p2 - p1 + 1) * 2 + 7 + padding; length = (p2 - p1 + 1) * 2 + 7 + padding;
setParameters (p1, p2, String.format ("%04X", p3)); setParameters (p1, p2, String.format ("%04X", p3));
int v = p1; int v = p1;
int min = ptr + padding + 7; int min = ptr + padding + 7;
int max = min + (p2 - p1) * 2; int max = min + (p2 - p1) * 2;
for (int i = min; i <= max; i += 2) for (int i = min; i <= max; i += 2)
{ {
jumps.add (new Jump (i, i - HexFormatter.intValue (buffer[i], buffer[i + 1]), v++)); jumps.add (new Jump (i,
} i - HexFormatter.intValue (buffer[i], buffer[i + 1]), v++));
break; }
break;
// UB, <block> - word aligned // UB, <block> - word aligned
case 179: //LDC case 179: //LDC
p1 = buffer[ptr + 1] & 0xFF; p1 = buffer[ptr + 1] & 0xFF;
padding = ptr % 2 == 0 ? 0 : 1; padding = ptr % 2 == 0 ? 0 : 1;
length = p1 * 2 + padding + 2; length = p1 * 2 + padding + 2;
setParameters (p1); setParameters (p1);
break; break;
// UB, <chars> // UB, <chars>
case 166: // LSA case 166: // LSA
case 208: // LPA case 208: // LPA
p1 = buffer[ptr + 1] & 0xFF; p1 = buffer[ptr + 1] & 0xFF;
length = p1 + 2; length = p1 + 2;
if (val == 166) if (val == 166)
{ {
text = HexFormatter.getPascalString (buffer, ptr + 1); text = HexFormatter.getPascalString (buffer, ptr + 1);
description += ": " + text; description += ": " + text;
} }
break; break;
// W // W
case 199: // LDCI case 199: // LDCI
p1 = getWord (buffer, ptr + 1); p1 = getWord (buffer, ptr + 1);
setParameters (p1); setParameters (p1);
break; break;
// B // B
case 162: // INC case 162: // INC
case 163: // IND case 163: // IND
case 164: // IXA case 164: // IXA
case 165: // LAO case 165: // LAO
case 168: // MOV case 168: // MOV
case 169: // LDO case 169: // LDO
case 171: // SRO case 171: // SRO
case 198: // LLA case 198: // LLA
case 202: // LDL case 202: // LDL
case 204: // STL case 204: // STL
case 213: // BPT case 213: // BPT
length = getLengthOfB (buffer[ptr + 1]) + 1; length = getLengthOfB (buffer[ptr + 1]) + 1;
p1 = getValueOfB (buffer, ptr + 1, length - 1); p1 = getValueOfB (buffer, ptr + 1, length - 1);
setParameters (p1); setParameters (p1);
break; break;
// DB, B or UB, B // DB, B or UB, B
case 157: // LDE case 157: // LDE
case 167: // LAE case 167: // LAE
case 178: // LDA case 178: // LDA
case 182: // LOD case 182: // LOD
case 184: // STR case 184: // STR
case 209: // STE case 209: // STE
length = getLengthOfB (buffer[ptr + 2]) + 2; length = getLengthOfB (buffer[ptr + 2]) + 2;
p1 = buffer[ptr + 1] & 0xFF; p1 = buffer[ptr + 1] & 0xFF;
p2 = getValueOfB (buffer, ptr + 2, length - 2); p2 = getValueOfB (buffer, ptr + 2, length - 2);
setParameters (p1, p2); setParameters (p1, p2);
break; break;
// UB1, UB2 // UB1, UB2
case 192: // IXP case 192: // IXP
case 205: // CXP case 205: // CXP
p1 = buffer[ptr + 1] & 0xFF; p1 = buffer[ptr + 1] & 0xFF;
p2 = buffer[ptr + 2] & 0xFF; p2 = buffer[ptr + 2] & 0xFF;
setParameters (p1, p2); setParameters (p1, p2);
break; break;
// SB or DB // SB or DB
case 161: // FJP case 161: // FJP
case 173: // RNP case 173: // RNP
case 185: // UJP case 185: // UJP
case 193: // RBP case 193: // RBP
case 211: // EFJ case 211: // EFJ
case 212: // NFJ case 212: // NFJ
p1 = buffer[ptr + 1]; p1 = buffer[ptr + 1];
if (val == 173 || val == 193) // return from procedure if (val == 173 || val == 193) // return from procedure
setParameters (p1); setParameters (p1);
else if (p1 < 0) else if (p1 < 0)
{ {
// look up jump table entry // look up jump table entry
int address = procPtr + p1; int address = procPtr + p1;
int ptr2 = address - ((buffer[address + 1] & 0xFF) * 256 + (buffer[address] & 0xFF)); int ptr2 = address
extras = String.format ("$%04X", ptr2); - ((buffer[address + 1] & 0xFF) * 256 + (buffer[address] & 0xFF));
jumps.add (new Jump (ptr, ptr2)); extras = String.format ("$%04X", ptr2);
} jumps.add (new Jump (ptr, ptr2));
else }
{ else
int address = ptr + length + p1; {
extras = String.format ("$%04X", address); int address = ptr + length + p1;
jumps.add (new Jump (ptr, address)); extras = String.format ("$%04X", address);
} jumps.add (new Jump (ptr, address));
break; }
break;
// UB // UB
case 160: // AOJ case 160: // AOJ
case 170: // SAS case 170: // SAS
case 174: // CIP case 174: // CIP
case 188: // LDM case 188: // LDM
case 189: // STM case 189: // STM
case 194: // CBP case 194: // CBP
case 206: // CLP case 206: // CLP
case 207: // CGP case 207: // CGP
p1 = buffer[ptr + 1] & 0xFF; p1 = buffer[ptr + 1] & 0xFF;
setParameters (p1); setParameters (p1);
break; break;
// CSP // CSP
case 158: case 158:
p1 = buffer[ptr + 1]; p1 = buffer[ptr + 1] & 0xFF;
description = "Call standard procedure - " + CSP[p1]; if (p1 < CSP.length)
break; description = "Call standard procedure - " + CSP[p1];
else
description = "Call standard procedure - index out of bounds";
break;
// Non-integer comparisons // Non-integer comparisons
case 175: case 175:
case 176: case 176:
case 177: case 177:
case 180: case 180:
case 181: case 181:
case 183: case 183:
p1 = buffer[ptr + 1]; // 2/4/6/8/10/12 p1 = buffer[ptr + 1] & 0xFF; // 2/4/6/8/10/12
if (p1 < 0 || p1 >= compValue.length) if (p1 < 0 || p1 >= compValue.length)
{ {
System.out.printf ("%d %d %d%n", val, p1, ptr); System.out.printf ("%d %d %d%n", val, p1, ptr);
mnemonic += "******************************"; mnemonic += "******************************";
break; break;
} }
mnemonic += compValue[p1]; mnemonic += compValue[p1];
if (p1 == 10 || p1 == 12) if (p1 == 10 || p1 == 12)
{ {
length = getLengthOfB (buffer[ptr + 2]) + 2; length = getLengthOfB (buffer[ptr + 2]) + 2;
p2 = getValueOfB (buffer, ptr + 2, length - 2); p2 = getValueOfB (buffer, ptr + 2, length - 2);
setParameters (p2); setParameters (p2);
} }
break; break;
default: default:
System.out.println ("Forgot : " + val); System.out.println ("Forgot : " + val);
} }
} }
} }
} }
private int getWord (byte[] buffer, int ptr) private int getWord (byte[] buffer, int ptr)
{ {
return (buffer[ptr + 1] & 0xFF) * 256 + (buffer[ptr] & 0xFF); return (buffer[ptr + 1] & 0xFF) * 256 + (buffer[ptr] & 0xFF);
} }
private int getLengthOfB (byte b) private int getLengthOfB (byte b)
{ {
return (b & 0x80) == 0x80 ? 2 : 1; return (b & 0x80) == 0x80 ? 2 : 1;
} }
private int getValueOfB (byte[] buffer, int ptr, int length) private int getValueOfB (byte[] buffer, int ptr, int length)
{ {
if (length == 2) if (length == 2)
return (buffer[ptr] & 0x7F) * 256 + (buffer[ptr + 1] & 0xFF); return (buffer[ptr] & 0x7F) * 256 + (buffer[ptr + 1] & 0xFF);
return buffer[ptr] & 0xFF; return buffer[ptr] & 0xFF;
} }
private void setParameters (int p1) private void setParameters (int p1)
{ {
description = description.replaceFirst (":1", p1 + ""); description = description.replaceFirst (":1", p1 + "");
extras = "#" + p1; extras = "#" + p1;
} }
private void setParameters (int p1, int p2) private void setParameters (int p1, int p2)
{ {
setParameters (p1); setParameters (p1);
extras += ", #" + p2; extras += ", #" + p2;
description = description.replaceFirst (":2", p2 + ""); description = description.replaceFirst (":2", p2 + "");
} }
private void setParameters (int p1, int p2, String p3) private void setParameters (int p1, int p2, String p3)
{ {
setParameters (p1, p2); setParameters (p1, p2);
description = description.replaceFirst (":3", p3); description = description.replaceFirst (":3", p3);
} }
public String toString () @Override
{ public String toString ()
String hex = getHex (buffer, ptr, length > 4 ? 4 : length); {
StringBuilder text = new StringBuilder (); String hex = getHex (buffer, ptr, length > 4 ? 4 : length);
text.append (String.format ("%2s%05X: %-11s %-6s %-8s %s%n", jumpTarget ? "->" : "", ptr, StringBuilder text = new StringBuilder ();
hex, mnemonic, extras, description)); text.append (String.format ("%2s%05X: %-11s %-6s %-8s %s%n",
if (length > 4) jumpTarget ? "->" : "", ptr, hex, mnemonic, extras,
{ description));
int bytesLeft = length - 4; if (length > 4)
int jmp = 0; {
int p = ptr + 4; int bytesLeft = length - 4;
while (bytesLeft > 0) int jmp = 0;
{ int p = ptr + 4;
String line = getHex (buffer, p, (bytesLeft > 4) ? 4 : bytesLeft); while (bytesLeft > 0)
text.append (" " + line); {
if (jumps.size () > 0) String line = getHex (buffer, p, (bytesLeft > 4) ? 4 : bytesLeft);
{ text.append (" " + line);
if (jmp < jumps.size ()) if (jumps.size () > 0)
text.append (" " + jumps.get (jmp++)); {
if (jmp < jumps.size ()) if (jmp < jumps.size ())
text.append (" " + jumps.get (jmp++)); text.append (" " + jumps.get (jmp++));
} if (jmp < jumps.size ())
text.append ("\n"); text.append (" " + jumps.get (jmp++));
bytesLeft -= 4; }
p += 4; text.append ("\n");
} bytesLeft -= 4;
} p += 4;
return text.toString (); }
} }
return text.toString ();
}
private String getHex (byte[] buffer, int offset, int length) private String getHex (byte[] buffer, int offset, int length)
{ {
if ((offset + length) >= buffer.length) if ((offset + length) >= buffer.length)
{ {
System.out.println ("too many"); System.out.println ("too many");
return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
} }
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
text.append (String.format ("%02X ", buffer[offset + i])); text.append (String.format ("%02X ", buffer[offset + i]));
if (text.length () > 0) if (text.length () > 0)
text.deleteCharAt (text.length () - 1); text.deleteCharAt (text.length () - 1);
return text.toString (); return text.toString ();
} }
class Jump class Jump
{ {
int addressFrom; int addressFrom;
int addressTo; int addressTo;
boolean caseJump; boolean caseJump;
int caseValue; int caseValue;
public Jump (int addressFrom, int addressTo) public Jump (int addressFrom, int addressTo)
{ {
this.addressFrom = addressFrom; this.addressFrom = addressFrom;
this.addressTo = addressTo; this.addressTo = addressTo;
} }
public Jump (int addressFrom, int addressTo, int value) public Jump (int addressFrom, int addressTo, int value)
{ {
this (addressFrom, addressTo); this (addressFrom, addressTo);
this.caseValue = value; this.caseValue = value;
this.caseJump = true; this.caseJump = true;
} }
public String toString () @Override
{ public String toString ()
if (caseJump) {
return String.format ("%3d: %04X", caseValue, addressTo); if (caseJump)
return String.format ("%04X", addressTo); return String.format ("%3d: %04X", caseValue, addressTo);
} return String.format ("%04X", addressTo);
} }
}
} }

View File

@ -2,117 +2,91 @@ package com.bytezone.diskbrowser.applefile;
public interface PascalConstants public interface PascalConstants
{ {
static String[] mnemonics = static String[] mnemonics =
{ "ABI", "ABR", "ADI", "ADR", "LAND", "DIF", "DVI", "DVR", "CHK", "FLO", "FLT", { "ABI", "ABR", "ADI", "ADR", "LAND", "DIF", "DVI", "DVR", "CHK", "FLO", "FLT",
"INN", "INT", "LOR", "MODI", "MPI", "MPR", "NGI", "NGR", "LNOT", "SRS", "SBI", "INN", "INT", "LOR", "MODI", "MPI", "MPR", "NGI", "NGR", "LNOT", "SRS", "SBI",
"SBR", "SGS", "SQI", "SQR", "STO", "IXS", "UNI", "LDE", "CSP", "LDCN", "ADJ", "SBR", "SGS", "SQI", "SQR", "STO", "IXS", "UNI", "LDE", "CSP", "LDCN", "ADJ",
"FJP", "INC", "IND", "IXA", "LAO", "LSA", "LAE", "MOV", "LDO", "SAS", "SRO", "XJP", "FJP", "INC", "IND", "IXA", "LAO", "LSA", "LAE", "MOV", "LDO", "SAS", "SRO",
"RNP", "CIP", "EQU", "GEQ", "GRT", "LDA", "LDC", "LEQ", "LES", "LOD", "NEQ", "STR", "XJP", "RNP", "CIP", "EQU", "GEQ", "GRT", "LDA", "LDC", "LEQ", "LES", "LOD",
"UJP", "LDP", "STP", "LDM", "STM", "LDB", "STB", "IXP", "RBP", "CBP", "EQUI", "NEQ", "STR", "UJP", "LDP", "STP", "LDM", "STM", "LDB", "STB", "IXP", "RBP",
"GEQI", "GRTI", "LLA", "LDCI", "LEQI", "LESI", "LDL", "NEQI", "STL", "CXP", "CLP", "CBP", "EQUI", "GEQI", "GRTI", "LLA", "LDCI", "LEQI", "LESI", "LDL", "NEQI",
"CGP", "LPA", "STE", "???", "EFJ", "NFJ", "BPT", "XIT", "NOP" }; "STL", "CXP", "CLP", "CGP", "LPA", "STE", "???", "EFJ", "NFJ", "BPT", "XIT",
"NOP" };
static int[] mnemonicSize = static int[] mnemonicSize =
// //
// 128 - 155 // 128 - 155
// 156 - 183 // 156 - 183
// 184 - 211 // 184 - 211
// 212 - 239 // 212 - 239
// 240 - 255 // 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, 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, 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, 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, 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,
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, 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 };
static String[] descriptions = static String[] descriptions =
{ { "Absolute value of integer - push ABS(ToS)",
"Absolute value of integer - push ABS(ToS)", "Absolute value of real - push abs((real)ToS)", "Add integers (tos + tos-1)",
"Absolute value of real - push abs((real)ToS)", "Add reals - push ToS + ToS-1", "Logical AND",
"Add integers (tos + tos-1)", "Set difference - push difference of sets ToS-1 and ToS",
"Add reals - push ToS + ToS-1", "Divide integers - push ToS-1 / ToS", "Divide reals - push ToS-1 / ToS",
"Logical AND", "Check subrange bounds - assert ToS-1 <= ToS-2 <= ToS, pop ToS, pop ToS-1",
"Set difference - push difference of sets ToS-1 and ToS", "Float next-to-ToS - push integer ToS-1 after converting to a real",
"Divide integers - push ToS-1 / ToS", "Float ToS - push integer ToS after converting to a float",
"Divide reals - push ToS-1 / ToS", "Set Membership - if int ToS-1 is in set ToS, push true, else push false",
"Check subrange bounds - assert ToS-1 <= ToS-2 <= ToS, pop ToS, pop ToS-1", "Set Intersection - push TOS AND TOS-1", "Logical OR",
"Float next-to-ToS - push integer ToS-1 after converting to a real", "Modulo integers - push ToS-1 % ToS", "Multiply TOS by TOS-1",
"Float ToS - push integer ToS after converting to a float", "Multiply reals - push ToS-1 * ToS",
"Set Membership - if int ToS-1 is in set ToS, push true, else push false", "Negate Integer - push two's complement of ToS",
"Set Intersection - push TOS AND TOS-1", "Negate real - push -((real)ToS)", "Logical Not - push one's complement of ToS",
"Logical OR", "Build a subrange set", "Subtract Integers push ToS-1 - ToS",
"Modulo integers - push ToS-1 % ToS", "Subtract reals - push ToS-1 - ToS", "Build a singleton set",
"Multiply TOS by TOS-1", "Square integer - push ToS ^ 2", "Square real - push ToS ^ 2",
"Multiply reals - push ToS-1 * ToS", "Store indirect word - store ToS into word pointed to by ToS-1",
"Negate Integer - push two's complement of ToS", "Index string array - push &(*ToS-1 + ToS)",
"Negate real - push -((real)ToS)", "Set union - push union of sets ToS OR ToS-1",
"Logical Not - push one's complement of ToS", "Load extended word - push word at segment :1+:2",
"Build a subrange set", "Call Standard Procedure #:1 - ", "Load Constant NIL", "Adjust set",
"Subtract Integers push ToS-1 - ToS", "Jump if ToS false", "Increment field ptr - push ToS+:1",
"Subtract reals - push ToS-1 - ToS", "Static index and load word", "Compute word pointer from ToS-1 + ToS * :1 words",
"Build a singleton set", "Load Global - push (BASE+:1)", "Load constant string address",
"Square integer - push ToS ^ 2", "Load extended address - push address of word at segment :1+:2",
"Square real - push ToS ^ 2", "Move words - transfer :1 words from *ToS to *ToS-1",
"Store indirect word - store ToS into word pointed to by ToS-1", "Load Global Word - push BASE+:1", "String Assign", "Store TOS into BASE+:1",
"Index string array - push &(*ToS-1 + ToS)", "Case Jump - :1::2, Error: :3", "Return from non-base procedure (pass :1 words)",
"Set union - push union of sets ToS OR ToS-1", "Call intermediate procedure #:1", "ToS-1 == ToS", "ToS-1 >= ToS", "ToS-1 > ToS",
"Load extended word - push word at segment :1+:2", "Load Intermediate Address - push :1th activation record +:2 bytes",
"Call Standard Procedure #:1 - ", "Load multi-word constant - :1 words", "ToS-1 <= ToS", "ToS-1 < ToS",
"Load Constant NIL", "Load Intermediate Word - push :1th activation record +:2 bytes", "ToS-1 <> ToS",
"Adjust set", "Store intermediate word - store TOS into :2, traverse :1", "Unconditional jump",
"Jump if ToS false", "Load Packed Field - push *ToS", "Store into packed field",
"Increment field ptr - push ToS+:1", "Load multiple words - push block of unsigned bytes at *ToS",
"Static index and load word", "Store multiple words - store block of UB at ToS to *ToS-1",
"Compute word pointer from ToS-1 + ToS * :1 words", "Load Byte - index the byte pointer ToS-1 by integer index ToS and push that byte",
"Load Global - push (BASE+:1)", "Store Byte - index the byte pointer ToS-2 by integer index ToS-1 and move ToS to that location",
"Load constant string address", "Index packed array - do complicated stuff with :1 and :2",
"Load extended address - push address of word at segment :1+:2", "Return from base procedure (pass :1 words)",
"Move words - transfer :1 words from *ToS to *ToS-1", "Call Base Procedure :1 at lex level -1 or 0", "Compare Integer : ToS-1 = ToS",
"Load Global Word - push BASE+:1", "Compare Integer : TOS-1 >= TOS", "Compare Integer : TOS-1 > ToS",
"String Assign", "Load Local Address - push MP+:1", "Load Word - push #:1",
"Store TOS into BASE+:1", "Compare Integer : TOS-1 <= TOS", "Compare Integer : TOS-1 < ToS",
"Case Jump - :1::2, Error: :3", "Load Local Word - push MP+:1", "Compare Integer : TOS-1 <> TOS",
"Return from non-base procedure (pass :1 words)", "Store Local Word - store ToS into MP+:1",
"Call intermediate procedure #:1", "Call external procedure #:2 in segment #:1", "Call local procedure #:1",
"ToS-1 == ToS", "Call global procedure #:1", "Load a packed array - use :1 and :2",
"ToS-1 >= ToS", "Store extended word - store ToS into word at segment :1+:2", "210 ",
"ToS-1 > ToS", "Equal false jump - jump :1 if ToS-1 <> ToS",
"Load Intermediate Address - push :1th activation record +:2 bytes", "Not equal false jump - jump :1 if ToS-1 == ToS",
"Load multi-word constant - :1 words", "Breakpoint - not used (does NOP)", "Exit OS - cold boot", "No-op" };
"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 = static String[] CSP =
{ "000", "NEW", "MVL", "MVR", "EXIT", "", "", "IDS", "TRS", "TIM", "FLC", "SCN", "", { "000", "NEW", "MVL", "MVR", "EXIT", "", "", "IDS", "TRS", "TIM", "FLC", "SCN", "",
"", "", "", "", "", "", "", "", "021", "TNC", "RND", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "021", "TNC", "RND", "", "", "", "", "", "", "",
"MRK", "RLS", "33", "34", "POT", "36", "37", "38", "39", "40" }; "MRK", "RLS", "33", "34", "POT", "36", "37", "38", "39", "40" };
static String[] SegmentKind = static String[] SegmentKind = { "Linked", "HostSeg", "SegProc", "UnitSeg", "SeprtSeg",
{ "Linked", "HostSeg", "SegProc", "UnitSeg", "SeprtSeg", "UnlinkedIntrins", "UnlinkedIntrins", "LinkedIntrins", "DataSeg" };
"LinkedIntrins", "DataSeg" };
} }

View File

@ -8,168 +8,183 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
public class PascalProcedure public class PascalProcedure
{ {
// all procedures have these fields // all procedures have these fields
byte[] buffer; byte[] buffer;
int procOffset; int procOffset;
int offset; int offset;
int slot; int slot;
boolean valid; boolean valid;
// only valid procedures have these fields // only valid procedures have these fields
int procedureNo; int procedureNo;
int procLevel; int procLevel;
int codeStart; int codeStart;
int codeEnd; int codeEnd;
int parmSize; int parmSize;
int dataSize; int dataSize;
List<PascalCodeStatement> statements = new ArrayList<PascalCodeStatement> (); List<PascalCodeStatement> statements = new ArrayList<PascalCodeStatement> ();
AssemblerProgram assembler; AssemblerProgram assembler;
int jumpTable = -8; int jumpTable = -8;
public PascalProcedure (byte[] buffer, int slot) public PascalProcedure (byte[] buffer, int slot)
{ {
this.buffer = buffer; this.buffer = buffer;
this.slot = slot; this.slot = slot;
int p = buffer.length - 2 - slot * 2; int p = buffer.length - 2 - slot * 2;
offset = HexFormatter.intValue (buffer[p], buffer[p + 1]); offset = HexFormatter.intValue (buffer[p], buffer[p + 1]);
procOffset = p - offset; procOffset = p - offset;
valid = procOffset > 0; valid = procOffset > 0;
if (valid) if (valid)
{ {
procedureNo = buffer[procOffset] & 0xFF; procedureNo = buffer[procOffset] & 0xFF;
procLevel = buffer[procOffset + 1]; procLevel = buffer[procOffset + 1];
codeStart = HexFormatter.intValue (buffer[procOffset - 2], buffer[procOffset - 1]); codeStart = HexFormatter.intValue (buffer[procOffset - 2], buffer[procOffset - 1]);
codeEnd = HexFormatter.intValue (buffer[procOffset - 4], buffer[procOffset - 3]); codeEnd = HexFormatter.intValue (buffer[procOffset - 4], buffer[procOffset - 3]);
parmSize = HexFormatter.intValue (buffer[procOffset - 6], buffer[procOffset - 5]); parmSize = HexFormatter.intValue (buffer[procOffset - 6], buffer[procOffset - 5]);
dataSize = HexFormatter.intValue (buffer[procOffset - 8], buffer[procOffset - 7]); dataSize = HexFormatter.intValue (buffer[procOffset - 8], buffer[procOffset - 7]);
} }
} }
private void decode () private void decode ()
{ {
if (statements.size () > 0 || assembler != null) if (statements.size () > 0 || assembler != null)
return; return;
int ptr = procOffset - codeStart - 2; int ptr = procOffset - codeStart - 2;
int max = procOffset + jumpTable; int max = procOffset + jumpTable;
if (codeEnd == 0) if (codeEnd == 0)
{ {
int len = codeStart + jumpTable + 2; int len = codeStart + jumpTable + 2;
if (len > 0) if (len > 0)
{ {
byte[] asmBuf = new byte[len]; byte[] asmBuf = new byte[len];
System.arraycopy (buffer, ptr, asmBuf, 0, len); System.arraycopy (buffer, ptr, asmBuf, 0, len);
assembler = new AssemblerProgram ("Proc", asmBuf, ptr); assembler = new AssemblerProgram ("Proc", asmBuf, ptr);
} }
return; return;
} }
while (ptr < max) while (ptr < max)
{ {
PascalCodeStatement cs = new PascalCodeStatement (buffer, ptr, procOffset); System.out.printf ("ptr:%d, max:%d, buf:%d %n", ptr, max, buffer.length);
if (cs.length <= 0) if (ptr >= buffer.length || ptr < 0)
{ {
System.out.println ("error - length <= 0 : " + cs); System.out.println ("Ptr outside buffer");
break; break;
} }
statements.add (cs); PascalCodeStatement cs = new PascalCodeStatement (buffer, ptr, procOffset);
if (cs.val == 185 || cs.val == 161) if (cs.length <= 0)
if (cs.p1 < jumpTable) {
{ System.out.println ("error - length <= 0 : " + cs);
jumpTable = cs.p1; break;
max = procOffset + jumpTable; }
} statements.add (cs);
ptr += cs.length; 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 // Tidy up left-over bytes at the end
if (statements.size () > 1) if (statements.size () > 1)
{ {
PascalCodeStatement lastStatement = statements.get (statements.size () - 1); PascalCodeStatement lastStatement = statements.get (statements.size () - 1);
PascalCodeStatement secondLastStatement = statements.get (statements.size () - 2); PascalCodeStatement secondLastStatement = statements.get (statements.size () - 2);
if (lastStatement.val == 0 if (lastStatement.val == 0 && (secondLastStatement.val == 0xD6
&& (secondLastStatement.val == 0xD6 || secondLastStatement.val == 0xC1 || secondLastStatement.val == 0xAD)) || secondLastStatement.val == 0xC1 || secondLastStatement.val == 0xAD))
statements.remove (statements.size () - 1); statements.remove (statements.size () - 1);
} }
// Mark statements that are jump targets // Mark statements that are jump targets
int actualEnd = procOffset - codeEnd - 4; int actualEnd = procOffset - codeEnd - 4;
for (PascalCodeStatement cs : statements) for (PascalCodeStatement cs : statements)
{ {
if (cs.ptr == actualEnd) if (cs.ptr == actualEnd)
{ {
cs.jumpTarget = true; cs.jumpTarget = true;
continue; continue;
} }
for (Jump cj : cs.jumps) for (Jump cj : cs.jumps)
for (PascalCodeStatement cs2 : statements) for (PascalCodeStatement cs2 : statements)
if (cs2.ptr == cj.addressTo) if (cs2.ptr == cj.addressTo)
{ {
cs2.jumpTarget = true; cs2.jumpTarget = true;
break; break;
} }
} }
} }
public List<PascalCodeStatement> extractStrings () public List<PascalCodeStatement> extractStrings ()
{ {
decode (); decode ();
List<PascalCodeStatement> strings = new ArrayList<PascalCodeStatement> (); List<PascalCodeStatement> strings = new ArrayList<PascalCodeStatement> ();
for (PascalCodeStatement cs : statements) for (PascalCodeStatement cs : statements)
if (cs.val == 166) if (cs.val == 166)
strings.add (cs); strings.add (cs);
return strings; return strings;
} }
public String toString () @Override
{ public String toString ()
if (!valid) {
return ""; if (!valid)
decode (); return "";
decode ();
StringBuilder text = new StringBuilder ("\nProcedure Header\n================\n\n"); StringBuilder text = new StringBuilder ("\nProcedure Header\n================\n\n");
if (false) if (false)
text.append (HexFormatter.format (buffer, procOffset + jumpTable, 2 - jumpTable) + "\n\n"); 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 ("Level.......%5d %02X%n", procLevel,
text.append (String.format ("Proc no.....%5d %02X%n", procedureNo, procedureNo)); procLevel & 0xFF));
text.append (String.format ("Code entry..%5d %04X (%04X - %04X = %04X)%n", codeStart, text.append (String.format ("Proc no.....%5d %02X%n", procedureNo, procedureNo));
codeStart, (procOffset - 2), codeStart, (procOffset - codeStart - 2))); text.append (String.format ("Code entry..%5d %04X (%04X - %04X = %04X)%n",
text.append (String.format ("Code exit...%5d %04X", codeEnd, codeEnd)); codeStart, codeStart, (procOffset - 2), codeStart,
if (codeEnd > 0) (procOffset - codeStart - 2)));
text.append (String.format (" (%04X - %04X = %04X)%n", (procOffset - 4), codeEnd, text.append (String.format ("Code exit...%5d %04X", codeEnd, codeEnd));
(procOffset - codeEnd - 4))); if (codeEnd > 0)
else text.append (String.format (" (%04X - %04X = %04X)%n", (procOffset - 4), codeEnd,
text.append (String.format ("%n")); (procOffset - codeEnd - 4)));
text.append (String.format ("Parm size...%5d %04X%n", parmSize, parmSize)); else
text.append (String.format ("Data size...%5d %04X%n%n", dataSize, dataSize)); 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; int ptr = procOffset - codeStart - 2;
if (false) if (false)
text.append (HexFormatter.format (buffer, ptr, codeStart + jumpTable + 2) + "\n\n"); text.append (HexFormatter.format (buffer, ptr, codeStart + jumpTable + 2) + "\n\n");
if (codeEnd == 0) if (codeEnd == 0)
text.append (assembler.getAssembler () + "\n"); {
else if (assembler != null)
{ text.append (assembler.getAssembler () + "\n");
for (PascalCodeStatement cs : statements) else
text.append (cs); text.append ("Null assembler in PascalProcedure");
}
else
{
for (PascalCodeStatement cs : statements)
text.append (cs);
if (jumpTable < -8 && false) if (jumpTable < -8 && false)
{ {
text.append ("\nJump table:\n"); text.append ("\nJump table:\n");
for (int i = procOffset + jumpTable; i < procOffset - 8; i += 2) for (int i = procOffset + jumpTable; i < procOffset - 8; i += 2)
{ {
ptr = i - ((buffer[i + 1] & 0xFF) * 256 + (buffer[i] & 0xFF)); 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], text.append (String.format ("%05X : %02X %02X --> %04X%n", i, buffer[i],
ptr)); buffer[i + 1], ptr));
} }
} }
} }
return text.toString (); return text.toString ();
} }
} }

View File

@ -33,19 +33,22 @@ public class PascalSegment extends AbstractFile implements PascalConstants
this.size = HexFormatter.intValue (fullBuffer[seq * 4 + 2], fullBuffer[seq * 4 + 3]); this.size = HexFormatter.intValue (fullBuffer[seq * 4 + 2], fullBuffer[seq * 4 + 3]);
this.segmentNoHeader = fullBuffer[0x100 + seq * 2]; this.segmentNoHeader = fullBuffer[0x100 + seq * 2];
segKind = segKind = HexFormatter.intValue (fullBuffer[0xC0 + seq * 2],
HexFormatter.intValue (fullBuffer[0xC0 + seq * 2], fullBuffer[0xC0 + seq * 2 + 1]); fullBuffer[0xC0 + seq * 2 + 1]);
textAddress = textAddress = HexFormatter.intValue (fullBuffer[0xE0 + seq * 2],
HexFormatter.intValue (fullBuffer[0xE0 + seq * 2], fullBuffer[0xE0 + seq * 2 + 1]); fullBuffer[0xE0 + seq * 2 + 1]);
int flags = fullBuffer[0x101 + seq * 2] & 0xFF; int flags = fullBuffer[0x101 + seq * 2] & 0xFF;
machineType = flags & 0x0F; machineType = flags & 0x0F;
version = (flags & 0xD0) >> 5; version = (flags & 0xD0) >> 5;
intrinsSegs1 = intrinsSegs1 = HexFormatter.intValue (fullBuffer[0x120 + seq * 4],
HexFormatter.intValue (fullBuffer[0x120 + seq * 4], fullBuffer[0x120 + seq * 4 + 1]); fullBuffer[0x120 + seq * 4 + 1]);
intrinsSegs2 = HexFormatter.intValue (fullBuffer[0x120 + seq * 4 + 2], intrinsSegs2 = HexFormatter.intValue (fullBuffer[0x120 + seq * 4 + 2],
fullBuffer[0x120 + seq * 4 + 3]); fullBuffer[0x120 + seq * 4 + 3]);
int offset = blockNo * 512; 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) if (offset < fullBuffer.length)
{ {
buffer = new byte[size]; // replaces this.buffer with the segment buffer only 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); System.out.printf ("Zero segment header in %s seq %d%n", name, seq);
else if (segmentNoBody != segmentNoHeader) else if (segmentNoBody != segmentNoHeader)
System.out.println ("Segment number mismatch : " + segmentNoBody + " / " System.out.println ("Segment number mismatch : " + segmentNoBody + " / "
+ segmentNoHeader); + segmentNoHeader);
} }
else 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"); throw new FileFormatException ("Error in PascalSegment");
} }
} }
@ -76,10 +80,10 @@ public class PascalSegment extends AbstractFile implements PascalConstants
public String toText () public String toText ()
{ {
return String.format ( return String
" %2d %02X %04X %,6d %-8s %-15s %3d %3d %d %d %d %d", .format (" %2d %02X %04X %,6d %-8s %-15s %3d %3d %d %d %d %d",
slot, blockNo, size, size, name, SegmentKind[segKind], textAddress, slot, blockNo, size, size, name, SegmentKind[segKind], textAddress,
segmentNoHeader, machineType, version, intrinsSegs1, intrinsSegs2); segmentNoHeader, machineType, version, intrinsSegs1, intrinsSegs2);
} }
@Override @Override
@ -91,9 +95,9 @@ public class PascalSegment extends AbstractFile implements PascalConstants
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
String title = "Segment - " + name; String title = "Segment - " + name;
text.append (title + "\n" text.append (title + "\n"
+ "===============================".substring (0, title.length ()) + "\n\n"); + "===============================".substring (0, title.length ()) + "\n\n");
String warning = String warning =
segmentNoBody == segmentNoHeader ? "" : " (" + segmentNoHeader + " in header)"; segmentNoBody == segmentNoHeader ? "" : " (" + segmentNoHeader + " in header)";
text.append (String.format ("Address........ %02X%n", blockNo)); text.append (String.format ("Address........ %02X%n", blockNo));
text.append (String.format ("Length......... %04X%n", buffer.length)); text.append (String.format ("Length......... %04X%n", buffer.length));
text.append (String.format ("Machine type... %d%n", machineType)); 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; int address = size - procedure.slot * 2 - 2;
text.append (String.format ( text.append (String.format (
" %2d %04X %3d %04X %04X %04X " " %2d %04X %3d %04X %04X %04X "
+ "%04X (%04X - %04X = %04X)%n", + "%04X (%04X - %04X = %04X)%n",
procedure.procedureNo, procedure.offset, procedure.procedureNo, procedure.offset,
procedure.procLevel, procedure.codeStart, procedure.procLevel, procedure.codeStart,
procedure.codeEnd, procedure.parmSize, procedure.dataSize, procedure.codeEnd, procedure.parmSize,
address, procedure.offset, procedure.procOffset)); procedure.dataSize, address, procedure.offset,
procedure.procOffset));
} }
else else
text.append (String.format (" %2d %04X%n", procedure.slot, procedure.offset)); text.append (String.format (" %2d %04X%n", procedure.slot, procedure.offset));
@ -131,7 +136,8 @@ public class PascalSegment extends AbstractFile implements PascalConstants
{ {
List<PascalCodeStatement> strings = pp.extractStrings (); List<PascalCodeStatement> strings = pp.extractStrings ();
for (PascalCodeStatement cs : strings) 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) for (PascalProcedure procedure : procedures)

View File

@ -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<DiskRecord> diskRecords = new ArrayList<DiskRecord> ();
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<Segment> segments = new ArrayList<Segment> ();
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);
}
}
}

View File

@ -384,6 +384,7 @@ public class AppleDisk implements Disk
if (!isValidAddress (block)) if (!isValidAddress (block))
{ {
System.out.println ("Invalid block : " + block); System.out.println ("Invalid block : " + block);
// assert false;
return null; return null;
// return new AppleDiskAddress (this, 0); this was looping 26/07/2016 // return new AppleDiskAddress (this, 0); this was looping 26/07/2016
} }

View File

@ -20,7 +20,7 @@ import com.bytezone.diskbrowser.wizardry.WizardryScenarioDisk;
public class DiskFactory public class DiskFactory
{ {
private static boolean debug = false; private static boolean debug = true;
private DiskFactory () private DiskFactory ()
{ {

View File

@ -15,7 +15,6 @@ import com.bytezone.common.State;
public class DiskBrowser extends JFrame implements DiskSelectionListener, QuitListener public class DiskBrowser extends JFrame implements DiskSelectionListener, QuitListener
{ {
private static final String windowTitle = "Apple ][ Disk Browser"; 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 final Preferences prefs = Preferences.userNodeForPackage (this.getClass ());
private WindowSaver windowSaver; private WindowSaver windowSaver;
@ -127,9 +126,6 @@ public class DiskBrowser extends JFrame implements DiskSelectionListener, QuitLi
pack (); pack ();
// prefs.addPreferenceChangeListener (catalogPanel);
// prefs.addPreferenceChangeListener (dataPanel);
// restore the menuHandler items before they are referenced // restore the menuHandler items before they are referenced
quitAction.restore (); quitAction.restore ();
@ -164,6 +160,7 @@ public class DiskBrowser extends JFrame implements DiskSelectionListener, QuitLi
@Override @Override
public void quit (Preferences preferences) public void quit (Preferences preferences)
{ {
windowSaver = new WindowSaver (prefs, this, "DiskBrowser");
windowSaver.saveWindow (); windowSaver.saveWindow ();
} }

View File

@ -1,5 +1,6 @@
package com.bytezone.diskbrowser.gui; package com.bytezone.diskbrowser.gui;
import java.awt.Dimension;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
import javax.swing.JFrame; import javax.swing.JFrame;
@ -23,6 +24,8 @@ public class WindowSaver
prefs.putInt (key + "Y", frame.getY ()); prefs.putInt (key + "Y", frame.getY ());
prefs.putInt (key + "Height", frame.getHeight ()); prefs.putInt (key + "Height", frame.getHeight ());
prefs.putInt (key + "Width", frame.getWidth ()); 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 () public boolean restoreWindow ()
@ -32,19 +35,24 @@ public class WindowSaver
int height = prefs.getInt (key + "Height", -1); int height = prefs.getInt (key + "Height", -1);
int width = prefs.getInt (key + "Width", -1); int width = prefs.getInt (key + "Width", -1);
Dimension screen = java.awt.Toolkit.getDefaultToolkit ().getScreenSize ();
if (width < 0) // nothing to restore if (width < 0) // nothing to restore
{ {
frame.setLocation (100, 100);
frame.setSize (1000, 600);
frame.setLocationRelativeTo (null); // centre 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; return false;
} }
// frame.setX (x); System.out.printf ("w:%d, sw:%f%n", width, screen.getWidth ());
// frame.setY (y); if (width > screen.getWidth () - 15)
// frame.setHeight (height); width = (int) (screen.getWidth () - 15);
// frame.setWidth (width);
frame.setLocation (x, y);
frame.setSize (width, height); 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; return true;
} }

View File

@ -14,11 +14,12 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
abstract class CatalogEntry implements AppleFileSource abstract class CatalogEntry implements AppleFileSource
{ {
protected final PascalDisk parent; protected final PascalDisk parent;
String name; protected final String name;
int firstBlock; int firstBlock;
int lastBlock; // block AFTER last used block int lastBlock; // block AFTER last used block
int fileType; int fileType;
GregorianCalendar date; GregorianCalendar date;
int bytesUsedInLastBlock;
List<DiskAddress> blocks = new ArrayList<DiskAddress> (); List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
AbstractFile file; AbstractFile file;
@ -28,13 +29,21 @@ abstract class CatalogEntry implements AppleFileSource
firstBlock = HexFormatter.intValue (buffer[0], buffer[1]); firstBlock = HexFormatter.intValue (buffer[0], buffer[1]);
lastBlock = HexFormatter.intValue (buffer[2], buffer[3]); lastBlock = HexFormatter.intValue (buffer[2], buffer[3]);
// fileType = HexFormatter.intValue (buffer[4], buffer[5]); fileType = HexFormatter.intValue (buffer[4], buffer[5]);
fileType = buffer[4] & 0x0F; // fileType = buffer[4] & 0x0F;
name = HexFormatter.getPascalString (buffer, 6); name = HexFormatter.getPascalString (buffer, 6);
bytesUsedInLastBlock = HexFormatter.intValue (buffer[16], buffer[17]);
Disk disk = parent.getDisk (); Disk disk = parent.getDisk ();
for (int i = firstBlock; i < lastBlock; i++) for (int i = firstBlock; i < lastBlock; i++)
{
if (i >= 280)
{
System.out.printf ("CatalogEntry: block >= 280%n");
break;
}
blocks.add (disk.getDiskAddress (i)); blocks.add (disk.getDiskAddress (i));
}
} }
@Override @Override

View File

@ -15,6 +15,10 @@ class FileEntry extends CatalogEntry
date = HexFormatter.getPascalDate (buffer, 24); date = HexFormatter.getPascalDate (buffer, 24);
for (int i = firstBlock; i < lastBlock; i++) for (int i = firstBlock; i < lastBlock; i++)
{
if (i >= 280)
break;
switch (fileType) switch (fileType)
{ {
case 2: case 2:
@ -46,6 +50,7 @@ class FileEntry extends CatalogEntry
parent.sectorTypes[i] = parent.dataSector; parent.sectorTypes[i] = parent.dataSector;
break; break;
} }
}
} }
@Override @Override
@ -58,30 +63,32 @@ class FileEntry extends CatalogEntry
switch (fileType) switch (fileType)
{ {
case 3:
file = new PascalText (name, buffer);
break;
case 2: case 2:
file = new PascalCode (name, buffer); file = new PascalCode (name, buffer);
break; break;
case 3:
file = new PascalText (name, buffer);
break;
case 4: case 4:
file = new PascalInfo (name, buffer); file = new PascalInfo (name, buffer);
break; break;
case 0: // volume
break;
case 5: // data case 5: // data
if (name.equals ("SYSTEM.CHARSET")) if (name.equals ("SYSTEM.CHARSET"))
file = new Charset (name, buffer); file = new Charset (name, buffer);
else if (name.equals ("WT")) // only testing // else if (name.equals ("WT")) // only testing
file = new WizardryTitle (name, buffer); // file = new WizardryTitle (name, buffer);
else if (name.equals ("SYSTEM.RELOC"))
file = new Relocator (name, buffer);
else else
file = new DefaultAppleFile (name, buffer); file = new DefaultAppleFile (name, buffer);
break; break;
case 0: // volume
break;
default: // unknown default: // unknown
file = new DefaultAppleFile (name, buffer); file = new DefaultAppleFile (name, buffer);
} }

View File

@ -3,6 +3,7 @@ package com.bytezone.diskbrowser.pascal;
import java.awt.Color; import java.awt.Color;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
@ -19,11 +20,11 @@ public class PascalDisk extends AbstractFormattedDisk
{ {
static final int CATALOG_ENTRY_SIZE = 26; static final int CATALOG_ENTRY_SIZE = 26;
private final DateFormat df = DateFormat.getDateInstance (DateFormat.SHORT); private final DateFormat df = DateFormat.getDateInstance (DateFormat.SHORT);
private final VolumeEntry volume; private final VolumeEntry volumeEntry;
private final PascalCatalogSector diskCatalogSector; private final PascalCatalogSector diskCatalogSector;
final String[] fileTypes = 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 diskBootSector = new SectorType ("Boot", Color.lightGray);
SectorType catalogSector = new SectorType ("Catalog", Color.magenta); SectorType catalogSector = new SectorType ("Catalog", Color.magenta);
@ -56,7 +57,7 @@ public class PascalDisk extends AbstractFormattedDisk
byte[] data = new byte[CATALOG_ENTRY_SIZE]; byte[] data = new byte[CATALOG_ENTRY_SIZE];
System.arraycopy (buffer, 0, data, 0, 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++) for (int i = 0; i < 2; i++)
if (!disk.isSectorEmpty (i)) if (!disk.isSectorEmpty (i))
@ -69,7 +70,7 @@ public class PascalDisk extends AbstractFormattedDisk
freeBlocks.set (i, true); freeBlocks.set (i, true);
List<DiskAddress> sectors = new ArrayList<DiskAddress> (); List<DiskAddress> sectors = new ArrayList<DiskAddress> ();
for (int i = 2; i < volume.lastBlock; i++) for (int i = 2; i < volumeEntry.lastBlock; i++)
{ {
DiskAddress da = disk.getDiskAddress (i); DiskAddress da = disk.getDiskAddress (i);
if (!disk.isSectorEmpty (da)) if (!disk.isSectorEmpty (da))
@ -82,34 +83,34 @@ public class PascalDisk extends AbstractFormattedDisk
diskCatalogSector = new PascalCatalogSector (disk, buffer, sectors); diskCatalogSector = new PascalCatalogSector (disk, buffer, sectors);
DefaultMutableTreeNode root = getCatalogTreeRoot (); DefaultMutableTreeNode root = getCatalogTreeRoot ();
DefaultMutableTreeNode volumeNode = new DefaultMutableTreeNode (volume); DefaultMutableTreeNode volumeNode = new DefaultMutableTreeNode (volumeEntry);
root.add (volumeNode); root.add (volumeNode);
// read the catalog // read the catalog
List<DiskAddress> addresses = new ArrayList<DiskAddress> (); List<DiskAddress> addresses = new ArrayList<DiskAddress> ();
for (int i = 2; i < volume.lastBlock; i++) for (int i = 2; i < volumeEntry.lastBlock; i++)
addresses.add (disk.getDiskAddress (i)); addresses.add (disk.getDiskAddress (i));
buffer = disk.readSectors (addresses); buffer = disk.readSectors (addresses);
// loop through each catalog entry (what if there are deleted files?) // 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; int ptr = i * CATALOG_ENTRY_SIZE;
data = new byte[CATALOG_ENTRY_SIZE]; data = new byte[CATALOG_ENTRY_SIZE];
System.arraycopy (buffer, ptr, data, 0, CATALOG_ENTRY_SIZE); System.arraycopy (buffer, ptr, data, 0, CATALOG_ENTRY_SIZE);
FileEntry fe = new FileEntry (this, data); FileEntry fileEntry = new FileEntry (this, data);
fileEntries.add (fe); fileEntries.add (fileEntry);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (fe); DefaultMutableTreeNode node = new DefaultMutableTreeNode (fileEntry);
if (fe.fileType == 2) // PascalCode if (fileEntry.fileType == 2) // PascalCode
{ {
node.setAllowsChildren (true); node.setAllowsChildren (true);
PascalCode pc = (PascalCode) fe.getDataSource (); PascalCode pascalCode = (PascalCode) fileEntry.getDataSource ();
for (PascalSegment ps : pc) for (PascalSegment pascalSegment : pascalCode)
{ {
DefaultMutableTreeNode segmentNode = DefaultMutableTreeNode segmentNode = new DefaultMutableTreeNode (
new DefaultMutableTreeNode (new PascalCodeObject (this, ps, fe.firstBlock)); new PascalCodeObject (this, pascalSegment, fileEntry.firstBlock));
node.add (segmentNode); node.add (segmentNode);
segmentNode.setAllowsChildren (false); segmentNode.setAllowsChildren (false);
} }
@ -118,7 +119,7 @@ public class PascalDisk extends AbstractFormattedDisk
node.setAllowsChildren (false); node.setAllowsChildren (false);
volumeNode.add (node); 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); freeBlocks.set (j, false);
} }
@ -128,9 +129,10 @@ public class PascalDisk extends AbstractFormattedDisk
public static boolean isCorrectFormat (AppleDisk disk, boolean debug) public static boolean isCorrectFormat (AppleDisk disk, boolean debug)
{ {
disk.setInterleave (1); disk.setInterleave (1); // should only ever be Prodos
if (checkFormat (disk, debug)) if (checkFormat (disk, debug))
return true; return true;
disk.setInterleave (0); disk.setInterleave (0);
if (checkFormat (disk, debug)) if (checkFormat (disk, debug))
return true; return true;
@ -141,8 +143,8 @@ public class PascalDisk extends AbstractFormattedDisk
public static boolean checkFormat (AppleDisk disk, boolean debug) public static boolean checkFormat (AppleDisk disk, boolean debug)
{ {
byte[] buffer = disk.readSector (2); byte[] buffer = disk.readSector (2);
if (debug) // if (debug)
System.out.println (HexFormatter.format (buffer)); // System.out.println (HexFormatter.format (buffer));
int nameLength = HexFormatter.intValue (buffer[6]); int nameLength = HexFormatter.intValue (buffer[6]);
if (nameLength < 1 || nameLength > 7) if (nameLength < 1 || nameLength > 7)
{ {
@ -166,6 +168,14 @@ public class PascalDisk extends AbstractFormattedDisk
return false; // will only work for floppies! 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<DiskAddress> addresses = new ArrayList<DiskAddress> (); List<DiskAddress> addresses = new ArrayList<DiskAddress> ();
for (int i = 2; i < to; i++) for (int i = 2; i < to; i++)
addresses.add (disk.getDiskAddress (i)); addresses.add (disk.getDiskAddress (i));
@ -185,27 +195,21 @@ public class PascalDisk extends AbstractFormattedDisk
for (int i = 1; i <= files; i++) for (int i = 1; i <= files; i++)
{ {
int ptr = i * 26; int ptr = i * 26;
int a = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]); int firstBlock = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]);
int b = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]); int lastBlock = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]);
int c = HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]); int kind = HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]);
if (b < a) if (lastBlock < firstBlock)
return false; return false;
if (c == 0) if (kind == 0)
return false; return false;
nameLength = HexFormatter.intValue (buffer[ptr + 6]); nameLength = HexFormatter.intValue (buffer[ptr + 6]);
if (nameLength < 1 || nameLength > 15) if (nameLength < 1 || nameLength > 15)
return false; return false;
int lastByte = HexFormatter.intValue (buffer[ptr + 22], buffer[ptr + 23]);
GregorianCalendar date = HexFormatter.getPascalDate (buffer, 24);
if (debug) if (debug)
System.out.printf ("%4d %4d %d %s%n", a, b, c, System.out.printf ("%4d %4d %d %-15s %d %s%n", firstBlock, lastBlock, kind,
new String (buffer, ptr + 7, nameLength)); new String (buffer, ptr + 7, nameLength), lastByte, date);
}
int blocks = HexFormatter.intValue (buffer[14], buffer[15]);
if (blocks > 280)
{
if (debug)
System.out.printf ("Blocks > 280: %d%n", blocks);
return false;
} }
return true; return true;
@ -254,13 +258,16 @@ public class PascalDisk extends AbstractFormattedDisk
{ {
String newLine = String.format ("%n"); String newLine = String.format ("%n");
String newLine2 = newLine + newLine; String newLine2 = newLine + newLine;
String line = "---- --------------- ---- -------- ------- ---- ----" + newLine; String line =
String date = volume.date == null ? "--" : df.format (volume.date.getTime ()); "---- --------------- ---- -------- ------- ---- ----" + newLine;
String date =
volumeEntry.date == null ? "--" : df.format (volumeEntry.date.getTime ());
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append ("Disk : " + disk.getFile ().getAbsolutePath () + newLine2); 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 ("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); text.append (line);
int usedBlocks = 6; int usedBlocks = 6;
@ -271,14 +278,15 @@ public class PascalDisk extends AbstractFormattedDisk
usedBlocks += size; usedBlocks += size;
date = ce.date == null ? "--" : df.format (ce.date.getTime ()); date = ce.date == null ? "--" : df.format (ce.date.getTime ());
int bytes = (size - 1) * 512 + ce.bytesUsedInLastBlock; int bytes = (size - 1) * 512 + ce.bytesUsedInLastBlock;
text.append (String.format (" %3d %-15s %s %8s %,8d $%03X $%03X%n", size, text.append (String.format ("%4d %-15s %s %8s %,8d $%03X $%03X%n", size,
ce.name, fileTypes[ce.fileType], date, bytes, ce.firstBlock, ce.name, fileTypes[ce.fileType], date, bytes,
ce.lastBlock)); ce.firstBlock, ce.lastBlock));
} }
text.append (line); text.append (line);
text.append (String.format ("Blocks free : %3d Blocks used : %3d Total blocks : %3d%n", text.append (String.format (
(volume.totalBlocks - usedBlocks), usedBlocks, "Blocks free : %3d Blocks used : %3d Total blocks : %3d%n",
volume.totalBlocks)); (volumeEntry.totalBlocks - usedBlocks), usedBlocks,
return new DefaultAppleFileSource (volume.name, text.toString (), this); volumeEntry.totalBlocks));
return new DefaultAppleFileSource (volumeEntry.name, text.toString (), this);
} }
} }

View File

@ -8,15 +8,26 @@ class VolumeEntry extends CatalogEntry
{ {
final int totalFiles; final int totalFiles;
final int totalBlocks; 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) public VolumeEntry (PascalDisk parent, byte[] buffer)
{ {
super (parent, 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]); totalFiles = HexFormatter.intValue (buffer[16], buffer[17]);
firstBlock = HexFormatter.intValue (buffer[18], buffer[19]); firstBlock = HexFormatter.intValue (buffer[18], buffer[19]); // 0
date = HexFormatter.getPascalDate (buffer, 20); date = HexFormatter.getPascalDate (buffer, 20); // 2 bytes
// bytes 0x16 - 0x19 are unused
} }
@Override @Override