mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2025-02-21 11:28:58 +00:00
infocom changes
This commit is contained in:
parent
8764dd0db8
commit
76125f9a4e
@ -20,7 +20,7 @@ class Abbreviations extends InfocomAbstractFile
|
|||||||
dataPtr = header.getWord (header.abbreviationsTable) * 2;
|
dataPtr = header.getWord (header.abbreviationsTable) * 2;
|
||||||
dataSize = header.abbreviationsTable - dataPtr;
|
dataSize = header.abbreviationsTable - dataPtr;
|
||||||
tablePtr = header.abbreviationsTable;
|
tablePtr = header.abbreviationsTable;
|
||||||
tableSize = header.objectTable - header.abbreviationsTable;
|
tableSize = header.objectTableOffset - header.abbreviationsTable;
|
||||||
|
|
||||||
// prepare hex dump
|
// prepare hex dump
|
||||||
hexBlocks.add (new HexBlock (dataPtr, dataSize, "Abbreviations data:"));
|
hexBlocks.add (new HexBlock (dataPtr, dataSize, "Abbreviations data:"));
|
||||||
@ -29,21 +29,17 @@ class Abbreviations extends InfocomAbstractFile
|
|||||||
|
|
||||||
private void populate ()
|
private void populate ()
|
||||||
{
|
{
|
||||||
System.out.println ("populating abbreviations");
|
|
||||||
list = new ArrayList<ZString> ();
|
list = new ArrayList<ZString> ();
|
||||||
|
|
||||||
for (int i = header.abbreviationsTable; i < header.objectTable; i += 2)
|
for (int i = header.abbreviationsTable; i < header.objectTableOffset; i += 2)
|
||||||
{
|
list.add (new ZString (header, header.getWord (i) * 2));
|
||||||
int j = header.getWord (i) * 2;
|
|
||||||
ZString zs = new ZString (buffer, j, header);
|
|
||||||
list.add (zs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAbbreviation (int abbreviationNumber)
|
public String getAbbreviation (int abbreviationNumber)
|
||||||
{
|
{
|
||||||
if (list == null)
|
if (list == null)
|
||||||
populate ();
|
populate ();
|
||||||
|
|
||||||
return list.get (abbreviationNumber).value;
|
return list.get (abbreviationNumber).value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class AttributeManager extends AbstractFile
|
|||||||
new StringBuilder ("Objects with attribute " + id + " set:\n\n");
|
new StringBuilder ("Objects with attribute " + id + " set:\n\n");
|
||||||
for (ZObject o : list)
|
for (ZObject o : list)
|
||||||
{
|
{
|
||||||
text.append (String.format ("%3d %-28s%n", o.id, o.getName ()));
|
text.append (String.format ("%3d %-28s%n", o.getId (), o.getName ()));
|
||||||
}
|
}
|
||||||
if (text.length () > 0)
|
if (text.length () > 0)
|
||||||
text.deleteCharAt (text.length () - 1);
|
text.deleteCharAt (text.length () - 1);
|
||||||
|
@ -36,7 +36,7 @@ class CodeManager extends AbstractFile
|
|||||||
for (Routine routine : routines.values ())
|
for (Routine routine : routines.values ())
|
||||||
{
|
{
|
||||||
String name = String.format ("%3d %s (%04X)", ++count, routine.getName (),
|
String name = String.format ("%3d %s (%04X)", ++count, routine.getName (),
|
||||||
routine.startPtr / 2);
|
routine.startPtr / 2);
|
||||||
DefaultAppleFileSource dafs = new DefaultAppleFileSource (name, routine, disk);
|
DefaultAppleFileSource dafs = new DefaultAppleFileSource (name, routine, disk);
|
||||||
dafs.setSectors (getSectors (routine, disk.getDisk ()));
|
dafs.setSectors (getSectors (routine, disk.getDisk ()));
|
||||||
|
|
||||||
@ -114,10 +114,10 @@ class CodeManager extends AbstractFile
|
|||||||
for (Routine r : routines.values ())
|
for (Routine r : routines.values ())
|
||||||
{
|
{
|
||||||
int gap = r.startPtr - nextAddress;
|
int gap = r.startPtr - nextAddress;
|
||||||
text.append (String
|
text.append (String.format (
|
||||||
.format ("%3d %05X %5d %3d %2d %3d %3d %4d %04X%n",
|
"%3d %05X %5d %3d %2d %3d %3d %4d %04X%n", ++count,
|
||||||
++count, r.startPtr, r.length, r.instructions.size (), r.strings,
|
r.startPtr, r.length, r.instructions.size (), r.strings, r.calledBy.size (),
|
||||||
r.calledBy.size (), r.calls.size (), gap, r.startPtr / 2));
|
r.calls.size (), gap, r.startPtr / 2));
|
||||||
|
|
||||||
nextAddress = r.startPtr + r.length;
|
nextAddress = r.startPtr + r.length;
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ class CodeManager extends AbstractFile
|
|||||||
|
|
||||||
Routine addRoutine (int address, int caller)
|
Routine addRoutine (int address, int caller)
|
||||||
{
|
{
|
||||||
if (address == 0) // stack-based call
|
if (address == 0) // stack-based call
|
||||||
return null;
|
return null;
|
||||||
if (address > header.fileLength)
|
if (address > header.fileLength)
|
||||||
return null;
|
return null;
|
||||||
@ -163,7 +163,7 @@ class CodeManager extends AbstractFile
|
|||||||
|
|
||||||
// try to create a new Routine
|
// try to create a new Routine
|
||||||
Routine r = new Routine (address, header, caller);
|
Routine r = new Routine (address, header, caller);
|
||||||
if (r.length == 0) // invalid routine
|
if (r.length == 0) // invalid routine
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// recursively add all routines called by this one
|
// recursively add all routines called by this one
|
||||||
|
@ -15,15 +15,12 @@ class Dictionary extends AbstractFile
|
|||||||
private final int totalSeparators;
|
private final int totalSeparators;
|
||||||
private final int dictionaryPtr, dictionarySize;
|
private final int dictionaryPtr, dictionarySize;
|
||||||
private final int entryLength;
|
private final int entryLength;
|
||||||
// private final Header header;
|
|
||||||
|
|
||||||
// this could be a Google Multimap
|
|
||||||
Map<Integer, List<WordEntry>> synonymList = new TreeMap<Integer, List<WordEntry>> ();
|
Map<Integer, List<WordEntry>> synonymList = new TreeMap<Integer, List<WordEntry>> ();
|
||||||
|
|
||||||
public Dictionary (Header header)
|
public Dictionary (Header header)
|
||||||
{
|
{
|
||||||
super ("Dictionary", header.buffer);
|
super ("Dictionary", header.buffer);
|
||||||
// this.header = header;
|
|
||||||
|
|
||||||
dictionaryPtr = header.dictionaryOffset;
|
dictionaryPtr = header.dictionaryOffset;
|
||||||
dictionary = new TreeMap<Integer, ZString> ();
|
dictionary = new TreeMap<Integer, ZString> ();
|
||||||
@ -38,7 +35,7 @@ class Dictionary extends AbstractFile
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < totalEntries; i++)
|
for (int i = 0; i < totalEntries; i++)
|
||||||
{
|
{
|
||||||
ZString string = new ZString (buffer, ptr, header);
|
ZString string = new ZString (header, ptr);
|
||||||
dictionary.put (ptr, string);
|
dictionary.put (ptr, string);
|
||||||
WordEntry wordEntry = new WordEntry (string, count++);
|
WordEntry wordEntry = new WordEntry (string, count++);
|
||||||
|
|
||||||
@ -56,8 +53,8 @@ class Dictionary extends AbstractFile
|
|||||||
{
|
{
|
||||||
int b1 = buffer[ptr + 5] & 0xFF;
|
int b1 = buffer[ptr + 5] & 0xFF;
|
||||||
int property = (b1 >= 1 && b1 <= 31) ? b1 : buffer[ptr + 6] & 0xFF;
|
int property = (b1 >= 1 && b1 <= 31) ? b1 : buffer[ptr + 6] & 0xFF;
|
||||||
if (header.propertyNames[property] == null
|
if (header.getPropertyName (property) == null
|
||||||
|| header.propertyNames[property].length () > string.value.length ())
|
|| header.getPropertyName (property).length () > string.value.length ())
|
||||||
header.propertyNames[property] = string.value;
|
header.propertyNames[property] = string.value;
|
||||||
}
|
}
|
||||||
ptr += entryLength;
|
ptr += entryLength;
|
||||||
@ -68,6 +65,48 @@ class Dictionary extends AbstractFile
|
|||||||
for (int i = 1; i < header.propertyNames.length; i++)
|
for (int i = 1; i < header.propertyNames.length; i++)
|
||||||
if (header.propertyNames[i] == null)
|
if (header.propertyNames[i] == null)
|
||||||
header.propertyNames[i] = i + "";
|
header.propertyNames[i] = i + "";
|
||||||
|
|
||||||
|
// testing (only works in Zork 1)
|
||||||
|
if (false)
|
||||||
|
{
|
||||||
|
if (header.propertyNames[4].equals ("4"))
|
||||||
|
header.propertyNames[4] = "PSEUDO";
|
||||||
|
if (header.propertyNames[5].equals ("5"))
|
||||||
|
header.propertyNames[5] = "GLOBAL";
|
||||||
|
if (header.propertyNames[6].equals ("6"))
|
||||||
|
header.propertyNames[6] = "VTYPE";
|
||||||
|
if (header.propertyNames[7].equals ("7"))
|
||||||
|
header.propertyNames[7] = "STRENGTH";
|
||||||
|
if (header.propertyNames[10].equals ("10"))
|
||||||
|
header.propertyNames[10] = "CAPACITY";
|
||||||
|
if (header.propertyNames[12].equals ("12"))
|
||||||
|
header.propertyNames[12] = "TVALU";
|
||||||
|
if (header.propertyNames[13].equals ("13"))
|
||||||
|
header.propertyNames[13] = "VALUE";
|
||||||
|
if (header.propertyNames[15].equals ("15"))
|
||||||
|
header.propertyNames[15] = "SIZE";
|
||||||
|
if (header.propertyNames[16].equals ("16"))
|
||||||
|
header.propertyNames[16] = "ADJ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4 = PSEUDO (property 4)
|
||||||
|
// 5 = GLOBAL (property 5)
|
||||||
|
// 6 = VTYPE (property 6)
|
||||||
|
// 7 = STRENGTH (property 7)
|
||||||
|
// STR3 = TEXT (property 8)
|
||||||
|
// CODE2 = DESCFCN (property 9)
|
||||||
|
// 10 = CAPACITY (property 10)
|
||||||
|
// STR1 = LDESC (property 11)
|
||||||
|
// 12 = TVALUE (property 12) value in trophy case
|
||||||
|
// 13 = VALUE (property 13)
|
||||||
|
// STR2 = FDESC (property 14)
|
||||||
|
// 15 = SIZE (property 15)
|
||||||
|
// 16 = ADJ (property 16)
|
||||||
|
// CODE1 = ACTION (property 17)
|
||||||
|
// 18 = DICT (property 18)
|
||||||
|
// 19 = LAND (property 19)
|
||||||
|
// 20 = OUT (property 20)
|
||||||
|
// 21 = IN (property 21)
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsWordAt (int address)
|
public boolean containsWordAt (int address)
|
||||||
@ -168,7 +207,7 @@ class Dictionary extends AbstractFile
|
|||||||
text.append ("\n");
|
text.append ("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wordEntry.value == 0x80) // nouns are all in one entry
|
if (wordEntry.value == 0x80) // nouns are all in one entry
|
||||||
{
|
{
|
||||||
for (WordEntry we : list)
|
for (WordEntry we : list)
|
||||||
text.append (we + "\n");
|
text.append (we + "\n");
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
package com.bytezone.diskbrowser.infocom;
|
package com.bytezone.diskbrowser.infocom;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.bytezone.diskbrowser.infocom.Instruction.Operand;
|
||||||
|
|
||||||
class Globals extends InfocomAbstractFile
|
class Globals extends InfocomAbstractFile
|
||||||
{
|
{
|
||||||
static final int TOTAL_GLOBALS = 240;
|
private static final int TOTAL_GLOBALS = 240;
|
||||||
Header header;
|
private final Header header;
|
||||||
int globalsPtr, globalsSize;
|
private final int globalsPtr, globalsSize;
|
||||||
int arrayPtr, arraySize;
|
private final int arrayPtr, arraySize;
|
||||||
|
private final List<List<Routine>> globalRoutines;
|
||||||
|
|
||||||
public Globals (Header header)
|
Globals (Header header)
|
||||||
{
|
{
|
||||||
super ("Globals", header.buffer);
|
super ("Globals", header.buffer);
|
||||||
this.header = header;
|
this.header = header;
|
||||||
@ -20,21 +26,39 @@ class Globals extends InfocomAbstractFile
|
|||||||
// add entries for AbstractFile.getHexDump ()
|
// add entries for AbstractFile.getHexDump ()
|
||||||
hexBlocks.add (new HexBlock (globalsPtr, globalsSize, "Globals:"));
|
hexBlocks.add (new HexBlock (globalsPtr, globalsSize, "Globals:"));
|
||||||
hexBlocks.add (new HexBlock (arrayPtr, arraySize, "Arrays:"));
|
hexBlocks.add (new HexBlock (arrayPtr, arraySize, "Arrays:"));
|
||||||
|
|
||||||
|
globalRoutines = new ArrayList<> (250);
|
||||||
|
for (int i = 0; i < 250; i++)
|
||||||
|
globalRoutines.add (new ArrayList<> ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRoutine (Routine routine, Operand operand)
|
||||||
|
{
|
||||||
|
int global = operand.value - 15;
|
||||||
|
List<Routine> list = globalRoutines.get (global);
|
||||||
|
if (!list.contains (routine))
|
||||||
|
list.add (routine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getText ()
|
public String getText ()
|
||||||
{
|
{
|
||||||
StringBuilder text = new StringBuilder ();
|
StringBuilder text = new StringBuilder ("GLB Value Routines\n");
|
||||||
for (int i = 1; i <= TOTAL_GLOBALS; i++)
|
for (int i = 1; i <= TOTAL_GLOBALS; i++)
|
||||||
{
|
{
|
||||||
int value = header.getWord (globalsPtr + i * 2);
|
int value = header.getWord (globalsPtr + i * 2);
|
||||||
text.append (String.format ("G%03d %04X ", i, value));
|
text.append (String.format ("G%03d %04X %02d ", i, value,
|
||||||
|
globalRoutines.get (i).size ()));
|
||||||
int address = value * 2;
|
int address = value * 2;
|
||||||
if (address >= header.stringPointer && address < header.fileLength)
|
if (address >= header.stringPointer && address < header.fileLength)
|
||||||
text.append (header.stringManager.stringAt (address) + "\n");
|
text.append (header.stringManager.stringAt (address) + "\n");
|
||||||
else
|
else
|
||||||
text.append (String.format ("%,6d%n", value));
|
{
|
||||||
|
for (Routine routine : globalRoutines.get (i))
|
||||||
|
text.append (String.format ("%05X ", routine.startPtr));
|
||||||
|
text.append ("\n");
|
||||||
|
}
|
||||||
|
// text.append (String.format ("%,6d%n", value));
|
||||||
}
|
}
|
||||||
text.deleteCharAt (text.length () - 1);
|
text.deleteCharAt (text.length () - 1);
|
||||||
return text.toString ();
|
return text.toString ();
|
||||||
|
@ -7,23 +7,24 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
|
|||||||
class Grammar extends InfocomAbstractFile
|
class Grammar extends InfocomAbstractFile
|
||||||
{
|
{
|
||||||
private static final int SENTENCE_LENGTH = 8;
|
private static final int SENTENCE_LENGTH = 8;
|
||||||
Header header;
|
private final Header header;
|
||||||
int indexPtr, indexSize;
|
private final int indexPtr, indexSize;
|
||||||
int tablePtr, tableSize;
|
private final int tablePtr, tableSize;
|
||||||
int actionPtr, actionSize;
|
private final int actionPtr, actionSize;
|
||||||
int preActionPtr, preActionSize;
|
private final int preActionPtr, preActionSize;
|
||||||
int prepositionPtr, prepositionSize;
|
private final int prepositionPtr, prepositionSize;
|
||||||
int indexEntries;
|
private final int indexEntries;
|
||||||
int totalPrepositions;
|
private final int totalPrepositions;
|
||||||
int padding;
|
private final int padding;
|
||||||
|
|
||||||
List<SentenceGroup> sentenceGroups = new ArrayList<SentenceGroup> ();
|
private final List<SentenceGroup> sentenceGroups = new ArrayList<SentenceGroup> ();
|
||||||
Map<Integer, List<Sentence>> actionList = new TreeMap<Integer, List<Sentence>> ();
|
private final Map<Integer, List<Sentence>> actionList =
|
||||||
|
new TreeMap<Integer, List<Sentence>> ();
|
||||||
|
|
||||||
List<Integer> actionRoutines = new ArrayList<Integer> ();
|
private final List<Integer> actionRoutines = new ArrayList<Integer> ();
|
||||||
List<Integer> preActionRoutines = new ArrayList<Integer> ();
|
private final List<Integer> preActionRoutines = new ArrayList<Integer> ();
|
||||||
|
|
||||||
public Grammar (String name, byte[] buffer, Header header)
|
Grammar (String name, byte[] buffer, Header header)
|
||||||
{
|
{
|
||||||
super (name, buffer);
|
super (name, buffer);
|
||||||
this.header = header;
|
this.header = header;
|
||||||
@ -173,8 +174,8 @@ class Grammar extends InfocomAbstractFile
|
|||||||
text.append (line);
|
text.append (line);
|
||||||
}
|
}
|
||||||
|
|
||||||
text.append ("\n" + actionRoutines.size ()
|
text.append (
|
||||||
+ " Action routines\n===================\n\n");
|
"\n" + actionRoutines.size () + " Action routines\n===================\n\n");
|
||||||
|
|
||||||
// add sentences in action routine sequence
|
// add sentences in action routine sequence
|
||||||
for (Integer routine : actionRoutines)
|
for (Integer routine : actionRoutines)
|
||||||
|
@ -9,12 +9,11 @@ class Header extends InfocomAbstractFile
|
|||||||
final String[] propertyNames = new String[32];
|
final String[] propertyNames = new String[32];
|
||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
// private final Disk disk;
|
|
||||||
int version;
|
int version;
|
||||||
int highMemory;
|
int highMemory;
|
||||||
int programCounter;
|
int programCounter;
|
||||||
int dictionaryOffset;
|
int dictionaryOffset;
|
||||||
int objectTable;
|
int objectTableOffset;
|
||||||
int globalsOffset;
|
int globalsOffset;
|
||||||
int staticMemory;
|
int staticMemory;
|
||||||
int abbreviationsTable;
|
int abbreviationsTable;
|
||||||
@ -23,29 +22,37 @@ class Header extends InfocomAbstractFile
|
|||||||
int stringPointer;
|
int stringPointer;
|
||||||
|
|
||||||
final Abbreviations abbreviations;
|
final Abbreviations abbreviations;
|
||||||
final Dictionary dictionary;
|
|
||||||
final ObjectManager objectManager;
|
final ObjectManager objectManager;
|
||||||
final StringManager stringManager;
|
|
||||||
final CodeManager codeManager;
|
|
||||||
final Globals globals;
|
final Globals globals;
|
||||||
final Grammar grammar;
|
final Grammar grammar;
|
||||||
|
final Dictionary dictionary;
|
||||||
|
final CodeManager codeManager;
|
||||||
|
final StringManager stringManager;
|
||||||
|
|
||||||
public Header (String name, byte[] buffer, Disk disk)
|
public Header (String name, byte[] buffer, Disk disk)
|
||||||
{
|
{
|
||||||
super (name, buffer);
|
super (name, buffer);
|
||||||
// this.disk = disk;
|
|
||||||
this.file = disk.getFile ();
|
this.file = disk.getFile ();
|
||||||
|
|
||||||
version = getByte (0);
|
version = getByte (00);
|
||||||
highMemory = getWord (4);
|
highMemory = getWord (0x04);
|
||||||
programCounter = getWord (6);
|
programCounter = getWord (0x06);
|
||||||
dictionaryOffset = getWord (8);
|
|
||||||
objectTable = getWord (10);
|
dictionaryOffset = getWord (0x08);
|
||||||
globalsOffset = getWord (12);
|
objectTableOffset = getWord (0x0A);
|
||||||
staticMemory = getWord (14);
|
globalsOffset = getWord (0x0C);
|
||||||
abbreviationsTable = getWord (24);
|
staticMemory = getWord (0x0E);
|
||||||
checksum = getWord (28);
|
abbreviationsTable = getWord (0x18);
|
||||||
fileLength = getWord (26) * 2;
|
|
||||||
|
fileLength = getWord (0x1A) * 2; // 2 for versions 1-3
|
||||||
|
checksum = getWord (0x1C);
|
||||||
|
int interpreterNumber = getByte (0x1E);
|
||||||
|
int interpreterVersion = getByte (0x1F);
|
||||||
|
int revision = getWord (0x30);
|
||||||
|
|
||||||
|
System.out.printf ("Version : %d%n", version);
|
||||||
|
System.out.printf ("Interpreter: %d.%d%n", interpreterNumber, interpreterVersion);
|
||||||
|
System.out.printf ("Revision : %d%n", revision);
|
||||||
|
|
||||||
if (fileLength == 0)
|
if (fileLength == 0)
|
||||||
fileLength = buffer.length;
|
fileLength = buffer.length;
|
||||||
@ -75,6 +82,11 @@ class Header extends InfocomAbstractFile
|
|||||||
hexBlocks.add (new HexBlock (0, 64, "Header data:"));
|
hexBlocks.add (new HexBlock (0, 64, "Header data:"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getPropertyName (int id)
|
||||||
|
{
|
||||||
|
return propertyNames[id];
|
||||||
|
}
|
||||||
|
|
||||||
public String getAbbreviation (int index)
|
public String getAbbreviation (int index)
|
||||||
{
|
{
|
||||||
return abbreviations.getAbbreviation (index);
|
return abbreviations.getAbbreviation (index);
|
||||||
@ -100,8 +112,8 @@ class Header extends InfocomAbstractFile
|
|||||||
text.append ("\nDynamic memory:\n");
|
text.append ("\nDynamic memory:\n");
|
||||||
text.append (String.format (" Abbreviation table %04X %,6d%n",
|
text.append (String.format (" Abbreviation table %04X %,6d%n",
|
||||||
abbreviationsTable, abbreviationsTable));
|
abbreviationsTable, abbreviationsTable));
|
||||||
text.append (String.format (" Objects table %04X %,6d%n", objectTable,
|
text.append (String.format (" Objects table %04X %,6d%n",
|
||||||
objectTable));
|
objectTableOffset, objectTableOffset));
|
||||||
text.append (String.format (" Global variables %04X %,6d%n", globalsOffset,
|
text.append (String.format (" Global variables %04X %,6d%n", globalsOffset,
|
||||||
globalsOffset));
|
globalsOffset));
|
||||||
|
|
||||||
@ -125,11 +137,16 @@ class Header extends InfocomAbstractFile
|
|||||||
text.append (String.format ("Total strings %d%n",
|
text.append (String.format ("Total strings %d%n",
|
||||||
stringManager.strings.size ()));
|
stringManager.strings.size ()));
|
||||||
text.append (String.format ("Total objects %d%n",
|
text.append (String.format ("Total objects %d%n",
|
||||||
objectManager.list.size ()));
|
objectManager.getObjects ().size ()));
|
||||||
|
|
||||||
return text.toString ();
|
return text.toString ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZObject getObject (int index)
|
||||||
|
{
|
||||||
|
return objectManager.getObject (index);
|
||||||
|
}
|
||||||
|
|
||||||
int getByte (int offset)
|
int getByte (int offset)
|
||||||
{
|
{
|
||||||
return buffer[offset] & 0xFF;
|
return buffer[offset] & 0xFF;
|
||||||
|
@ -86,16 +86,16 @@ public class InfocomDisk extends AbstractFormattedDisk
|
|||||||
stringsNode = addToTree (root, "Strings", header.stringManager, TYPE_LEAF);
|
stringsNode = addToTree (root, "Strings", header.stringManager, TYPE_LEAF);
|
||||||
|
|
||||||
PropertyManager pm = new PropertyManager ("Properties", data, header);
|
PropertyManager pm = new PropertyManager ("Properties", data, header);
|
||||||
pm.addNodes (addToTree (objectNode, "Properties", pm, TYPE_NODE), this);
|
pm.addNodes (addToTree (root, "Properties", pm, TYPE_NODE), this);
|
||||||
|
|
||||||
AttributeManager am = new AttributeManager ("Attributes", data, header);
|
AttributeManager am = new AttributeManager ("Attributes", data, header);
|
||||||
am.addNodes (addToTree (objectNode, "Attributes", am, TYPE_NODE), this);
|
am.addNodes (addToTree (root, "Attributes", am, TYPE_NODE), this);
|
||||||
|
|
||||||
sectorTypes[48] = headerSector;
|
sectorTypes[48] = headerSector;
|
||||||
|
|
||||||
setSectorTypes (header.abbreviationsTable, header.objectTable, abbreviationsSector,
|
setSectorTypes (header.abbreviationsTable, header.objectTableOffset, abbreviationsSector,
|
||||||
abbreviationsNode);
|
abbreviationsNode);
|
||||||
setSectorTypes (header.objectTable, header.globalsOffset, objectsSector, objectNode);
|
setSectorTypes (header.objectTableOffset, header.globalsOffset, objectsSector, objectNode);
|
||||||
setSectorTypes (header.globalsOffset, header.staticMemory, globalsSector,
|
setSectorTypes (header.globalsOffset, header.staticMemory, globalsSector,
|
||||||
globalsNode);
|
globalsNode);
|
||||||
setSectorTypes (header.staticMemory, header.dictionaryOffset, grammarSector,
|
setSectorTypes (header.staticMemory, header.dictionaryOffset, grammarSector,
|
||||||
|
@ -7,487 +7,508 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
|
|||||||
|
|
||||||
class Instruction
|
class Instruction
|
||||||
{
|
{
|
||||||
Opcode opcode;
|
Opcode opcode;
|
||||||
int startPtr;
|
int startPtr;
|
||||||
byte[] buffer;
|
byte[] buffer;
|
||||||
// List<ZString> abbreviations;
|
// List<ZString> abbreviations;
|
||||||
Header header;
|
Header header;
|
||||||
|
|
||||||
static final String[] name2OP =
|
enum OperandType
|
||||||
{ "*bad*", "je", "jl", "jg", "dec_chk", "inc_chk", "jin", "test", "or", "and", "test_attr",
|
{
|
||||||
"set_attr", "clear_attr", "store", "insert_obj", "loadw", "loadb", "get_prop",
|
VAR_STACK, VAR_LOCAL, VAR_GLOBAL, BYTE, WORD, ARG_BRANCH, ARG_STRING
|
||||||
"get_prop_addr", "get_next_prop", "add", "sub", "mul", "div", "mod", "call_2s",
|
}
|
||||||
"call_2n", "set_colour", "throw", "*bad*", "*bad*", "*bad*" };
|
|
||||||
static final String[] name1OP =
|
|
||||||
{ "jz", "get_sibling", "get_child", "get_parent", "get_prop_len", "inc", "dec",
|
|
||||||
"print_addr", "call_ls", "remove_obj", "print_obj", "ret", "jump", "print_paddr", "load",
|
|
||||||
"not" };
|
|
||||||
static final String[] name0OP =
|
|
||||||
{ "rtrue", "rfalse", "print", "print_ret", "nop", "save", "restore", "restart",
|
|
||||||
"ret_popped", "pop", "quit", "new_line", "show_status", "verify", "", "piracy" };
|
|
||||||
static final String[] nameVAR =
|
|
||||||
{ "call", "storew", "storeb", "put_prop", "sread", "print_char", "print_num", "random",
|
|
||||||
"push", "pull", "split_window", "set_window", "call_vs2", "erase_window", "erase_line",
|
|
||||||
"set_cursor", "get_cursor", "set_text_style", "buffer_mode", "output_stream",
|
|
||||||
"input_stream", "sound_effect", "read_char", "scan_table", "not", "call_vn", "call_vn2",
|
|
||||||
"tokenise", "encode_text", "copy_table", "print_table", "check_arg" };
|
|
||||||
|
|
||||||
public Instruction (byte[] buffer, int ptr, Header header)
|
static final String[] name2OP =
|
||||||
{
|
{ "*bad*", "je", "jl", "jg", "dec_chk", "inc_chk", "jin", "test", "or", "and",
|
||||||
this.buffer = buffer;
|
"test_attr", "set_attr", "clear_attr", "store", "insert_obj", "loadw", "loadb",
|
||||||
this.startPtr = ptr;
|
"get_prop", "get_prop_addr", "get_next_prop", "add", "sub", "mul", "div", "mod",
|
||||||
this.header = header;
|
"call_2s", "call_2n", "set_colour", "throw", "*bad*", "*bad*", "*bad*" };
|
||||||
byte b1 = buffer[ptr];
|
static final String[] name1OP =
|
||||||
|
{ "jz", "get_sibling", "get_child", "get_parent", "get_prop_len", "inc", "dec",
|
||||||
|
"print_addr", "call_ls", "remove_obj", "print_obj", "ret", "jump", "print_paddr",
|
||||||
|
"load", "not" };
|
||||||
|
static final String[] name0OP =
|
||||||
|
{ "rtrue", "rfalse", "print", "print_ret", "nop", "save", "restore", "restart",
|
||||||
|
"ret_popped", "pop", "quit", "new_line", "show_status", "verify", "", "piracy" };
|
||||||
|
static final String[] nameVAR =
|
||||||
|
{ "call", "storew", "storeb", "put_prop", "sread", "print_char", "print_num",
|
||||||
|
"random", "push", "pull", "split_window", "set_window", "call_vs2",
|
||||||
|
"erase_window", "erase_line", "set_cursor", "get_cursor", "set_text_style",
|
||||||
|
"buffer_mode", "output_stream", "input_stream", "sound_effect", "read_char",
|
||||||
|
"scan_table", "not", "call_vn", "call_vn2", "tokenise", "encode_text",
|
||||||
|
"copy_table", "print_table", "check_arg" };
|
||||||
|
|
||||||
// long
|
public Instruction (byte[] buffer, int ptr, Header header)
|
||||||
if ((b1 & 0x80) == 0)
|
{
|
||||||
opcode = new Opcode2OPLong (buffer, ptr);
|
this.buffer = buffer;
|
||||||
// short
|
this.startPtr = ptr;
|
||||||
else if ((b1 & 0x40) == 0)
|
this.header = header;
|
||||||
{
|
byte b1 = buffer[ptr];
|
||||||
if ((b1 & 0x30) == 0x30)
|
|
||||||
opcode = new Opcode0OP (buffer, ptr);
|
|
||||||
else
|
|
||||||
opcode = new Opcode1OP (buffer, ptr);
|
|
||||||
}
|
|
||||||
// variable
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((b1 & 0x20) == 0)
|
|
||||||
opcode = new Opcode2OPVar (buffer, ptr);
|
|
||||||
else
|
|
||||||
opcode = new OpcodeVar (buffer, ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length ()
|
// long
|
||||||
{
|
if ((b1 & 0x80) == 0)
|
||||||
return opcode.length ();
|
opcode = new Opcode2OPLong (buffer, ptr);
|
||||||
}
|
// short
|
||||||
|
else if ((b1 & 0x40) == 0)
|
||||||
|
{
|
||||||
|
if ((b1 & 0x30) == 0x30)
|
||||||
|
opcode = new Opcode0OP (buffer, ptr);
|
||||||
|
else
|
||||||
|
opcode = new Opcode1OP (buffer, ptr);
|
||||||
|
}
|
||||||
|
// variable
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((b1 & 0x20) == 0)
|
||||||
|
opcode = new Opcode2OPVar (buffer, ptr);
|
||||||
|
else
|
||||||
|
opcode = new OpcodeVar (buffer, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isReturn ()
|
public int length ()
|
||||||
{
|
{
|
||||||
return opcode.isReturn;
|
return opcode.length ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPrint ()
|
public boolean isReturn ()
|
||||||
{
|
{
|
||||||
return opcode.string != null;
|
return opcode.isReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCall ()
|
public boolean isPrint ()
|
||||||
{
|
{
|
||||||
return opcode.isCall;
|
return opcode.string != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isJump ()
|
public boolean isCall ()
|
||||||
{
|
{
|
||||||
// could use jumpTarget != 0
|
return opcode.isCall;
|
||||||
return (opcode instanceof Opcode1OP && opcode.opcodeNumber == 12);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBranch ()
|
public boolean isJump ()
|
||||||
{
|
{
|
||||||
return opcode.branch != null;
|
// could use jumpTarget != 0
|
||||||
}
|
return (opcode instanceof Opcode1OP && opcode.opcodeNumber == 12);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isStore ()
|
public boolean isBranch ()
|
||||||
{
|
{
|
||||||
return opcode.store != null;
|
return opcode.branch != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int target ()
|
public boolean isStore ()
|
||||||
{
|
{
|
||||||
return isBranch () ? opcode.branch.target : 0;
|
return opcode.store != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public int target ()
|
||||||
public String toString ()
|
{
|
||||||
{
|
return isBranch () ? opcode.branch.target : 0;
|
||||||
int max = opcode.length ();
|
}
|
||||||
String extra = "";
|
|
||||||
if (max > 9)
|
|
||||||
{
|
|
||||||
max = 9;
|
|
||||||
extra = "..";
|
|
||||||
}
|
|
||||||
String hex = HexFormatter.getHexString (buffer, startPtr, max);
|
|
||||||
return String.format ("%-26s%2s %s", hex, extra, opcode.toString ());
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Opcode
|
@Override
|
||||||
{
|
public String toString ()
|
||||||
int opcodeNumber;
|
{
|
||||||
int opcodeLength;
|
int max = opcode.length ();
|
||||||
List<Operand> operands;
|
String extra = "";
|
||||||
int totalOperandLength;
|
if (max > 9)
|
||||||
ArgumentBranch branch;
|
{
|
||||||
ArgumentString string;
|
max = 9;
|
||||||
OperandVariable store;
|
extra = "..";
|
||||||
boolean isReturn, isCall, isExit;
|
}
|
||||||
int jumpTarget;
|
String hex = HexFormatter.getHexString (buffer, startPtr, max);
|
||||||
int callTarget;
|
return String.format ("%-26s%2s %s", hex, extra, opcode.toString ());
|
||||||
|
}
|
||||||
|
|
||||||
public Opcode ()
|
abstract class Opcode
|
||||||
{
|
{
|
||||||
operands = new ArrayList<Operand> ();
|
int opcodeNumber;
|
||||||
}
|
int opcodeLength;
|
||||||
|
List<Operand> operands;
|
||||||
|
int totalOperandLength;
|
||||||
|
ArgumentBranch branch;
|
||||||
|
ArgumentString string;
|
||||||
|
OperandVariable store;
|
||||||
|
boolean isReturn, isCall, isExit;
|
||||||
|
int jumpTarget;
|
||||||
|
int callTarget;
|
||||||
|
|
||||||
@Override
|
public Opcode ()
|
||||||
public String toString ()
|
{
|
||||||
{
|
operands = new ArrayList<Operand> ();
|
||||||
StringBuilder text = new StringBuilder ();
|
}
|
||||||
if (false)
|
|
||||||
text.append (HexFormatter.formatNoHeader (buffer, startPtr, length ()) + "\n");
|
|
||||||
text.append (String.format ("%05X : %-12s", startPtr, opcodeName ()));
|
|
||||||
if (jumpTarget != 0)
|
|
||||||
text.append (String.format (" L:%05X", jumpTarget));
|
|
||||||
else if (isCall)
|
|
||||||
{
|
|
||||||
text.append (String.format (" R:%05X (", callTarget));
|
|
||||||
int count = 0;
|
|
||||||
for (Operand op : operands)
|
|
||||||
if (count++ > 0)
|
|
||||||
text.append (op + ", ");
|
|
||||||
if (operands.size () > 1)
|
|
||||||
text.delete (text.length () - 2, text.length ());
|
|
||||||
text.append (") --> " + store);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (Operand op : operands)
|
|
||||||
text.append (" " + op);
|
|
||||||
if (branch != null)
|
|
||||||
text.append (branch);
|
|
||||||
if (store != null)
|
|
||||||
text.append (" --> " + store);
|
|
||||||
if (string != null)
|
|
||||||
text.append (" \"" + string + "\"");
|
|
||||||
}
|
|
||||||
return text.toString ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length ()
|
@Override
|
||||||
{
|
public String toString ()
|
||||||
int length = totalOperandLength + opcodeLength;
|
{
|
||||||
if (branch != null)
|
StringBuilder text = new StringBuilder ();
|
||||||
length += branch.length;
|
if (false)
|
||||||
if (store != null)
|
text.append (HexFormatter.formatNoHeader (buffer, startPtr, length ()) + "\n");
|
||||||
length += store.length;
|
text.append (String.format ("%05X : %-12s", startPtr, opcodeName ()));
|
||||||
if (string != null)
|
if (jumpTarget != 0)
|
||||||
length += string.length;
|
text.append (String.format (" L:%05X", jumpTarget));
|
||||||
return length;
|
else if (isCall)
|
||||||
}
|
{
|
||||||
|
text.append (String.format (" R:%05X (", callTarget));
|
||||||
|
int count = 0;
|
||||||
|
for (Operand op : operands)
|
||||||
|
if (count++ > 0)
|
||||||
|
text.append (op + ", ");
|
||||||
|
if (operands.size () > 1)
|
||||||
|
text.delete (text.length () - 2, text.length ());
|
||||||
|
text.append (") --> " + store);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (Operand op : operands)
|
||||||
|
text.append (" " + op);
|
||||||
|
if (branch != null)
|
||||||
|
text.append (branch);
|
||||||
|
if (store != null)
|
||||||
|
text.append (" --> " + store);
|
||||||
|
if (string != null)
|
||||||
|
text.append (" \"" + string + "\"");
|
||||||
|
}
|
||||||
|
return text.toString ();
|
||||||
|
}
|
||||||
|
|
||||||
public abstract String opcodeName ();
|
public int length ()
|
||||||
|
{
|
||||||
|
int length = totalOperandLength + opcodeLength;
|
||||||
|
if (branch != null)
|
||||||
|
length += branch.length;
|
||||||
|
if (store != null)
|
||||||
|
length += store.length;
|
||||||
|
if (string != null)
|
||||||
|
length += string.length;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
private void addOperand (Operand operand)
|
public abstract String opcodeName ();
|
||||||
{
|
|
||||||
operands.add (operand);
|
|
||||||
totalOperandLength += operand.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addOperand (byte[] buffer, int ptr, boolean bit1, boolean bit2)
|
private void addOperand (Operand operand)
|
||||||
{
|
{
|
||||||
int offset = ptr + totalOperandLength;
|
operands.add (operand);
|
||||||
if (bit1)
|
totalOperandLength += operand.length;
|
||||||
{
|
}
|
||||||
if (!bit2)
|
|
||||||
addOperand (new OperandVariable (buffer[offset])); // %10
|
|
||||||
}
|
|
||||||
else if (bit2)
|
|
||||||
addOperand (new OperandByte (buffer[offset])); // %01
|
|
||||||
else
|
|
||||||
addOperand (new OperandWord (header.getWord (offset))); // %00
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addOperand (byte[] buffer, int ptr, boolean bit)
|
protected void addOperand (byte[] buffer, int ptr, boolean bit1, boolean bit2)
|
||||||
{
|
{
|
||||||
int address = ptr + totalOperandLength;
|
int offset = ptr + totalOperandLength;
|
||||||
if (address >= buffer.length)
|
if (bit1)
|
||||||
{
|
{
|
||||||
System.out.println ("Illegal byte address : " + address);
|
if (!bit2)
|
||||||
return;
|
addOperand (new OperandVariable (buffer[offset])); // %10
|
||||||
}
|
}
|
||||||
if (bit)
|
else if (bit2)
|
||||||
addOperand (new OperandVariable (buffer[address]));
|
addOperand (new OperandByte (buffer[offset])); // %01
|
||||||
else
|
else
|
||||||
addOperand (new OperandByte (buffer[address]));
|
addOperand (new OperandWord (header.getWord (offset))); // %00
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setVariableOperands (int ptr)
|
protected void addOperand (byte[] buffer, int ptr, boolean bit)
|
||||||
{
|
{
|
||||||
int value = buffer[ptr + 1] & 0xFF;
|
int address = ptr + totalOperandLength;
|
||||||
for (int i = 0; i < 4; i++)
|
if (address >= buffer.length)
|
||||||
{
|
{
|
||||||
boolean bit1 = ((value & 0x80) == 0x80);
|
System.out.println ("Illegal byte address : " + address);
|
||||||
boolean bit2 = ((value & 0x40) == 0x40);
|
return;
|
||||||
if (bit1 && bit2)
|
}
|
||||||
break;
|
if (bit)
|
||||||
addOperand (buffer, ptr + 2, bit1, bit2);
|
addOperand (new OperandVariable (buffer[address]));
|
||||||
value <<= 2;
|
else
|
||||||
}
|
addOperand (new OperandByte (buffer[address]));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setStore (byte[] buffer)
|
protected void setVariableOperands (int ptr)
|
||||||
{
|
{
|
||||||
store = new OperandVariable (buffer[startPtr + totalOperandLength + opcodeLength]);
|
int value = buffer[ptr + 1] & 0xFF;
|
||||||
}
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
boolean bit1 = ((value & 0x80) == 0x80);
|
||||||
|
boolean bit2 = ((value & 0x40) == 0x40);
|
||||||
|
if (bit1 && bit2)
|
||||||
|
break;
|
||||||
|
addOperand (buffer, ptr + 2, bit1, bit2);
|
||||||
|
value <<= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void setBranch (byte[] buffer)
|
protected void setStore (byte[] buffer)
|
||||||
{
|
{
|
||||||
int offset = startPtr + totalOperandLength + (store == null ? 0 : 1) + opcodeLength;
|
store = new OperandVariable (buffer[startPtr + totalOperandLength + opcodeLength]);
|
||||||
if ((buffer[offset] & 0x40) == 0x40)
|
}
|
||||||
branch = new ArgumentBranch (buffer[offset], offset);
|
|
||||||
else
|
|
||||||
branch = new ArgumentBranch (header.getWord (offset), offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setZString (byte[] buffer)
|
protected void setBranch (byte[] buffer)
|
||||||
{
|
{
|
||||||
int offset = startPtr + totalOperandLength + opcodeLength;
|
int offset = startPtr + totalOperandLength + (store == null ? 0 : 1) + opcodeLength;
|
||||||
string = new ArgumentString (buffer, offset);
|
if ((buffer[offset] & 0x40) == 0x40)
|
||||||
}
|
branch = new ArgumentBranch (buffer[offset], offset);
|
||||||
}
|
else
|
||||||
|
branch = new ArgumentBranch (header.getWord (offset), offset);
|
||||||
|
}
|
||||||
|
|
||||||
class Opcode0OP extends Opcode
|
protected void setZString (byte[] buffer)
|
||||||
{
|
{
|
||||||
public Opcode0OP (byte[] buffer, int ptr)
|
int offset = startPtr + totalOperandLength + opcodeLength;
|
||||||
{
|
string = new ArgumentString (buffer, offset);
|
||||||
opcodeNumber = buffer[ptr] & 0x0F;
|
}
|
||||||
opcodeLength = 1;
|
}
|
||||||
|
|
||||||
if (opcodeNumber == 5 || opcodeNumber == 6 || opcodeNumber == 13)
|
class Opcode0OP extends Opcode
|
||||||
setBranch (buffer);
|
{
|
||||||
|
public Opcode0OP (byte[] buffer, int ptr)
|
||||||
|
{
|
||||||
|
opcodeNumber = buffer[ptr] & 0x0F;
|
||||||
|
opcodeLength = 1;
|
||||||
|
|
||||||
if (opcodeNumber == 0 || opcodeNumber == 1 || opcodeNumber == 3 || opcodeNumber == 8)
|
if (opcodeNumber == 5 || opcodeNumber == 6 || opcodeNumber == 13)
|
||||||
isReturn = true;
|
setBranch (buffer);
|
||||||
|
|
||||||
if (opcodeNumber == 2 || opcodeNumber == 3)
|
if (opcodeNumber == 0 || opcodeNumber == 1 || opcodeNumber == 3
|
||||||
setZString (buffer);
|
|| opcodeNumber == 8)
|
||||||
|
isReturn = true;
|
||||||
|
|
||||||
if (opcodeNumber == 7 || opcodeNumber == 10)
|
if (opcodeNumber == 2 || opcodeNumber == 3)
|
||||||
isExit = true;
|
setZString (buffer);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (opcodeNumber == 7 || opcodeNumber == 10)
|
||||||
public String opcodeName ()
|
isExit = true;
|
||||||
{
|
}
|
||||||
return name0OP[opcodeNumber];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Opcode1OP extends Opcode
|
@Override
|
||||||
{
|
public String opcodeName ()
|
||||||
public Opcode1OP (byte[] buffer, int ptr)
|
{
|
||||||
{
|
return name0OP[opcodeNumber];
|
||||||
opcodeNumber = buffer[ptr] & 0x0F;
|
}
|
||||||
opcodeLength = 1;
|
}
|
||||||
|
|
||||||
boolean bit1 = ((buffer[ptr] & 0x20) == 0x20);
|
class Opcode1OP extends Opcode
|
||||||
boolean bit2 = ((buffer[ptr] & 0x10) == 0x10);
|
{
|
||||||
addOperand (buffer, ptr + 1, bit1, bit2);
|
public Opcode1OP (byte[] buffer, int ptr)
|
||||||
|
{
|
||||||
|
opcodeNumber = buffer[ptr] & 0x0F;
|
||||||
|
opcodeLength = 1;
|
||||||
|
|
||||||
if ((opcodeNumber >= 1 && opcodeNumber <= 4) || opcodeNumber == 8 || opcodeNumber == 14
|
boolean bit1 = ((buffer[ptr] & 0x20) == 0x20);
|
||||||
|| opcodeNumber == 15)
|
boolean bit2 = ((buffer[ptr] & 0x10) == 0x10);
|
||||||
setStore (buffer);
|
addOperand (buffer, ptr + 1, bit1, bit2);
|
||||||
if (opcodeNumber <= 2)
|
|
||||||
setBranch (buffer);
|
|
||||||
if (opcodeNumber == 12)
|
|
||||||
jumpTarget = (short) operands.get (0).value + startPtr - 2 + length ();
|
|
||||||
if (opcodeNumber == 11)
|
|
||||||
isReturn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if ((opcodeNumber >= 1 && opcodeNumber <= 4) || opcodeNumber == 8
|
||||||
public String opcodeName ()
|
|| opcodeNumber == 14 || opcodeNumber == 15)
|
||||||
{
|
setStore (buffer);
|
||||||
return name1OP[opcodeNumber];
|
if (opcodeNumber <= 2)
|
||||||
}
|
setBranch (buffer);
|
||||||
}
|
if (opcodeNumber == 12)
|
||||||
|
jumpTarget = (short) operands.get (0).value + startPtr - 2 + length ();
|
||||||
|
if (opcodeNumber == 11)
|
||||||
|
isReturn = true;
|
||||||
|
}
|
||||||
|
|
||||||
abstract class Opcode2OP extends Opcode
|
@Override
|
||||||
{
|
public String opcodeName ()
|
||||||
public Opcode2OP ()
|
{
|
||||||
{
|
return name1OP[opcodeNumber];
|
||||||
opcodeLength = 1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setArguments (byte[] buffer)
|
abstract class Opcode2OP extends Opcode
|
||||||
{
|
{
|
||||||
if ((opcodeNumber >= 1 && opcodeNumber <= 7) || opcodeNumber == 10)
|
public Opcode2OP ()
|
||||||
setBranch (buffer);
|
{
|
||||||
else if ((opcodeNumber >= 15 && opcodeNumber <= 25) || opcodeNumber == 8 || opcodeNumber == 9)
|
opcodeLength = 1;
|
||||||
setStore (buffer);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public void setArguments (byte[] buffer)
|
||||||
public String opcodeName ()
|
{
|
||||||
{
|
if ((opcodeNumber >= 1 && opcodeNumber <= 7) || opcodeNumber == 10)
|
||||||
return name2OP[opcodeNumber];
|
setBranch (buffer);
|
||||||
}
|
else if ((opcodeNumber >= 15 && opcodeNumber <= 25) || opcodeNumber == 8
|
||||||
}
|
|| opcodeNumber == 9)
|
||||||
|
setStore (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
class Opcode2OPLong extends Opcode2OP
|
@Override
|
||||||
{
|
public String opcodeName ()
|
||||||
public Opcode2OPLong (byte[] buffer, int ptr)
|
{
|
||||||
{
|
return name2OP[opcodeNumber];
|
||||||
opcodeNumber = buffer[ptr] & 0x1F;
|
}
|
||||||
boolean bit1 = ((buffer[ptr] & 0x40) == 0x40);
|
}
|
||||||
boolean bit2 = ((buffer[ptr] & 0x20) == 0x20);
|
|
||||||
addOperand (buffer, ptr + 1, bit1);
|
|
||||||
addOperand (buffer, ptr + 1, bit2);
|
|
||||||
|
|
||||||
setArguments (buffer);
|
class Opcode2OPLong extends Opcode2OP
|
||||||
}
|
{
|
||||||
}
|
public Opcode2OPLong (byte[] buffer, int ptr)
|
||||||
|
{
|
||||||
|
opcodeNumber = buffer[ptr] & 0x1F;
|
||||||
|
boolean bit1 = ((buffer[ptr] & 0x40) == 0x40);
|
||||||
|
boolean bit2 = ((buffer[ptr] & 0x20) == 0x20);
|
||||||
|
addOperand (buffer, ptr + 1, bit1);
|
||||||
|
addOperand (buffer, ptr + 1, bit2);
|
||||||
|
|
||||||
class Opcode2OPVar extends Opcode2OP
|
setArguments (buffer);
|
||||||
{
|
}
|
||||||
public Opcode2OPVar (byte[] buffer, int ptr)
|
}
|
||||||
{
|
|
||||||
opcodeNumber = buffer[ptr] & 0x1F;
|
|
||||||
opcodeLength = 2;
|
|
||||||
setVariableOperands (ptr);
|
|
||||||
setArguments (buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OpcodeVar extends Opcode
|
class Opcode2OPVar extends Opcode2OP
|
||||||
{
|
{
|
||||||
public OpcodeVar (byte[] buffer, int ptr)
|
public Opcode2OPVar (byte[] buffer, int ptr)
|
||||||
{
|
{
|
||||||
opcodeNumber = buffer[ptr] & 0x1F;
|
opcodeNumber = buffer[ptr] & 0x1F;
|
||||||
opcodeLength = 2;
|
opcodeLength = 2;
|
||||||
setVariableOperands (ptr);
|
setVariableOperands (ptr);
|
||||||
|
setArguments (buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opcodeNumber == 0 || opcodeNumber == 7)
|
class OpcodeVar extends Opcode
|
||||||
setStore (buffer);
|
{
|
||||||
if (opcodeNumber == 0)
|
public OpcodeVar (byte[] buffer, int ptr)
|
||||||
{
|
{
|
||||||
isCall = true;
|
opcodeNumber = buffer[ptr] & 0x1F;
|
||||||
callTarget = operands.get (0).value * 2;
|
opcodeLength = 2;
|
||||||
}
|
setVariableOperands (ptr);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (opcodeNumber == 0 || opcodeNumber == 7)
|
||||||
public String opcodeName ()
|
setStore (buffer);
|
||||||
{
|
if (opcodeNumber == 0)
|
||||||
return nameVAR[opcodeNumber];
|
{
|
||||||
}
|
isCall = true;
|
||||||
}
|
callTarget = operands.get (0).value * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class Operand
|
@Override
|
||||||
{
|
public String opcodeName ()
|
||||||
int length;
|
{
|
||||||
int value;
|
return nameVAR[opcodeNumber];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class OperandWord extends Operand
|
abstract class Operand
|
||||||
{
|
{
|
||||||
public OperandWord (int value)
|
int length;
|
||||||
{
|
int value;
|
||||||
this.value = value;
|
OperandType operandType;
|
||||||
length = 2;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
class OperandWord extends Operand
|
||||||
public String toString ()
|
{
|
||||||
{
|
public OperandWord (int value)
|
||||||
return String.format ("#%05d", value);
|
{
|
||||||
}
|
this.value = value;
|
||||||
}
|
length = 2;
|
||||||
|
operandType = OperandType.WORD;
|
||||||
|
}
|
||||||
|
|
||||||
class OperandByte extends Operand
|
@Override
|
||||||
{
|
public String toString ()
|
||||||
public OperandByte (byte value)
|
{
|
||||||
{
|
return String.format ("#%05d", value);
|
||||||
this.value = value & 0xFF;
|
}
|
||||||
length = 1;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
class OperandByte extends Operand
|
||||||
public String toString ()
|
{
|
||||||
{
|
public OperandByte (byte value)
|
||||||
return String.format ("#%03d", value);
|
{
|
||||||
}
|
this.value = value & 0xFF;
|
||||||
}
|
length = 1;
|
||||||
|
operandType = OperandType.BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
class OperandVariable extends Operand
|
@Override
|
||||||
{
|
public String toString ()
|
||||||
public OperandVariable (byte value)
|
{
|
||||||
{
|
return String.format ("#%03d", value);
|
||||||
this.value = value & 0xFF;
|
}
|
||||||
length = 1;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
class OperandVariable extends Operand
|
||||||
public String toString ()
|
{
|
||||||
{
|
public OperandVariable (byte value)
|
||||||
if (value == 0)
|
{
|
||||||
return ("ToS");
|
this.value = value & 0xFF;
|
||||||
if (value <= 15)
|
length = 1;
|
||||||
return (String.format ("L%02d", value));
|
|
||||||
return String.format ("G%03d", (value - 15));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ArgumentBranch extends Operand
|
if (value == 0)
|
||||||
{
|
operandType = OperandType.VAR_STACK;
|
||||||
int target;
|
else if (value <= 15)
|
||||||
boolean branchOnTrue;
|
operandType = OperandType.VAR_LOCAL;
|
||||||
|
else
|
||||||
|
operandType = OperandType.VAR_GLOBAL;
|
||||||
|
}
|
||||||
|
|
||||||
public ArgumentBranch (byte value, int offset)
|
@Override
|
||||||
{
|
public String toString ()
|
||||||
branchOnTrue = (value & 0x80) == 0x80;
|
{
|
||||||
int val = value & 0x3F; // unsigned
|
if (operandType == OperandType.VAR_STACK)
|
||||||
if (val <= 1)
|
return ("ToS");
|
||||||
target = val;
|
if (operandType == OperandType.VAR_LOCAL)
|
||||||
else
|
return (String.format ("L%02d", value));
|
||||||
target = val + offset - 1;
|
return String.format ("G%03d", (value - 15));
|
||||||
length = 1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArgumentBranch (int value, int offset)
|
class ArgumentBranch extends Operand
|
||||||
{
|
{
|
||||||
branchOnTrue = (value & 0x8000) == 0x8000;
|
int target;
|
||||||
int val = value & 0x3FFF; // signed
|
boolean branchOnTrue;
|
||||||
if (val > 8191)
|
|
||||||
val -= 16384;
|
|
||||||
target = val + offset;
|
|
||||||
length = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public ArgumentBranch (byte value, int offset)
|
||||||
public String toString ()
|
{
|
||||||
{
|
branchOnTrue = (value & 0x80) == 0x80;
|
||||||
StringBuilder text = new StringBuilder ();
|
int val = value & 0x3F; // unsigned
|
||||||
text.append (" [" + (branchOnTrue ? "true" : "false") + "] ");
|
if (val <= 1)
|
||||||
if (target == 0 || target == 1)
|
target = val;
|
||||||
text.append (target == 0 ? "RFALSE" : "RTRUE");
|
else
|
||||||
else
|
target = val + offset - 1;
|
||||||
text.append (String.format ("%05X", target));
|
length = 1;
|
||||||
return text.toString ();
|
operandType = OperandType.ARG_BRANCH;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class ArgumentString extends Operand
|
public ArgumentBranch (int value, int offset)
|
||||||
{
|
{
|
||||||
ZString text;
|
branchOnTrue = (value & 0x8000) == 0x8000;
|
||||||
int startPtr;
|
int val = value & 0x3FFF; // signed
|
||||||
byte[] buffer;
|
if (val > 8191)
|
||||||
|
val -= 16384;
|
||||||
|
target = val + offset;
|
||||||
|
length = 2;
|
||||||
|
operandType = OperandType.ARG_BRANCH;
|
||||||
|
}
|
||||||
|
|
||||||
public ArgumentString (byte[] buffer, int offset)
|
@Override
|
||||||
{
|
public String toString ()
|
||||||
this.buffer = buffer;
|
{
|
||||||
text = new ZString (buffer, offset, header);
|
StringBuilder text = new StringBuilder ();
|
||||||
length = text.length;
|
text.append (" [" + (branchOnTrue ? "true" : "false") + "] ");
|
||||||
}
|
if (target == 0 || target == 1)
|
||||||
|
text.append (target == 0 ? "RFALSE" : "RTRUE");
|
||||||
|
else
|
||||||
|
text.append (String.format ("%05X", target));
|
||||||
|
return text.toString ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
class ArgumentString extends Operand
|
||||||
public String toString ()
|
{
|
||||||
{
|
ZString text;
|
||||||
return text.value;
|
int startPtr;
|
||||||
}
|
byte[] buffer;
|
||||||
}
|
|
||||||
|
public ArgumentString (byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
this.buffer = buffer;
|
||||||
|
text = new ZString (header, offset);
|
||||||
|
length = text.length;
|
||||||
|
operandType = OperandType.ARG_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return text.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -8,210 +8,212 @@ import com.bytezone.diskbrowser.infocom.ZObject.Property;
|
|||||||
|
|
||||||
class ObjectAnalyser
|
class ObjectAnalyser
|
||||||
{
|
{
|
||||||
Header header;
|
Header header;
|
||||||
ObjectManager parent;
|
ObjectManager parent;
|
||||||
List<Statistics> list = new ArrayList<Statistics> ();
|
List<Statistics> list = new ArrayList<Statistics> ();
|
||||||
List<Integer> routines = new ArrayList<Integer> ();
|
List<Integer> routines = new ArrayList<Integer> ();
|
||||||
|
|
||||||
public ObjectAnalyser (Header header, ObjectManager parent)
|
public ObjectAnalyser (Header header, ObjectManager parent)
|
||||||
{
|
{
|
||||||
this.header = header;
|
this.header = header;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
|
||||||
// assign the DICT property for each object
|
// assign the DICT property for each object
|
||||||
setDictionary ();
|
setDictionary ();
|
||||||
|
|
||||||
// find the point where code ends and strings begin
|
// find the point where code ends and strings begin
|
||||||
setStringPointer ();
|
setStringPointer ();
|
||||||
|
|
||||||
// add routines called from object properties (requires stringPointer)
|
// add routines called from object properties (requires stringPointer)
|
||||||
createPropertyLinks ();
|
createPropertyLinks ();
|
||||||
|
|
||||||
// assumes that all properties with exactly three bytes are routine addresses
|
// assumes that all properties with exactly three bytes are routine addresses
|
||||||
// checkThreeByteProperties ();
|
// checkThreeByteProperties ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStringPointer ()
|
public void setStringPointer ()
|
||||||
{
|
{
|
||||||
PropertyTester pt = new PropertyTester (parent.list);
|
PropertyTester pt = new PropertyTester (parent.getObjects ());
|
||||||
pt.addTest (new LengthTwoCondition ());
|
pt.addTest (new LengthTwoCondition ());
|
||||||
HighMemoryCondition hmc = new HighMemoryCondition ();
|
HighMemoryCondition hmc = new HighMemoryCondition ();
|
||||||
pt.addTest (hmc);
|
pt.addTest (hmc);
|
||||||
pt.doTests ();
|
pt.doTests ();
|
||||||
|
|
||||||
System.out.println ("\nSetting the string pointer\n");
|
// System.out.println ("\nSetting the string pointer\n");
|
||||||
|
|
||||||
for (Integer propertyNo : pt)
|
for (Integer propertyNo : pt)
|
||||||
// list of all properties that passed all tests
|
// list of all properties that passed all tests
|
||||||
list.add (hmc.statistics[propertyNo]);
|
list.add (hmc.statistics[propertyNo]);
|
||||||
Collections.sort (list);
|
Collections.sort (list);
|
||||||
|
|
||||||
// Calculate lowest string pointer
|
// Calculate lowest string pointer
|
||||||
int lo = list.get (0).lo;
|
int lo = list.get (0).lo;
|
||||||
for (Statistics s : list)
|
for (Statistics s : list)
|
||||||
{
|
{
|
||||||
System.out.println (s);
|
System.out.println (s);
|
||||||
if (s.hi > lo && s.lo < lo)
|
if (s.hi > lo && s.lo < lo)
|
||||||
lo = s.lo;
|
lo = s.lo;
|
||||||
if (s.hi < lo)
|
if (s.hi < lo)
|
||||||
{
|
{
|
||||||
header.stringPointer = lo;
|
header.stringPointer = lo;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createPropertyLinks ()
|
public void createPropertyLinks ()
|
||||||
{
|
{
|
||||||
int sCount = 0;
|
int sCount = 0;
|
||||||
int rCount = 0;
|
int rCount = 0;
|
||||||
int totStrings = 0;
|
int totStrings = 0;
|
||||||
int totRoutines = 0;
|
int totRoutines = 0;
|
||||||
|
|
||||||
for (Statistics s : list)
|
for (Statistics s : list)
|
||||||
{
|
{
|
||||||
if (header.propertyNames[s.propertyNumber].charAt (0) >= 'a')
|
if (header.getPropertyName (s.propertyNumber).charAt (0) >= 'a')
|
||||||
continue;
|
continue;
|
||||||
if (s.lo >= header.stringPointer)
|
if (s.lo >= header.stringPointer)
|
||||||
{
|
{
|
||||||
header.propertyNames[s.propertyNumber] = "STR" + ++sCount;
|
header.propertyNames[s.propertyNumber] = "STR" + ++sCount;
|
||||||
totStrings += s.offsets.size ();
|
totStrings += s.offsets.size ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
header.propertyNames[s.propertyNumber] = "CODE" + ++rCount;
|
header.propertyNames[s.propertyNumber] = "CODE" + ++rCount;
|
||||||
routines.addAll (s.offsets);
|
routines.addAll (s.offsets);
|
||||||
totRoutines += s.offsets.size ();
|
totRoutines += s.offsets.size ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
System.out.println ("Strings found : " + totStrings);
|
System.out.println ("Strings found : " + totStrings);
|
||||||
System.out.println ("Routines found : " + totRoutines);
|
System.out.println ("Routines found : " + totRoutines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkThreeByteProperties ()
|
public void checkThreeByteProperties ()
|
||||||
{
|
{
|
||||||
for (ZObject object : parent.list)
|
for (ZObject object : parent.getObjects ())
|
||||||
{
|
{
|
||||||
for (Property property : object.properties)
|
for (Property property : object.properties)
|
||||||
{
|
{
|
||||||
if (header.propertyNames[property.propertyNumber].charAt (0) < 'a' && property.length == 3)
|
if (header.getPropertyName (property.propertyNumber).charAt (0) < 'a'
|
||||||
{
|
&& property.length == 3)
|
||||||
int address = header.getWord (property.ptr + 1) * 2;
|
{
|
||||||
System.out.println ("checking " + address);
|
int address = header.getWord (property.ptr + 1) * 2;
|
||||||
header.codeManager.addRoutine (address, 0);
|
System.out.println ("checking " + address);
|
||||||
}
|
header.codeManager.addRoutine (address, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// find the property with only dictionary entries
|
// find the property with only dictionary entries
|
||||||
public void setDictionary ()
|
public void setDictionary ()
|
||||||
{
|
{
|
||||||
PropertyTester pt = new PropertyTester (parent.list);
|
PropertyTester pt = new PropertyTester (parent.getObjects ());
|
||||||
pt.addTest (new LengthEvenCondition ());
|
pt.addTest (new LengthEvenCondition ());
|
||||||
pt.addTest (new ValidDictionaryCondition ());
|
pt.addTest (new ValidDictionaryCondition ());
|
||||||
pt.doTests ();
|
pt.doTests ();
|
||||||
|
|
||||||
for (Integer i : pt)
|
for (Integer i : pt)
|
||||||
// should only be one
|
// should only be one
|
||||||
header.propertyNames[i] = "DICT";
|
header.propertyNames[i] = "DICT"; // SYNONYM
|
||||||
}
|
}
|
||||||
|
|
||||||
class Statistics implements Comparable<Statistics>
|
class Statistics implements Comparable<Statistics>
|
||||||
{
|
{
|
||||||
int propertyNumber;
|
int propertyNumber;
|
||||||
int lo;
|
int lo;
|
||||||
int hi;
|
int hi;
|
||||||
List<Integer> offsets = new ArrayList<Integer> ();
|
List<Integer> offsets = new ArrayList<Integer> ();
|
||||||
|
|
||||||
public Statistics (int propertyNumber)
|
public Statistics (int propertyNumber)
|
||||||
{
|
{
|
||||||
this.propertyNumber = propertyNumber;
|
this.propertyNumber = propertyNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void increment (Property property)
|
public void increment (Property property)
|
||||||
{
|
{
|
||||||
offsets.add (property.offset);
|
offsets.add (property.offset);
|
||||||
if (property.offset > hi)
|
if (property.offset > hi)
|
||||||
hi = property.offset;
|
hi = property.offset;
|
||||||
if (property.offset < lo || lo == 0)
|
if (property.offset < lo || lo == 0)
|
||||||
lo = property.offset;
|
lo = property.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString ()
|
public String toString ()
|
||||||
{
|
{
|
||||||
return String.format ("%2d %3d %,7d %,7d", propertyNumber, offsets.size (), lo, hi);
|
return String.format ("%2d %3d %,7d %,7d", propertyNumber, offsets.size (),
|
||||||
}
|
lo, hi);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo (Statistics o)
|
public int compareTo (Statistics o)
|
||||||
{
|
{
|
||||||
return o.hi - hi;
|
return o.hi - hi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LengthTwoCondition extends Condition
|
class LengthTwoCondition extends Condition
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
boolean test (Property property)
|
boolean test (Property property)
|
||||||
{
|
{
|
||||||
return property.length == 2;
|
return property.length == 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LengthThreeCondition extends Condition
|
class LengthThreeCondition extends Condition
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
boolean test (Property property)
|
boolean test (Property property)
|
||||||
{
|
{
|
||||||
return property.length == 3;
|
return property.length == 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LengthEvenCondition extends Condition
|
class LengthEvenCondition extends Condition
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
boolean test (Property property)
|
boolean test (Property property)
|
||||||
{
|
{
|
||||||
return (property.length % 2) == 0;
|
return (property.length % 2) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HighMemoryCondition extends Condition
|
class HighMemoryCondition extends Condition
|
||||||
{
|
{
|
||||||
int lo, hi;
|
int lo, hi;
|
||||||
Statistics[] statistics = new Statistics[32]; // note there is no property #0
|
Statistics[] statistics = new Statistics[32]; // note there is no property #0
|
||||||
|
|
||||||
public HighMemoryCondition ()
|
public HighMemoryCondition ()
|
||||||
{
|
{
|
||||||
lo = header.highMemory;
|
lo = header.highMemory;
|
||||||
hi = header.fileLength;
|
hi = header.fileLength;
|
||||||
for (int i = 1; i < statistics.length; i++)
|
for (int i = 1; i < statistics.length; i++)
|
||||||
statistics[i] = new Statistics (i);
|
statistics[i] = new Statistics (i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean test (Property property)
|
boolean test (Property property)
|
||||||
{
|
{
|
||||||
statistics[property.propertyNumber].increment (property);
|
statistics[property.propertyNumber].increment (property);
|
||||||
int address = header.getWord (property.ptr + 1) * 2;
|
int address = header.getWord (property.ptr + 1) * 2;
|
||||||
return (address >= lo && address < hi) || address == 0;
|
return (address >= lo && address < hi) || address == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ValidDictionaryCondition extends Condition
|
class ValidDictionaryCondition extends Condition
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
boolean test (Property property)
|
boolean test (Property property)
|
||||||
{
|
{
|
||||||
for (int i = 1; i <= property.length; i += 2)
|
for (int i = 1; i <= property.length; i += 2)
|
||||||
{
|
{
|
||||||
int address = header.getWord (property.ptr + i);
|
int address = header.getWord (property.ptr + i);
|
||||||
if (!header.containsWordAt (address))
|
if (!header.containsWordAt (address))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package com.bytezone.diskbrowser.infocom;
|
package com.bytezone.diskbrowser.infocom;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -11,21 +12,22 @@ import com.bytezone.diskbrowser.disk.FormattedDisk;
|
|||||||
|
|
||||||
class ObjectManager extends InfocomAbstractFile implements Iterable<ZObject>
|
class ObjectManager extends InfocomAbstractFile implements Iterable<ZObject>
|
||||||
{
|
{
|
||||||
Header header;
|
private final Header header;
|
||||||
List<ZObject> list;
|
private final List<ZObject> list;
|
||||||
int defaultsPtr, defaultsSize;
|
private List<ZObject> sortedList;
|
||||||
int tablePtr, tableSize;
|
private final int defaultsPtr, defaultsSize;
|
||||||
int propertyPtr, propertySize;
|
private final int tablePtr, tableSize;
|
||||||
ObjectAnalyser analyser;
|
private final int propertyPtr, propertySize;
|
||||||
|
private final ObjectAnalyser analyser;
|
||||||
|
|
||||||
public ObjectManager (Header header)
|
public ObjectManager (Header header)
|
||||||
{
|
{
|
||||||
super ("Objects", header.buffer);
|
super ("Objects", header.buffer);
|
||||||
this.header = header;
|
this.header = header;
|
||||||
|
|
||||||
defaultsPtr = header.objectTable;
|
defaultsPtr = header.objectTableOffset;
|
||||||
defaultsSize = 62;
|
defaultsSize = 62;
|
||||||
tablePtr = header.objectTable + 62;
|
tablePtr = header.objectTableOffset + 62;
|
||||||
propertyPtr = header.getWord (tablePtr + 7);
|
propertyPtr = header.getWord (tablePtr + 7);
|
||||||
propertySize = header.globalsOffset - propertyPtr;
|
propertySize = header.globalsOffset - propertyPtr;
|
||||||
tableSize = (propertyPtr - tablePtr);
|
tableSize = (propertyPtr - tablePtr);
|
||||||
@ -45,6 +47,16 @@ class ObjectManager extends InfocomAbstractFile implements Iterable<ZObject>
|
|||||||
hexBlocks.add (new HexBlock (propertyPtr, propertySize, "Properties:"));
|
hexBlocks.add (new HexBlock (propertyPtr, propertySize, "Properties:"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ZObject> getObjects ()
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZObject getObject (int index)
|
||||||
|
{
|
||||||
|
return list.get (index);
|
||||||
|
}
|
||||||
|
|
||||||
public void addNodes (DefaultMutableTreeNode root, FormattedDisk disk)
|
public void addNodes (DefaultMutableTreeNode root, FormattedDisk disk)
|
||||||
{
|
{
|
||||||
root.setAllowsChildren (true);
|
root.setAllowsChildren (true);
|
||||||
@ -61,10 +73,9 @@ class ObjectManager extends InfocomAbstractFile implements Iterable<ZObject>
|
|||||||
new DefaultAppleFileSource (object.getName (), object, disk));
|
new DefaultAppleFileSource (object.getName (), object, disk));
|
||||||
parentNode.add (child);
|
parentNode.add (child);
|
||||||
if (object.sibling > 0)
|
if (object.sibling > 0)
|
||||||
buildObjectTree (header.objectManager.list.get (object.sibling - 1), parentNode,
|
buildObjectTree (list.get (object.sibling - 1), parentNode, disk);
|
||||||
disk);
|
|
||||||
if (object.child > 0)
|
if (object.child > 0)
|
||||||
buildObjectTree (header.objectManager.list.get (object.child - 1), child, disk);
|
buildObjectTree (list.get (object.child - 1), child, disk);
|
||||||
else
|
else
|
||||||
child.setAllowsChildren (false);
|
child.setAllowsChildren (false);
|
||||||
}
|
}
|
||||||
@ -77,8 +88,8 @@ class ObjectManager extends InfocomAbstractFile implements Iterable<ZObject>
|
|||||||
@Override
|
@Override
|
||||||
public String getText ()
|
public String getText ()
|
||||||
{
|
{
|
||||||
String header1 = "ID Attributes Pr Sb Ch Prop Title\n-- -----------"
|
// String header1 = "ID Attributes Pr Sb Ch Prop Title\n-- -----------"
|
||||||
+ " -- -- -- ----- -----------------------------\n";
|
// + " -- -- -- ----- -----------------------------\n";
|
||||||
String underline = " ----------------------------------------";
|
String underline = " ----------------------------------------";
|
||||||
String titles[] =
|
String titles[] =
|
||||||
{ "ID ", "Title ",
|
{ "ID ", "Title ",
|
||||||
@ -89,13 +100,21 @@ class ObjectManager extends InfocomAbstractFile implements Iterable<ZObject>
|
|||||||
+ "-- " + underline + underline + underline + underline + " ----------- -----\n";
|
+ "-- " + underline + underline + underline + underline + " ----------- -----\n";
|
||||||
StringBuilder text = new StringBuilder (header2);
|
StringBuilder text = new StringBuilder (header2);
|
||||||
|
|
||||||
int objectNumber = 0;
|
if (sortedList == null)
|
||||||
|
sortedList = new ArrayList<> (list);
|
||||||
|
Collections.sort (sortedList);
|
||||||
|
|
||||||
|
// int objectNumber = 0;
|
||||||
for (ZObject zo : list)
|
for (ZObject zo : list)
|
||||||
if (false)
|
// if (false)
|
||||||
text.append (String.format ("%02X %s%n", ++objectNumber, zo));
|
// text.append (String.format ("%02X %s%n", ++objectNumber, zo));
|
||||||
else
|
// else
|
||||||
text.append (
|
text.append (String.format ("%02X %s%n", zo.getId (), zo.getDescription (list)));
|
||||||
String.format ("%02X %s%n", ++objectNumber, zo.getDescription (list)));
|
|
||||||
|
text.append ("\n\n");
|
||||||
|
text.append (header2);
|
||||||
|
for (ZObject zo : sortedList)
|
||||||
|
text.append (String.format ("%02X %s%n", zo.getId (), zo.getDescription (list)));
|
||||||
|
|
||||||
text.deleteCharAt (text.length () - 1);
|
text.deleteCharAt (text.length () - 1);
|
||||||
return text.toString ();
|
return text.toString ();
|
||||||
|
@ -33,7 +33,7 @@ class PropertyManager extends AbstractFile
|
|||||||
for (Statistic stat : list)
|
for (Statistic stat : list)
|
||||||
if (stat.list.size () > 0)
|
if (stat.list.size () > 0)
|
||||||
{
|
{
|
||||||
String title = "Property " + header.propertyNames[stat.id].trim ();
|
String title = "Property " + header.getPropertyName (stat.id).trim ();
|
||||||
DefaultMutableTreeNode child = new DefaultMutableTreeNode (
|
DefaultMutableTreeNode child = new DefaultMutableTreeNode (
|
||||||
new DefaultAppleFileSource (title, stat.getText (), disk));
|
new DefaultAppleFileSource (title, stat.getText (), disk));
|
||||||
node.add (child);
|
node.add (child);
|
||||||
@ -72,13 +72,13 @@ class PropertyManager extends AbstractFile
|
|||||||
|
|
||||||
String getText ()
|
String getText ()
|
||||||
{
|
{
|
||||||
StringBuilder text =
|
StringBuilder text = new StringBuilder (String
|
||||||
new StringBuilder ("Objects with property " + id + " set:\n\n");
|
.format ("Objects with property %d %s set:%n%n", id, header.propertyNames[id]));
|
||||||
for (ZObject o : list)
|
for (ZObject o : list)
|
||||||
{
|
{
|
||||||
ZObject.Property p = o.getProperty (id);
|
ZObject.Property p = o.getProperty (id);
|
||||||
text.append (String.format ("%02X %-29s%s%n", o.id, o.getName (),
|
text.append (String.format ("%02X %-29s%s%n", o.getId (), o.getName (),
|
||||||
p.toString ().substring (7)));
|
p.toString ().substring (11)));
|
||||||
}
|
}
|
||||||
if (text.length () > 0)
|
if (text.length () > 0)
|
||||||
text.deleteCharAt (text.length () - 1);
|
text.deleteCharAt (text.length () - 1);
|
||||||
@ -88,7 +88,7 @@ class PropertyManager extends AbstractFile
|
|||||||
@Override
|
@Override
|
||||||
public String toString ()
|
public String toString ()
|
||||||
{
|
{
|
||||||
return String.format (" %2d %-6s %3d", id, header.propertyNames[id],
|
return String.format (" %2d %-6s %3d", id, header.getPropertyName (id),
|
||||||
list.size ());
|
list.size ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,15 @@ import java.util.ArrayList;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.bytezone.diskbrowser.infocom.Instruction.Operand;
|
||||||
|
import com.bytezone.diskbrowser.infocom.Instruction.OperandType;
|
||||||
|
|
||||||
class Routine extends InfocomAbstractFile
|
class Routine extends InfocomAbstractFile
|
||||||
implements Iterable<Instruction>, Comparable<Routine>
|
implements Iterable<Instruction>, Comparable<Routine>
|
||||||
{
|
{
|
||||||
private static final String padding = " ";
|
private static final String padding = " ";
|
||||||
|
|
||||||
int startPtr, length, strings, locals;
|
int startPtr, length, strings, locals;
|
||||||
// private final Header header;
|
|
||||||
|
|
||||||
List<Parameter> parameters = new ArrayList<Parameter> ();
|
List<Parameter> parameters = new ArrayList<Parameter> ();
|
||||||
List<Instruction> instructions = new ArrayList<Instruction> ();
|
List<Instruction> instructions = new ArrayList<Instruction> ();
|
||||||
@ -21,11 +23,13 @@ class Routine extends InfocomAbstractFile
|
|||||||
public Routine (int ptr, Header header, int caller)
|
public Routine (int ptr, Header header, int caller)
|
||||||
{
|
{
|
||||||
super (String.format ("Routine %05X", ptr), header.buffer);
|
super (String.format ("Routine %05X", ptr), header.buffer);
|
||||||
// this.header = header;
|
|
||||||
|
|
||||||
locals = buffer[ptr] & 0xFF;
|
locals = buffer[ptr] & 0xFF;
|
||||||
if (locals > 15)
|
if (locals > 15)
|
||||||
|
{
|
||||||
|
System.out.println ("Too many locals: " + locals);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
startPtr = ptr++; // also used to flag a valid routine
|
startPtr = ptr++; // also used to flag a valid routine
|
||||||
calledBy.add (caller);
|
calledBy.add (caller);
|
||||||
@ -53,6 +57,10 @@ class Routine extends InfocomAbstractFile
|
|||||||
if (instruction.isPrint ())
|
if (instruction.isPrint ())
|
||||||
strings++;
|
strings++;
|
||||||
|
|
||||||
|
for (Operand operand : instruction.opcode.operands)
|
||||||
|
if (operand.operandType == OperandType.VAR_GLOBAL)
|
||||||
|
header.globals.addRoutine (this, operand);
|
||||||
|
|
||||||
ptr += instruction.length ();
|
ptr += instruction.length ();
|
||||||
|
|
||||||
// is it a backwards jump?
|
// is it a backwards jump?
|
||||||
|
@ -20,9 +20,9 @@ class StringManager extends AbstractFile
|
|||||||
int max = header.fileLength;
|
int max = header.fileLength;
|
||||||
while (ptr < max)
|
while (ptr < max)
|
||||||
{
|
{
|
||||||
ZString zs = new ZString (buffer, ptr, header);
|
ZString zs = new ZString (header, ptr);
|
||||||
if (zs.value == null)
|
if (zs.value == null)
|
||||||
break; // used when eof not known or correct - fix!!
|
break; // used when eof not known or correct - fix!!
|
||||||
strings.put (ptr, zs);
|
strings.put (ptr, zs);
|
||||||
ptr += zs.length;
|
ptr += zs.length;
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ class StringManager extends AbstractFile
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
text.append (" # Start String\n");
|
text.append (" # Start String\n");
|
||||||
text.append ("--- ----- --------------------------------------------------------"
|
text.append ("--- ----- --------------------------------------------------------"
|
||||||
+ "-------------------\n");
|
+ "-------------------\n");
|
||||||
|
|
||||||
for (ZString s : strings.values ())
|
for (ZString s : strings.values ())
|
||||||
{
|
{
|
||||||
|
@ -7,26 +7,28 @@ import java.util.List;
|
|||||||
import com.bytezone.diskbrowser.applefile.AbstractFile;
|
import com.bytezone.diskbrowser.applefile.AbstractFile;
|
||||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||||
|
|
||||||
class ZObject extends AbstractFile
|
class ZObject extends AbstractFile implements Comparable<ZObject>
|
||||||
{
|
{
|
||||||
static final int HEADER_SIZE = 9;
|
static final int HEADER_SIZE = 9;
|
||||||
|
|
||||||
int id;
|
private final Header header;
|
||||||
int startPtr;
|
private final int id;
|
||||||
int propertyTablePtr;
|
private final int startPtr;
|
||||||
int propertyTableLength;
|
|
||||||
int parent, sibling, child;
|
|
||||||
List<Property> properties = new ArrayList<Property> ();
|
|
||||||
Header header;
|
|
||||||
BitSet attributes = new BitSet (32);
|
|
||||||
|
|
||||||
public ZObject (String name, byte[] buffer, int offset, int seq, Header header)
|
private final int propertyTablePtr;
|
||||||
|
private final int propertyTableLength;
|
||||||
|
|
||||||
|
final int parent, sibling, child;
|
||||||
|
final List<Property> properties = new ArrayList<Property> ();
|
||||||
|
final BitSet attributes = new BitSet (32);
|
||||||
|
|
||||||
|
public ZObject (String name, byte[] buffer, int offset, int id, Header header)
|
||||||
{
|
{
|
||||||
super (name, buffer);
|
super (name, buffer);
|
||||||
|
|
||||||
this.header = header;
|
this.header = header;
|
||||||
this.startPtr = offset;
|
this.startPtr = offset;
|
||||||
id = seq;
|
this.id = id;
|
||||||
|
|
||||||
// attributes
|
// attributes
|
||||||
int bitIndex = 0;
|
int bitIndex = 0;
|
||||||
@ -51,19 +53,24 @@ class ZObject extends AbstractFile
|
|||||||
propertyTablePtr = header.getWord (offset + 7);
|
propertyTablePtr = header.getWord (offset + 7);
|
||||||
int ptr = propertyTablePtr;
|
int ptr = propertyTablePtr;
|
||||||
int nameLength = header.getByte (ptr) * 2;
|
int nameLength = header.getByte (ptr) * 2;
|
||||||
this.name = nameLength == 0 ? "<<none>>" : new ZString (buffer, ++ptr, header).value;
|
this.name = nameLength == 0 ? "<<" + id + ">>" : new ZString (header, ++ptr).value;
|
||||||
ptr += nameLength;
|
ptr += nameLength;
|
||||||
|
|
||||||
// read each property
|
// read each property
|
||||||
while (buffer[ptr] != 0)
|
while (buffer[ptr] != 0)
|
||||||
{
|
{
|
||||||
Property p = new Property (buffer, ptr);
|
Property p = new Property (ptr);
|
||||||
properties.add (p);
|
properties.add (p);
|
||||||
ptr += p.length + 1;
|
ptr += p.length + 1;
|
||||||
}
|
}
|
||||||
propertyTableLength = ptr - propertyTablePtr;
|
propertyTableLength = ptr - propertyTablePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getId ()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getText ()
|
public String getText ()
|
||||||
{
|
{
|
||||||
@ -71,9 +78,9 @@ class ZObject extends AbstractFile
|
|||||||
|
|
||||||
text.append (String.format ("ID : %02X (%<3d) %s%n%n", id, name));
|
text.append (String.format ("ID : %02X (%<3d) %s%n%n", id, name));
|
||||||
|
|
||||||
String obj1 = parent == 0 ? "" : header.objectManager.list.get (parent - 1).name;
|
String obj1 = parent == 0 ? "" : header.getObject (parent - 1).name;
|
||||||
String obj2 = sibling == 0 ? "" : header.objectManager.list.get (sibling - 1).name;
|
String obj2 = sibling == 0 ? "" : header.getObject (sibling - 1).name;
|
||||||
String obj3 = child == 0 ? "" : header.objectManager.list.get (child - 1).name;
|
String obj3 = child == 0 ? "" : header.getObject (child - 1).name;
|
||||||
|
|
||||||
text.append (String.format ("Parent : %02X (%<3d) %s%n", parent, obj1));
|
text.append (String.format ("Parent : %02X (%<3d) %s%n", parent, obj1));
|
||||||
text.append (String.format ("Sibling : %02X (%<3d) %s%n", sibling, obj2));
|
text.append (String.format ("Sibling : %02X (%<3d) %s%n", sibling, obj2));
|
||||||
@ -140,7 +147,7 @@ class ZObject extends AbstractFile
|
|||||||
int length;
|
int length;
|
||||||
int offset; // only used if length == 2
|
int offset; // only used if length == 2
|
||||||
|
|
||||||
public Property (byte[] buffer, int ptr)
|
public Property (int ptr)
|
||||||
{
|
{
|
||||||
this.ptr = ptr;
|
this.ptr = ptr;
|
||||||
length = header.getByte (ptr) / 32 + 1;
|
length = header.getByte (ptr) / 32 + 1;
|
||||||
@ -152,41 +159,53 @@ class ZObject extends AbstractFile
|
|||||||
|
|
||||||
private ZObject getObject ()
|
private ZObject getObject ()
|
||||||
{
|
{
|
||||||
return header.objectManager.list.get ((buffer[ptr + 1] & 0xFF) - 1);
|
return header.getObject ((buffer[ptr + 1] & 0xFF) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZObject getObject (int id)
|
||||||
|
{
|
||||||
|
return header.getObject (id - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString ()
|
public String toString ()
|
||||||
{
|
{
|
||||||
StringBuilder text = new StringBuilder (
|
StringBuilder text = new StringBuilder (
|
||||||
String.format ("%5s : ", header.propertyNames[propertyNumber]));
|
String.format ("%8s : ", header.getPropertyName (propertyNumber)));
|
||||||
|
|
||||||
String propertyType = header.propertyNames[propertyNumber];
|
String propertyType = header.getPropertyName (propertyNumber);
|
||||||
|
|
||||||
if (!propertyType.equals ("DICT") && !propertyType.contains ("STR"))
|
if (!(propertyType.equals ("DICT") || propertyType.startsWith ("STR")))
|
||||||
text.append (
|
text.append (
|
||||||
String.format ("%-20s", HexFormatter.getHexString (buffer, ptr + 1, length)));
|
String.format ("%-20s", HexFormatter.getHexString (buffer, ptr + 1, length)));
|
||||||
|
|
||||||
if (propertyType.charAt (0) >= 'a') // directions are in lowercase
|
if (propertyNumber >= 19) // directions
|
||||||
{
|
{
|
||||||
switch (length)
|
switch (length)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1: // UEXIT - unconditional exit
|
||||||
text.append (getObject ().name);
|
text.append (getObject ().name);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
text.append ("\"" + header.stringManager.stringAt (offset) + "\"");
|
text.append ("\"" + header.stringManager.stringAt (offset) + "\"");
|
||||||
break;
|
break;
|
||||||
case 3: // executable routine
|
case 3: // FEXIT - function exit
|
||||||
int address = header.getWord (ptr + 1) * 2;
|
int address = header.getWord (ptr + 1) * 2;
|
||||||
text.append (String.format ("R:%05X", address));
|
text.append (String.format ("R:%05X", address));
|
||||||
appendRoutine (text, address);
|
appendRoutine (text, address);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
// text.append (getObject ().name + " : ");
|
||||||
|
text.append (String.format ("%s : IF G%02X ELSE ", getObject ().name,
|
||||||
|
header.getByte (ptr + 2)));
|
||||||
address = header.getWord (ptr + 3) * 2;
|
address = header.getWord (ptr + 3) * 2;
|
||||||
if (address > 0)
|
if (address > 0)
|
||||||
text.append ("\"" + header.stringManager.stringAt (address) + "\"");
|
text.append ("\"" + header.stringManager.stringAt (address) + "\"");
|
||||||
break;
|
break;
|
||||||
|
case 5:
|
||||||
|
text.append (String.format ("%s : IF G%02X ", getObject ().name,
|
||||||
|
header.getByte (ptr + 2)));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -196,7 +215,7 @@ class ZObject extends AbstractFile
|
|||||||
for (int i = 1; i <= length; i += 2)
|
for (int i = 1; i <= length; i += 2)
|
||||||
{
|
{
|
||||||
int address = header.getWord (ptr + i);
|
int address = header.getWord (ptr + i);
|
||||||
text.append (header.wordAt (address) + ", ");
|
text.append (String.format ("%02X: %s, ", address, header.wordAt (address)));
|
||||||
}
|
}
|
||||||
text.deleteCharAt (text.length () - 1);
|
text.deleteCharAt (text.length () - 1);
|
||||||
text.deleteCharAt (text.length () - 1);
|
text.deleteCharAt (text.length () - 1);
|
||||||
@ -211,6 +230,33 @@ class ZObject extends AbstractFile
|
|||||||
text.append (String.format ("(%4X) \"%s\"", offset,
|
text.append (String.format ("(%4X) \"%s\"", offset,
|
||||||
header.stringManager.stringAt (offset)));
|
header.stringManager.stringAt (offset)));
|
||||||
}
|
}
|
||||||
|
else if (propertyType.equals ("ADJ"))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (propertyType.equals ("SIZE"))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (propertyType.equals ("VALUE"))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (propertyType.equals ("TVALU"))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (propertyType.equals ("GLBL"))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
int objectId = header.getByte (ptr + i + 1);
|
||||||
|
text.append (
|
||||||
|
String.format ("%s%s", (i == 0 ? "" : ", "), getObject (objectId).name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
// text.append ("Unknown property type: " + propertyType);
|
||||||
|
|
||||||
return text.toString ();
|
return text.toString ();
|
||||||
}
|
}
|
||||||
@ -224,4 +270,10 @@ class ZObject extends AbstractFile
|
|||||||
text.append ("\n\n****** null routine\n");
|
text.append ("\n\n****** null routine\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo (ZObject o)
|
||||||
|
{
|
||||||
|
return this.name.compareTo (o.name);
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,155 +2,157 @@ package com.bytezone.diskbrowser.infocom;
|
|||||||
|
|
||||||
class ZString
|
class ZString
|
||||||
{
|
{
|
||||||
private static String[] letters =
|
private static String[] letters =
|
||||||
{ " abcdefghijklmnopqrstuvwxyz", " ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
{ " abcdefghijklmnopqrstuvwxyz", " ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
" 0123456789.,!?_#\'\"/\\-:()" };
|
" 0123456789.,!?_#\'\"/\\-:()" };
|
||||||
String value;
|
String value;
|
||||||
Header header;
|
Header header;
|
||||||
int startPtr;
|
int startPtr;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
public ZString (byte[] buffer, int offset, Header header)
|
public ZString (Header header, int offset)
|
||||||
{
|
{
|
||||||
ZStringBuilder text = new ZStringBuilder ();
|
ZStringBuilder text = new ZStringBuilder ();
|
||||||
this.header = header;
|
this.header = header;
|
||||||
this.startPtr = offset;
|
this.startPtr = offset;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (offset >= header.buffer.length - 1)
|
if (offset >= header.buffer.length - 1)
|
||||||
{
|
{
|
||||||
System.out.println ("********" + text.toString ());
|
System.out.println ("********" + text.toString ());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the next two bytes
|
// get the next two bytes
|
||||||
int val = header.getWord (offset);
|
int val = header.getWord (offset);
|
||||||
|
|
||||||
// process each zChar as a 5-bit value
|
// process each zChar as a 5-bit value
|
||||||
text.processZChar ((byte) ((val >> 10) & 0x1F));
|
text.processZChar ((byte) ((val >>> 10) & 0x1F));
|
||||||
text.processZChar ((byte) ((val >> 5) & 0x1F));
|
text.processZChar ((byte) ((val >>> 5) & 0x1F));
|
||||||
text.processZChar ((byte) (val & 0x1F));
|
text.processZChar ((byte) (val & 0x1F));
|
||||||
|
|
||||||
if ((val & 0x8000) > 0) // bit 15 = finished flag
|
if ((val & 0x8000) != 0) // bit 15 = finished flag
|
||||||
{
|
{
|
||||||
length = offset - startPtr + 2;
|
length = offset - startPtr + 2;
|
||||||
value = text.toString ();
|
value = text.toString ();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
offset += 2;
|
offset += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString ()
|
public String toString ()
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ZStringBuilder
|
private class ZStringBuilder
|
||||||
{
|
{
|
||||||
int alphabet;
|
int alphabet;
|
||||||
boolean shift;
|
boolean shift;
|
||||||
int shiftAlphabet;
|
int shiftAlphabet;
|
||||||
int synonym;
|
int synonym;
|
||||||
int buildingLevel;
|
int buildingLevel;
|
||||||
int builtLetter;
|
int builtLetter;
|
||||||
StringBuilder text = new StringBuilder ();
|
StringBuilder text = new StringBuilder ();
|
||||||
|
|
||||||
private void processZChar (byte zchar)
|
private void processZChar (byte zchar)
|
||||||
{
|
{
|
||||||
// A flag to indicate that we are building a character not in the alphabet. The
|
// A flag to indicate that we are building a character not in the alphabet. The
|
||||||
// value indicates which half of the character the current zchar goes into. Once
|
// value indicates which half of the character the current zchar goes into. Once
|
||||||
// both halves are full, we use the ascii value in builtLetter.
|
// both halves are full, we use the ascii value in builtLetter.
|
||||||
if (buildingLevel > 0)
|
if (buildingLevel > 0)
|
||||||
{
|
{
|
||||||
builtLetter = (short) ((builtLetter << 5) | zchar);
|
builtLetter = (short) ((builtLetter << 5) | zchar);
|
||||||
if (++buildingLevel == 3)
|
if (++buildingLevel == 3)
|
||||||
{
|
{
|
||||||
text.append ((char) builtLetter);
|
text.append ((char) builtLetter);
|
||||||
buildingLevel = 0;
|
buildingLevel = 0;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A flag to indicate that we need to insert an abbreviation. The synonym value
|
// A flag to indicate that we need to insert an abbreviation. The synonym value
|
||||||
// (1-3) indicates which abbreviation block to use, and the current zchar is the offset
|
// (1-3) indicates which abbreviation block to use, and the current zchar is the
|
||||||
// within that block.
|
// offset within that block.
|
||||||
if (synonym > 0)
|
if (synonym > 0)
|
||||||
{
|
{
|
||||||
text.append (header.getAbbreviation ((synonym - 1) * 32 + zchar));
|
text.append (header.getAbbreviation ((synonym - 1) * 32 + zchar));
|
||||||
synonym = 0;
|
synonym = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this should be in the switch
|
if ((shift && shiftAlphabet == 2) || (!shift && alphabet == 2))
|
||||||
if ((shift && shiftAlphabet == 2) || (!shift && alphabet == 2))
|
{
|
||||||
{
|
if (zchar == 6)
|
||||||
if (zchar == 6)
|
{
|
||||||
{
|
buildingLevel = 1;
|
||||||
buildingLevel = 1;
|
builtLetter = 0;
|
||||||
builtLetter = 0;
|
shift = false;
|
||||||
shift = false;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (zchar == 7)
|
||||||
if (zchar == 7)
|
{
|
||||||
{
|
text.append ("\n");
|
||||||
text.append ("\n");
|
shift = false;
|
||||||
shift = false;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// zChar values 0-5 have special meanings, and 6-7 are special only in alphabet #2.
|
// zChar values 0-5 have special meanings, and 6-7 are special only in alphabet #2.
|
||||||
// Otherwise it's just a straight lookup into the current alphabet.
|
// Otherwise it's just a straight lookup into the current alphabet.
|
||||||
switch (zchar)
|
switch (zchar)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
text.append (" ");
|
text.append (" ");
|
||||||
shift = false;
|
shift = false;
|
||||||
return;
|
return;
|
||||||
case 1:
|
|
||||||
synonym = zchar;
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
if (header.version >= 3)
|
|
||||||
{
|
|
||||||
synonym = zchar;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// version 1 or 2
|
|
||||||
shiftAlphabet = (alphabet + zchar - 1) % 3;
|
|
||||||
shift = true;
|
|
||||||
return;
|
|
||||||
case 4:
|
|
||||||
case 5:
|
|
||||||
if (header.version >= 3) // shift key
|
|
||||||
{
|
|
||||||
shiftAlphabet = zchar - 3;
|
|
||||||
shift = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// shift lock key
|
|
||||||
alphabet = (alphabet + zchar - 3) % 3;
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
if (shift)
|
|
||||||
{
|
|
||||||
text.append (letters[shiftAlphabet].charAt (zchar));
|
|
||||||
shift = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
text.append (letters[alphabet].charAt (zchar));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
case 1:
|
||||||
public String toString ()
|
synonym = zchar;
|
||||||
{
|
return;
|
||||||
return text.toString ();
|
|
||||||
}
|
case 2:
|
||||||
}
|
case 3:
|
||||||
|
if (header.version >= 3)
|
||||||
|
{
|
||||||
|
synonym = zchar;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// version 1 or 2
|
||||||
|
shiftAlphabet = (alphabet + zchar - 1) % 3;
|
||||||
|
shift = true;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
if (header.version >= 3) // shift key
|
||||||
|
{
|
||||||
|
shiftAlphabet = zchar - 3;
|
||||||
|
shift = true;
|
||||||
|
}
|
||||||
|
else // shift lock key
|
||||||
|
alphabet = (alphabet + zchar - 3) % 3;
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (shift)
|
||||||
|
{
|
||||||
|
text.append (letters[shiftAlphabet].charAt (zchar));
|
||||||
|
shift = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
text.append (letters[alphabet].charAt (zchar));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return text.toString ();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user