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-08-06 00:02:45 +00:00
|
|
|
private final static int BLOCK_SIZE = 512;
|
2016-08-05 08:40:32 +00:00
|
|
|
final int segmentNoHeader;
|
2016-02-29 01:54:44 +00:00
|
|
|
private int segmentNoBody;
|
2016-08-14 08:41:19 +00:00
|
|
|
// private final int blockOffset;
|
2016-08-09 04:15:44 +00:00
|
|
|
// private final Relocator relocator;
|
2016-08-14 08:41:19 +00:00
|
|
|
boolean debug = false;
|
2016-07-18 08:55:32 +00:00
|
|
|
|
2016-08-04 06:08:19 +00:00
|
|
|
public int blockNo;
|
2016-08-06 00:02:45 +00:00
|
|
|
// 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-14 08:41:19 +00:00
|
|
|
// private List<MultiDiskAddress> addresses;
|
2016-08-04 06:08:19 +00:00
|
|
|
|
2016-08-09 04:15:44 +00:00
|
|
|
public PascalSegment (String name, byte[] fullBuffer, int seq, int blockOffset)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
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;
|
2016-08-14 08:41:19 +00:00
|
|
|
// this.blockOffset = blockOffset;
|
2016-08-09 04:15:44 +00:00
|
|
|
// this.relocator = relocator;
|
2016-08-06 00:02:45 +00:00
|
|
|
|
2015-06-01 09:35:51 +00:00
|
|
|
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-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-06 00:02:45 +00:00
|
|
|
|
2016-08-09 04:15:44 +00:00
|
|
|
// if (relocator != null)
|
|
|
|
// {
|
|
|
|
// // if (segmentNoHeader > 1)
|
|
|
|
// // {
|
|
|
|
// int sizeInBlocks = (size - 1) / BLOCK_SIZE + 1;
|
|
|
|
// int targetBlock = blockNo + blockOffset;
|
|
|
|
// addresses = relocator.getMultiDiskAddress (name, targetBlock, sizeInBlocks);
|
|
|
|
// if (addresses.size () > 0)
|
|
|
|
// {
|
|
|
|
// MultiDiskAddress multiDiskAddress = addresses.get (0);
|
|
|
|
// if (multiDiskAddress.diskNumber == 1)
|
|
|
|
// offset = (multiDiskAddress.physicalBlockNumber - blockOffset) * BLOCK_SIZE;
|
|
|
|
// else
|
|
|
|
// offset = -1;
|
|
|
|
// }
|
|
|
|
// // }
|
|
|
|
// }
|
2016-08-06 00:02:45 +00:00
|
|
|
|
|
|
|
if (offset < 0)
|
|
|
|
{
|
|
|
|
buffer = new byte[0];
|
|
|
|
}
|
2016-08-14 08:41:19 +00:00
|
|
|
else if ((offset + size) < fullBuffer.length)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
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
|
|
|
|
2016-08-14 08:41:19 +00:00
|
|
|
if (debug)
|
|
|
|
if (segmentNoHeader == 0)
|
|
|
|
System.out.printf ("Zero segment header in %s seq %d%n", name, seq);
|
|
|
|
else if (segmentNoBody != segmentNoHeader)
|
|
|
|
System.out.println (
|
|
|
|
"Segment number mismatch : " + segmentNoBody + " / " + segmentNoHeader);
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw new FileFormatException ("Error in PascalSegment");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-14 08:41:19 +00:00
|
|
|
// void setMultiDiskAddresses (List<MultiDiskAddress> addresses)
|
|
|
|
// {
|
|
|
|
// this.addresses = addresses;
|
|
|
|
// }
|
2016-08-06 00:02:45 +00:00
|
|
|
|
2015-06-01 09:35:51 +00:00
|
|
|
private void buildProcedureList ()
|
|
|
|
{
|
|
|
|
procedures = new ArrayList<PascalProcedure> (totalProcedures);
|
|
|
|
|
|
|
|
for (int i = 1; i <= totalProcedures; i++)
|
|
|
|
procedures.add (new PascalProcedure (buffer, i));
|
|
|
|
}
|
|
|
|
|
2016-08-06 00:02:45 +00:00
|
|
|
public String toText ()
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
2016-08-06 00:02:45 +00:00
|
|
|
int sizeInBlocks = (size - 1) / BLOCK_SIZE + 1;
|
2016-08-05 08:40:32 +00:00
|
|
|
|
2016-08-04 06:08:19 +00:00
|
|
|
return String.format (
|
2016-08-05 21:29:27 +00:00
|
|
|
" %2d %02X %02X %04X %-8s %-15s%3d " + "%02X %d %d %d %d %s",
|
|
|
|
slot, blockNo, sizeInBlocks, size, name, SegmentKind[segKind], textAddress,
|
|
|
|
segmentNoHeader, machineType, version, intrinsSegs1, intrinsSegs2,
|
2016-08-06 00:02:45 +00:00
|
|
|
getMultiDiskAddresses ());
|
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 ? ""
|
2016-08-06 07:17:16 +00:00
|
|
|
: String.format (" (%02X in routine)", segmentNoBody);
|
2015-06-01 09:35:51 +00:00
|
|
|
text.append (String.format ("Address........ %02X%n", blockNo));
|
2016-08-06 07:17:16 +00:00
|
|
|
// if (addresses != null)
|
|
|
|
text.append (String.format ("Multi disk .... %s%n", getMultiDiskAddresses ()));
|
2015-06-01 09:35:51 +00:00
|
|
|
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-06 07:17:16 +00:00
|
|
|
text.append (String.format ("Segment........ %02X%s%n", segmentNoHeader, 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
|
|
|
|
2016-08-06 00:02:45 +00:00
|
|
|
private String getMultiDiskAddresses ()
|
2016-08-04 06:08:19 +00:00
|
|
|
{
|
2016-08-06 00:02:45 +00:00
|
|
|
String multiDiskAddressText = "";
|
|
|
|
int sizeInBlocks = (size - 1) / BLOCK_SIZE + 1;
|
2016-08-04 06:08:19 +00:00
|
|
|
|
2016-08-06 07:17:16 +00:00
|
|
|
// if (segmentNoHeader == 1) // main segment
|
|
|
|
// {
|
|
|
|
// multiDiskAddressText = String.format ("1:%03X", (blockNo + blockOffset));
|
|
|
|
// }
|
|
|
|
// else
|
2016-08-09 04:15:44 +00:00
|
|
|
// if (relocator != null)
|
|
|
|
// {
|
|
|
|
// int targetBlock = blockNo + blockOffset;
|
|
|
|
// List<MultiDiskAddress> addresses =
|
|
|
|
// relocator.getMultiDiskAddress (name, targetBlock, sizeInBlocks);
|
|
|
|
// if (addresses.isEmpty ())
|
|
|
|
// multiDiskAddressText = ".";
|
|
|
|
// else
|
|
|
|
// {
|
|
|
|
// StringBuilder locations = new StringBuilder ();
|
|
|
|
// for (MultiDiskAddress multiDiskAddress : addresses)
|
|
|
|
// locations.append (multiDiskAddress.toString () + ", ");
|
|
|
|
// if (locations.length () > 2)
|
|
|
|
// {
|
|
|
|
// locations.deleteCharAt (locations.length () - 1);
|
|
|
|
// locations.deleteCharAt (locations.length () - 1);
|
|
|
|
// }
|
|
|
|
// multiDiskAddressText = locations.toString ();
|
|
|
|
// }
|
|
|
|
// }
|
2016-08-06 00:02:45 +00:00
|
|
|
return multiDiskAddressText;
|
2016-08-04 06:08:19 +00:00
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|