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,9 +4,11 @@ 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;
@ -29,16 +31,26 @@ public class PascalCode extends AbstractFile implements PascalConstants, Iterabl
{ {
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]);
System.out.printf ("%s %s %d %n", HexFormatter.getHexString (buffer, i * 4, 4),
codeName, size);
if (size > 0) if (size > 0)
{ {
if (codeName.length () == 0) if (codeName.length () == 0)
codeName = "<NULL" + nonameCounter++ + ">"; codeName = "<NULL" + nonameCounter++ + ">";
try
{
segments.add (new PascalSegment (codeName, buffer, i)); segments.add (new PascalSegment (codeName, buffer, i));
} }
catch (FileFormatException e)
{
System.out.println ("Bad segment");
}
}
} }
comment = HexFormatter.getPascalString (buffer, 0x1B0); comment = HexFormatter.getPascalString (buffer, 0x1B0);
} }
@Override
public String getText () public String getText ()
{ {
StringBuilder text = new StringBuilder (getHeader ()); StringBuilder text = new StringBuilder (getHeader ());
@ -62,6 +74,7 @@ public class PascalCode extends AbstractFile implements PascalConstants, Iterabl
return "Name : " + name + "\n\n"; return "Name : " + name + "\n\n";
} }
@Override
public Iterator<PascalSegment> iterator () public Iterator<PascalSegment> iterator ()
{ {
return segments.iterator (); return segments.iterator ();

View File

@ -75,7 +75,8 @@ public class PascalCodeStatement implements PascalConstants
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;
@ -157,7 +158,8 @@ public class PascalCodeStatement implements PascalConstants
{ {
// 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
- ((buffer[address + 1] & 0xFF) * 256 + (buffer[address] & 0xFF));
extras = String.format ("$%04X", ptr2); extras = String.format ("$%04X", ptr2);
jumps.add (new Jump (ptr, ptr2)); jumps.add (new Jump (ptr, ptr2));
} }
@ -184,8 +186,11 @@ public class PascalCodeStatement implements PascalConstants
// CSP // CSP
case 158: case 158:
p1 = buffer[ptr + 1]; p1 = buffer[ptr + 1] & 0xFF;
if (p1 < CSP.length)
description = "Call standard procedure - " + CSP[p1]; description = "Call standard procedure - " + CSP[p1];
else
description = "Call standard procedure - index out of bounds";
break; break;
// Non-integer comparisons // Non-integer comparisons
@ -195,7 +200,7 @@ public class PascalCodeStatement implements PascalConstants
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);
@ -254,12 +259,14 @@ public class PascalCodeStatement implements PascalConstants
description = description.replaceFirst (":3", p3); description = description.replaceFirst (":3", p3);
} }
@Override
public String toString () public String toString ()
{ {
String hex = getHex (buffer, ptr, length > 4 ? 4 : length); String hex = getHex (buffer, ptr, length > 4 ? 4 : length);
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append (String.format ("%2s%05X: %-11s %-6s %-8s %s%n", jumpTarget ? "->" : "", ptr, text.append (String.format ("%2s%05X: %-11s %-6s %-8s %s%n",
hex, mnemonic, extras, description)); jumpTarget ? "->" : "", ptr, hex, mnemonic, extras,
description));
if (length > 4) if (length > 4)
{ {
int bytesLeft = length - 4; int bytesLeft = length - 4;
@ -319,6 +326,7 @@ public class PascalCodeStatement implements PascalConstants
this.caseJump = true; this.caseJump = true;
} }
@Override
public String toString () public String toString ()
{ {
if (caseJump) if (caseJump)

View File

@ -6,11 +6,12 @@ public interface PascalConstants
{ "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 =
// //
@ -20,74 +21,48 @@ public interface PascalConstants
// 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)",
"Add reals - push ToS + ToS-1",
"Logical AND",
"Set difference - push difference of sets ToS-1 and ToS", "Set difference - push difference of sets ToS-1 and ToS",
"Divide integers - push ToS-1 / ToS", "Divide integers - push ToS-1 / ToS", "Divide reals - push ToS-1 / ToS",
"Divide reals - push ToS-1 / ToS",
"Check subrange bounds - assert ToS-1 <= ToS-2 <= ToS, pop ToS, pop ToS-1", "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 next-to-ToS - push integer ToS-1 after converting to a real",
"Float ToS - push integer ToS after converting to a float", "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 Membership - if int ToS-1 is in set ToS, push true, else push false",
"Set Intersection - push TOS AND TOS-1", "Set Intersection - push TOS AND TOS-1", "Logical OR",
"Logical OR", "Modulo integers - push ToS-1 % ToS", "Multiply TOS by TOS-1",
"Modulo integers - push ToS-1 % ToS",
"Multiply TOS by TOS-1",
"Multiply reals - push ToS-1 * ToS", "Multiply reals - push ToS-1 * ToS",
"Negate Integer - push two's complement of ToS", "Negate Integer - push two's complement of ToS",
"Negate real - push -((real)ToS)", "Negate real - push -((real)ToS)", "Logical Not - push one's complement of ToS",
"Logical Not - push one's complement of ToS", "Build a subrange set", "Subtract Integers push ToS-1 - ToS",
"Build a subrange set", "Subtract reals - push ToS-1 - ToS", "Build a singleton set",
"Subtract Integers push ToS-1 - ToS", "Square integer - push ToS ^ 2", "Square real - push ToS ^ 2",
"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", "Store indirect word - store ToS into word pointed to by ToS-1",
"Index string array - push &(*ToS-1 + ToS)", "Index string array - push &(*ToS-1 + ToS)",
"Set union - push union of sets ToS OR ToS-1", "Set union - push union of sets ToS OR ToS-1",
"Load extended word - push word at segment :1+:2", "Load extended word - push word at segment :1+:2",
"Call Standard Procedure #:1 - ", "Call Standard Procedure #:1 - ", "Load Constant NIL", "Adjust set",
"Load Constant NIL", "Jump if ToS false", "Increment field ptr - push ToS+:1",
"Adjust set", "Static index and load word", "Compute word pointer from ToS-1 + ToS * :1 words",
"Jump if ToS false", "Load Global - push (BASE+:1)", "Load constant string address",
"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", "Load extended address - push address of word at segment :1+:2",
"Move words - transfer :1 words from *ToS to *ToS-1", "Move words - transfer :1 words from *ToS to *ToS-1",
"Load Global Word - push BASE+:1", "Load Global Word - push BASE+:1", "String Assign", "Store TOS into BASE+:1",
"String Assign", "Case Jump - :1::2, Error: :3", "Return from non-base procedure (pass :1 words)",
"Store TOS into BASE+:1", "Call intermediate procedure #:1", "ToS-1 == ToS", "ToS-1 >= ToS", "ToS-1 > ToS",
"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 Intermediate Address - push :1th activation record +:2 bytes",
"Load multi-word constant - :1 words", "Load multi-word constant - :1 words", "ToS-1 <= ToS", "ToS-1 < ToS",
"ToS-1 <= ToS", "Load Intermediate Word - push :1th activation record +:2 bytes", "ToS-1 <> ToS",
"ToS-1 < ToS", "Store intermediate word - store TOS into :2, traverse :1", "Unconditional jump",
"Load Intermediate Word - push :1th activation record +:2 bytes", "Load Packed Field - push *ToS", "Store into packed field",
"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", "Load multiple words - push block of unsigned bytes at *ToS",
"Store multiple words - store block of UB at ToS to *ToS-1", "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", "Load Byte - index the byte pointer ToS-1 by integer index ToS and push that byte",
@ -112,7 +87,6 @@ public interface PascalConstants
"", "", "", "", "", "", "", "", "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

@ -67,6 +67,12 @@ public class PascalProcedure
while (ptr < max) 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); PascalCodeStatement cs = new PascalCodeStatement (buffer, ptr, procOffset);
if (cs.length <= 0) if (cs.length <= 0)
{ {
@ -88,8 +94,8 @@ public class PascalProcedure
{ {
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);
} }
@ -122,6 +128,7 @@ public class PascalProcedure
return strings; return strings;
} }
@Override
public String toString () public String toString ()
{ {
if (!valid) if (!valid)
@ -131,12 +138,15 @@ public class PascalProcedure
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,
procLevel & 0xFF));
text.append (String.format ("Proc no.....%5d %02X%n", procedureNo, procedureNo)); text.append (String.format ("Proc no.....%5d %02X%n", procedureNo, procedureNo));
text.append (String.format ("Code entry..%5d %04X (%04X - %04X = %04X)%n", codeStart, text.append (String.format ("Code entry..%5d %04X (%04X - %04X = %04X)%n",
codeStart, (procOffset - 2), codeStart, (procOffset - codeStart - 2))); codeStart, codeStart, (procOffset - 2), codeStart,
(procOffset - codeStart - 2)));
text.append (String.format ("Code exit...%5d %04X", codeEnd, codeEnd)); text.append (String.format ("Code exit...%5d %04X", codeEnd, codeEnd));
if (codeEnd > 0) if (codeEnd > 0)
text.append (String.format (" (%04X - %04X = %04X)%n", (procOffset - 4), codeEnd, text.append (String.format (" (%04X - %04X = %04X)%n", (procOffset - 4), codeEnd,
@ -153,7 +163,12 @@ public class PascalProcedure
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)
{
if (assembler != null)
text.append (assembler.getAssembler () + "\n"); text.append (assembler.getAssembler () + "\n");
else
text.append ("Null assembler in PascalProcedure");
}
else else
{ {
for (PascalCodeStatement cs : statements) for (PascalCodeStatement cs : statements)
@ -165,8 +180,8 @@ public class PascalProcedure
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));
} }
} }
} }

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
@ -61,7 +64,8 @@ public class PascalSegment extends AbstractFile implements PascalConstants
} }
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,8 +80,8 @@ 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);
} }
@ -119,8 +123,9 @@ public class PascalSegment extends AbstractFile implements PascalConstants
+ "%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,14 +29,22 @@ 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
public boolean contains (DiskAddress da) public boolean contains (DiskAddress da)

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:
@ -47,6 +51,7 @@ class FileEntry extends CatalogEntry
break; break;
} }
} }
}
@Override @Override
public AbstractFile getDataSource () public AbstractFile getDataSource ()
@ -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,7 +20,7 @@ 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 =
@ -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