dmolony-DiskBrowser/src/com/bytezone/diskbrowser/applefile/PascalSegment.java

206 lines
7.5 KiB
Java
Raw Normal View History

2015-06-01 09:35:51 +00:00
package com.bytezone.diskbrowser.applefile;
import java.util.ArrayList;
import java.util.List;
2016-02-24 21:11:14 +00:00
import com.bytezone.diskbrowser.utilities.FileFormatException;
import com.bytezone.diskbrowser.utilities.HexFormatter;
2015-06-01 09:35:51 +00:00
public class PascalSegment extends AbstractFile implements PascalConstants
{
2016-02-29 01:54:44 +00:00
private final int segmentNoHeader;
private int segmentNoBody;
2016-07-18 08:55:32 +00:00
2016-08-04 06:08:19 +00:00
public int blockNo;
public int newBlockNo;
2015-06-01 09:35:51 +00:00
public final int size;
2016-07-18 08:55:32 +00:00
2016-02-29 01:54:44 +00:00
private final int segKind;
private final int textAddress;
private final int machineType;
private final int version;
private final int intrinsSegs1;
private final int intrinsSegs2;
private final int slot;
private int totalProcedures;
2016-07-18 08:55:32 +00:00
private List<PascalProcedure> procedures;
2016-08-04 06:08:19 +00:00
private static final List<Redirection> redirections = new ArrayList<Redirection> ();
static
{
2016-08-04 12:00:53 +00:00
// somehow the offsets should match the data in SYSTEM.RELOC
2016-08-04 06:08:19 +00:00
redirections.add (new Redirection ("WIZARDRY", 0x01, 0x1C66, 0x01));
2016-08-04 12:00:53 +00:00
redirections.add (new Redirection ("KANJIREA", 0x3F, 0x104E, 0x10));
2016-08-04 06:08:19 +00:00
redirections.add (new Redirection ("UTILITIE", 0x48, 0x1598, 0x19));
2016-08-04 12:00:53 +00:00
redirections.add (new Redirection ("SHOPS ", 0x53, 0x0BE2, 0x24));
redirections.add (new Redirection ("CAMP ", 0x70, 0x24CA, 0x2A));
redirections.add (new Redirection ("DOCOPY ", 0x83, 0x07A0, 0x3D));
redirections.add (new Redirection ("DOCACHE ", 0x87, 0x072E, 0x41));
2016-08-04 06:08:19 +00:00
}
2015-06-01 09:35:51 +00:00
public PascalSegment (String name, byte[] fullBuffer, int seq)
{
2016-07-18 08:55:32 +00:00
super (name, fullBuffer); // sets this.buffer to the full buffer temporarily
2015-06-01 09:35:51 +00:00
this.slot = seq;
this.blockNo = HexFormatter.intValue (fullBuffer[seq * 4], fullBuffer[seq * 4 + 1]);
this.size = HexFormatter.intValue (fullBuffer[seq * 4 + 2], fullBuffer[seq * 4 + 3]);
2016-07-18 08:55:32 +00:00
2016-08-04 06:08:19 +00:00
for (Redirection redirection : redirections)
if (redirection.matches (name, blockNo, size))
{
newBlockNo = redirection.newOffset;
break;
}
2016-08-02 10:37:27 +00:00
segKind = HexFormatter.intValue (fullBuffer[0xC0 + seq * 2],
2016-08-04 06:08:19 +00:00
fullBuffer[0xC0 + seq * 2 + 1]);
2016-08-03 11:32:47 +00:00
2016-08-02 10:37:27 +00:00
textAddress = HexFormatter.intValue (fullBuffer[0xE0 + seq * 2],
2016-08-04 06:08:19 +00:00
fullBuffer[0xE0 + seq * 2 + 1]);
2016-08-03 11:32:47 +00:00
2016-08-04 06:08:19 +00:00
// segment 1 is the main segment, 2-6 are used by the system, and 7
2016-08-04 12:00:53 +00:00
// onwards is for the program
2016-08-03 11:32:47 +00:00
this.segmentNoHeader = fullBuffer[0x100 + seq * 2] & 0xFF;
2015-06-01 09:35:51 +00:00
int flags = fullBuffer[0x101 + seq * 2] & 0xFF;
2016-08-04 12:00:53 +00:00
// 0 unknown,
// 1 positive byte sex p-code
// 2 negative byte sex p-code (apple pascal)
// 3-9 6502 code (7 = apple 6502)
2015-06-01 09:35:51 +00:00
machineType = flags & 0x0F;
2016-08-04 12:00:53 +00:00
2015-06-01 09:35:51 +00:00
version = (flags & 0xD0) >> 5;
2016-08-04 12:00:53 +00:00
2016-08-02 10:37:27 +00:00
intrinsSegs1 = HexFormatter.intValue (fullBuffer[0x120 + seq * 4],
2016-08-04 06:08:19 +00:00
fullBuffer[0x120 + seq * 4 + 1]);
2016-02-29 01:54:44 +00:00
intrinsSegs2 = HexFormatter.intValue (fullBuffer[0x120 + seq * 4 + 2],
2016-08-04 06:08:19 +00:00
fullBuffer[0x120 + seq * 4 + 3]);
2015-06-01 09:35:51 +00:00
int offset = blockNo * 512;
2016-08-04 06:08:19 +00:00
if (newBlockNo > 0)
offset = newBlockNo * 512;
2016-08-02 10:37:27 +00:00
// 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));
2015-06-01 09:35:51 +00:00
if (offset < fullBuffer.length)
{
2016-02-29 01:54:44 +00:00
buffer = new byte[size]; // replaces this.buffer with the segment buffer only
2016-08-04 06:08:19 +00:00
System.arraycopy (fullBuffer, offset, buffer, 0, size);
2015-06-01 09:35:51 +00:00
totalProcedures = buffer[size - 1] & 0xFF;
segmentNoBody = buffer[size - 2] & 0xFF;
2016-07-18 08:55:32 +00:00
if (segmentNoHeader == 0)
System.out.printf ("Zero segment header in %s seq %d%n", name, seq);
else if (segmentNoBody != segmentNoHeader)
2016-08-04 06:08:19 +00:00
System.out.println (
"Segment number mismatch : " + segmentNoBody + " / " + segmentNoHeader);
2015-06-01 09:35:51 +00:00
}
else
{
2016-08-03 11:32:47 +00:00
// System.out.printf ("Error in blocksize %,d > %,d for pascal disk%n", offset,
// fullBuffer.length);
2015-06-01 09:35:51 +00:00
throw new FileFormatException ("Error in PascalSegment");
}
}
private void buildProcedureList ()
{
procedures = new ArrayList<PascalProcedure> (totalProcedures);
for (int i = 1; i <= totalProcedures; i++)
procedures.add (new PascalProcedure (buffer, i));
}
public String toText ()
{
2016-08-04 06:08:19 +00:00
int sizeInBlocks = (size - 1) / 512 + 1;
String newBlock = newBlockNo > 0 ? String.format ("%02X + %02X = %02X", newBlockNo,
sizeInBlocks, (newBlockNo + sizeInBlocks)) : "";
return String.format (
" %2d %02X %02X %04X %,6d %-8s %-15s%3d "
+ "%02X %d %d %d %d %s",
slot, blockNo, sizeInBlocks, size, size, name, SegmentKind[segKind], textAddress,
segmentNoHeader, machineType, version, intrinsSegs1, intrinsSegs2, newBlock);
2015-06-01 09:35:51 +00:00
}
@Override
public String getText ()
{
if (procedures == null)
buildProcedureList ();
StringBuilder text = new StringBuilder ();
String title = "Segment - " + name;
text.append (title + "\n"
2016-08-02 10:37:27 +00:00
+ "===============================".substring (0, title.length ()) + "\n\n");
2016-08-03 11:32:47 +00:00
String warning = segmentNoBody == segmentNoHeader ? ""
: String.format (" (%02X in header)", segmentNoHeader);
2015-06-01 09:35:51 +00:00
text.append (String.format ("Address........ %02X%n", blockNo));
text.append (String.format ("Length......... %04X%n", buffer.length));
text.append (String.format ("Machine type... %d%n", machineType));
text.append (String.format ("Version........ %d%n", version));
2016-08-03 11:32:47 +00:00
text.append (String.format ("Segment........ %02X%s%n", segmentNoBody, warning));
2015-06-01 09:35:51 +00:00
text.append (String.format ("Total procs.... %d%n", procedures.size ()));
text.append ("\nProcedure Dictionary\n====================\n\n");
int len = procedures.size () * 2 + 2;
if (false)
text.append (HexFormatter.format (buffer, buffer.length - len, len) + "\n\n");
text.append ("Proc Offset Lvl Entry Exit Parm Data Proc header\n");
2016-08-04 06:08:19 +00:00
text.append (
"---- ------ --- ----- ---- ---- ---- --------------------\n");
2015-06-01 09:35:51 +00:00
for (PascalProcedure procedure : procedures)
{
if (procedure.valid)
{
int address = size - procedure.slot * 2 - 2;
2016-08-04 06:08:19 +00:00
text.append (String.format (
" %3d %04X %3d %04X %04X %04X %04X (%04X - %04X = %04X)%n",
procedure.procedureNo, procedure.offset, procedure.procLevel,
procedure.codeStart, procedure.codeEnd, procedure.parmSize,
procedure.dataSize, address, procedure.offset, procedure.procOffset));
2015-06-01 09:35:51 +00:00
}
else
2016-08-03 11:32:47 +00:00
text.append (String.format (" %3d %04X%n", procedure.slot, procedure.offset));
2015-06-01 09:35:51 +00:00
}
text.append ("\nStrings\n=======\n");
for (PascalProcedure pp : procedures)
{
List<PascalCodeStatement> strings = pp.extractStrings ();
for (PascalCodeStatement cs : strings)
2016-08-04 06:08:19 +00:00
text.append (
String.format (" %2d %04X %s%n", pp.procedureNo, cs.ptr, cs.text));
2015-06-01 09:35:51 +00:00
}
for (PascalProcedure procedure : procedures)
if (procedure.valid)
text.append (procedure);
2016-08-04 12:00:53 +00:00
2015-06-01 09:35:51 +00:00
return text.toString ();
}
2016-08-04 06:08:19 +00:00
}
class Redirection
{
int oldOffset;
int newOffset;
int length;
String name;
public Redirection (String name, int oldOffset, int length, int newOffset)
{
2016-08-04 12:00:53 +00:00
this.name = name.trim ();
2016-08-04 06:08:19 +00:00
this.oldOffset = oldOffset;
this.newOffset = newOffset;
this.length = length;
}
public boolean matches (String name, int offset, int length)
{
return this.name.equals (name) && this.oldOffset == offset && this.length == length;
}
2015-06-01 09:35:51 +00:00
}