230 lines
7.3 KiB
Java
230 lines
7.3 KiB
Java
package com.bytezone.diskbrowser.applefile;
|
|
|
|
import static com.bytezone.diskbrowser.utilities.Utility.getShort;
|
|
|
|
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
|
import com.bytezone.diskbrowser.utilities.Utility;
|
|
|
|
// -----------------------------------------------------------------------------------//
|
|
public class CPMBasicFile extends BasicProgram
|
|
// -----------------------------------------------------------------------------------//
|
|
{
|
|
String[] tokens = { //
|
|
"", "END", "FOR", "NEXT", "DATA", "INPUT", "DIM", "READ", // 0x80
|
|
"LET", "GOTO", "RUN", "IF", "RESTORE", "GOSUB", "RETURN", "REM", // 0x88
|
|
"STOP", "PRINT", "CLEAR", "LIST", "NEW", "ON", "DEF", "POKE", // 0x90
|
|
"", "", "", "LPRINT", "LLIST", "WIDTH", "ELSE", "", // 0x98
|
|
"", "SWAP", "ERASE", "", "ERROR", "RESUME", "DELETE", "", // 0xA0
|
|
"RENUM", "DEFSTR", "DEFINT", "", "DEFDBL", "LINE", "", "WHILE", // 0xA8
|
|
"WEND", "CALL", "WRITE", "COMMON", "CHAIN", // 0xB0
|
|
"OPTION", "RANDOMIZE", "SYSTEM", // 0xB5
|
|
"OPEN", "FIELD", "GET", "PUT", "CLOSE", "LOAD", "MERGE", "", // 0xB8
|
|
"NAME", "KILL", "LSET", "RSET", "SAVE", "RESET", "TEXT", "HOME", // 0xC0
|
|
"VTAB", "HTAB", "INVERSE", "NORMAL", "", "", "", "", // 0xC8
|
|
"", "", "", "", "", "WAIT", "", "", // 0xD0
|
|
"", "", "", "", "", "TO", "THEN", "TAB(", // 0xD8
|
|
"STEP", "USR", "FN", "SPC(", "", "ERL", "ERR", "STRING$", // 0xE0
|
|
"USING", "INSTR", "'", "VARPTR", "", "", "INKEY$", ">", // 0xE8
|
|
"=", "<", "+", "-", "*", "/", "", "AND", // 0xF0
|
|
"OR", "", "", "", "MOD", "/", "", "", // 0xF8
|
|
};
|
|
|
|
String[] functions = { //
|
|
"", "LEFT$", "RIGHT$", "MID$", "SGN", "INT", "ABS", "SQR", // 0x80
|
|
"RND", "SIN", "LOG", "EXP", "COS", "TAN", "ATN", "FRE", // 0x88
|
|
"POS", "LEN", "STR$", "VAL", "ASC", "CHR$", "PEEK", "SPACE$", // 0x90
|
|
"OCT$", "HEX$", "LPOS", "CINT", "CSNG", "CDBL", "FIX", "", // 0x98
|
|
"", "", "", "", "", "", "", "", // 0xA0
|
|
"", "", "CVI", "CVS", "CVD", "", "EOF", "LOC", // 0xA8
|
|
"", "MKI$", "MKS$", "MKD$", // 0xB0
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
public CPMBasicFile (String name, byte[] buffer)
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
super (name, buffer);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
@Override
|
|
public String getText ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
if (basicPreferences.showHeader)
|
|
text.append ("Name : " + name + "\n\n");
|
|
|
|
int ptr = 5;
|
|
while (buffer[ptr] != 0)
|
|
ptr++;
|
|
|
|
if (showDebugText)
|
|
return debugText ();
|
|
|
|
ptr = 1;
|
|
while (ptr < buffer.length)
|
|
{
|
|
int nextAddress = getShort (buffer, ptr);
|
|
|
|
if (nextAddress == 0)
|
|
break;
|
|
|
|
int lineNumber = getShort (buffer, ptr + 2);
|
|
|
|
text.append (String.format (" %d ", lineNumber));
|
|
ptr += 4;
|
|
|
|
while (true)
|
|
{
|
|
int val = buffer[ptr++] & 0xFF;
|
|
|
|
if (val == 0)
|
|
break;
|
|
|
|
if ((val & 0x80) != 0)
|
|
{
|
|
if (val == 0xFF)
|
|
{
|
|
val = buffer[ptr++] & 0xFF;
|
|
String token = functions[val & 0x7F];
|
|
if (token.length () == 0)
|
|
token = String.format ("<FF %02X>", val);
|
|
text.append (token);
|
|
}
|
|
else
|
|
{
|
|
String token = tokens[val & 0x7F];
|
|
if (token.length () == 0)
|
|
token = String.format ("<%02X>", val);
|
|
text.append (token);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (val >= 0x20 && val <= 0x7E) // printable
|
|
{
|
|
// check for stupid apostrophe comment
|
|
if (val == 0x3A && ptr + 1 < buffer.length && buffer[ptr] == (byte) 0x8F
|
|
&& buffer[ptr + 1] == (byte) 0xEA)
|
|
{
|
|
text.append ("'");
|
|
ptr += 2;
|
|
}
|
|
else if (val == 0x3A && ptr < buffer.length && buffer[ptr] == (byte) 0x9E)
|
|
{
|
|
// ignore colon before ELSE
|
|
}
|
|
else
|
|
text.append (String.format ("%s", (char) val));
|
|
continue;
|
|
}
|
|
|
|
if (val >= 0x11 && val <= 0x1A) // inline numbers
|
|
{
|
|
text.append (val - 0x11);
|
|
continue;
|
|
}
|
|
|
|
switch (val)
|
|
{
|
|
case 0x07:
|
|
text.append ("<BELL>");
|
|
break;
|
|
|
|
case 0x09:
|
|
text.append (" ");
|
|
break;
|
|
|
|
case 0x0A:
|
|
text.append ("\n ");
|
|
break;
|
|
|
|
case 0x0C:
|
|
text.append ("&H" + String.format ("%X", Utility.getShort (buffer, ptr)));
|
|
ptr += 2;
|
|
break;
|
|
|
|
case 0x0E: // same as 0x1C ??
|
|
text.append (Utility.getShort (buffer, ptr));
|
|
ptr += 2;
|
|
break;
|
|
|
|
case 0x0F:
|
|
text.append (buffer[ptr++] & 0xFF);
|
|
break;
|
|
|
|
case 0x1C: // same as 0x0E ??
|
|
text.append (Utility.getShort (buffer, ptr));
|
|
ptr += 2;
|
|
break;
|
|
|
|
case 0x1D:
|
|
String d4 = Utility.floatValueMS4 (buffer, ptr) + "";
|
|
if (d4.endsWith (".0"))
|
|
d4 = d4.substring (0, d4.length () - 2);
|
|
text.append (d4 + "!");
|
|
ptr += 4;
|
|
break;
|
|
|
|
case 0x1F:
|
|
String d8 = Utility.floatValueMS8 (buffer, ptr) + "";
|
|
if (d8.endsWith (".0"))
|
|
d8 = d8.substring (0, d8.length () - 2);
|
|
text.append (d8 + "#");
|
|
ptr += 8;
|
|
break;
|
|
|
|
default:
|
|
text.append (String.format ("<%02X>", val));
|
|
}
|
|
}
|
|
|
|
text.append ("\n");
|
|
}
|
|
|
|
return Utility.rtrim (text);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
private String debugText ()
|
|
// ---------------------------------------------------------------------------------//
|
|
{
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
int ptr = 1;
|
|
int lastPtr;
|
|
|
|
while (ptr < buffer.length)
|
|
{
|
|
int nextAddress = getShort (buffer, ptr);
|
|
if (nextAddress == 0)
|
|
break;
|
|
|
|
int lineNumber = getShort (buffer, ptr + 2);
|
|
lastPtr = ptr;
|
|
|
|
ptr += 4;
|
|
|
|
int val;
|
|
while ((val = buffer[ptr++]) != 0)
|
|
{
|
|
ptr += switch (val)
|
|
{
|
|
case 0x0C, 0x0E, 0x1C -> 2; // 2 byte numeric
|
|
case 0x1D -> 4; // 4 byte single precision
|
|
case 0x1F -> 8; // 8 byte double precision
|
|
case 0x0F, 0xFF -> 1; // 1 byte numeric, function table entry
|
|
default -> 0;
|
|
};
|
|
}
|
|
|
|
text.append (String.format (" %d %s%n", lineNumber,
|
|
HexFormatter.getHexString (buffer, lastPtr + 4, ptr - lastPtr - 4)));
|
|
}
|
|
|
|
return Utility.rtrim (text);
|
|
}
|
|
}
|