method header lines

This commit is contained in:
Denis Molony 2020-02-09 23:02:48 +10:00
parent ed872ce87e
commit 5b640cbb1c
17 changed files with 2310 additions and 2040 deletions

View File

@ -1,68 +1,78 @@
package com.bytezone.diskbrowser.infocom; package com.bytezone.diskbrowser.infocom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
class Abbreviations extends InfocomAbstractFile // -----------------------------------------------------------------------------------//
{ class Abbreviations extends InfocomAbstractFile
List<ZString> list; // -----------------------------------------------------------------------------------//
Header header; {
int dataPtr; List<ZString> list;
int dataSize; Header header;
int tablePtr; int dataPtr;
int tableSize; int dataSize;
int tablePtr;
public Abbreviations (Header header) int tableSize;
{
super ("Abbreviations", header.buffer); // ---------------------------------------------------------------------------------//
this.header = header; Abbreviations (Header header)
// ---------------------------------------------------------------------------------//
dataPtr = header.getWord (header.abbreviationsTable) * 2; {
dataSize = header.abbreviationsTable - dataPtr; super ("Abbreviations", header.buffer);
tablePtr = header.abbreviationsTable; this.header = header;
tableSize = header.objectTableOffset - header.abbreviationsTable;
dataPtr = header.getWord (header.abbreviationsTable) * 2;
// prepare hex dump dataSize = header.abbreviationsTable - dataPtr;
hexBlocks.add (new HexBlock (dataPtr, dataSize, "Abbreviations data:")); tablePtr = header.abbreviationsTable;
hexBlocks.add (new HexBlock (tablePtr, tableSize, "Abbreviations table:")); tableSize = header.objectTableOffset - header.abbreviationsTable;
}
// prepare hex dump
private void populate () hexBlocks.add (new HexBlock (dataPtr, dataSize, "Abbreviations data:"));
{ hexBlocks.add (new HexBlock (tablePtr, tableSize, "Abbreviations table:"));
list = new ArrayList<> (); }
for (int i = header.abbreviationsTable; i < header.objectTableOffset; i += 2) // ---------------------------------------------------------------------------------//
list.add (new ZString (header, header.getWord (i) * 2)); private void populate ()
} // ---------------------------------------------------------------------------------//
{
public String getAbbreviation (int abbreviationNumber) list = new ArrayList<> ();
{
if (list == null) for (int i = header.abbreviationsTable; i < header.objectTableOffset; i += 2)
populate (); list.add (new ZString (header, header.getWord (i) * 2));
}
return list.get (abbreviationNumber).value;
} // ---------------------------------------------------------------------------------//
String getAbbreviation (int abbreviationNumber)
@Override // ---------------------------------------------------------------------------------//
public String getText () {
{ if (list == null)
if (list == null) populate ();
populate ();
return list.get (abbreviationNumber).value;
StringBuilder text = new StringBuilder (); }
// text.append (String.format ("Data address....%04X %d%n", dataPtr, dataPtr)); // ---------------------------------------------------------------------------------//
// text.append (String.format ("Data size.......%04X %d%n", dataSize, dataSize)); @Override
// text.append (String.format ("Table address...%04X %d%n", tablePtr, tablePtr)); public String getText ()
// text.append (String.format ("Table size......%04X %d (%d words)%n%n", tableSize, tableSize, // ---------------------------------------------------------------------------------//
// (tableSize / 2))); {
if (list == null)
int count = 0; populate ();
for (ZString word : list)
text.append (String.format ("%3d %s%n", count++, word.value)); StringBuilder text = new StringBuilder ();
if (list.size () > 0)
text.deleteCharAt (text.length () - 1); // text.append (String.format ("Data address....%04X %d%n", dataPtr, dataPtr));
// text.append (String.format ("Data size.......%04X %d%n", dataSize, dataSize));
return text.toString (); // text.append (String.format ("Table address...%04X %d%n", tablePtr, tablePtr));
} // text.append (String.format ("Table size......%04X %d (%d words)%n%n",
// tableSize, tableSize, (tableSize / 2)));
int count = 0;
for (ZString word : list)
text.append (String.format ("%3d %s%n", count++, word.value));
if (list.size () > 0)
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
} }

View File

@ -9,12 +9,16 @@ import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
import com.bytezone.diskbrowser.disk.FormattedDisk; import com.bytezone.diskbrowser.disk.FormattedDisk;
// -----------------------------------------------------------------------------------//
class AttributeManager extends AbstractFile class AttributeManager extends AbstractFile
// -----------------------------------------------------------------------------------//
{ {
List<Statistic> list = new ArrayList<> (); List<Statistic> list = new ArrayList<> ();
Header header; Header header;
// ---------------------------------------------------------------------------------//
public AttributeManager (String name, byte[] buffer, Header header) public AttributeManager (String name, byte[] buffer, Header header)
// ---------------------------------------------------------------------------------//
{ {
super (name, buffer); super (name, buffer);
this.header = header; this.header = header;
@ -23,7 +27,9 @@ class AttributeManager extends AbstractFile
list.add (new Statistic (attrNo)); list.add (new Statistic (attrNo));
} }
// ---------------------------------------------------------------------------------//
public void addNodes (DefaultMutableTreeNode node, FormattedDisk disk) public void addNodes (DefaultMutableTreeNode node, FormattedDisk disk)
// ---------------------------------------------------------------------------------//
{ {
node.setAllowsChildren (true); node.setAllowsChildren (true);
@ -37,8 +43,10 @@ class AttributeManager extends AbstractFile
} }
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String getText () public String getText ()
// ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder ("Attribute Frequency\n"); StringBuilder text = new StringBuilder ("Attribute Frequency\n");
text.append ("--------- ---------\n"); text.append ("--------- ---------\n");
@ -50,7 +58,9 @@ class AttributeManager extends AbstractFile
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------//
private class Statistic private class Statistic
// ---------------------------------------------------------------------------------//
{ {
int id; int id;
List<ZObject> list = new ArrayList<> (); List<ZObject> list = new ArrayList<> ();

View File

@ -15,19 +15,25 @@ import com.bytezone.diskbrowser.infocom.Grammar.Sentence;
import com.bytezone.diskbrowser.infocom.Grammar.SentenceGroup; import com.bytezone.diskbrowser.infocom.Grammar.SentenceGroup;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
// -----------------------------------------------------------------------------------//
class CodeManager extends AbstractFile class CodeManager extends AbstractFile
// -----------------------------------------------------------------------------------//
{ {
private final Header header; private final Header header;
private int codeSize; private int codeSize;
private final Map<Integer, Routine> routines = new TreeMap<> (); private final Map<Integer, Routine> routines = new TreeMap<> ();
public CodeManager (Header header) // ---------------------------------------------------------------------------------//
CodeManager (Header header)
// ---------------------------------------------------------------------------------//
{ {
super ("Code", header.buffer); super ("Code", header.buffer);
this.header = header; this.header = header;
} }
// ---------------------------------------------------------------------------------//
void addNodes (DefaultMutableTreeNode root, InfocomDisk disk) void addNodes (DefaultMutableTreeNode root, InfocomDisk disk)
// ---------------------------------------------------------------------------------//
{ {
root.setAllowsChildren (true); root.setAllowsChildren (true);
@ -48,7 +54,9 @@ class CodeManager extends AbstractFile
} }
} }
// ---------------------------------------------------------------------------------//
private List<DiskAddress> getSectors (Routine routine, Disk disk) private List<DiskAddress> getSectors (Routine routine, Disk disk)
// ---------------------------------------------------------------------------------//
{ {
int blockNo = routine.startPtr / 256 + 48; int blockNo = routine.startPtr / 256 + 48;
int size = routine.length; int size = routine.length;
@ -62,7 +70,9 @@ class CodeManager extends AbstractFile
return blocks; return blocks;
} }
// ---------------------------------------------------------------------------------//
void addRoutines (int programCounter) void addRoutines (int programCounter)
// ---------------------------------------------------------------------------------//
{ {
addRoutine (programCounter - 1, -1); addRoutine (programCounter - 1, -1);
addActionRoutines (); // obtained from Grammar addActionRoutines (); // obtained from Grammar
@ -111,19 +121,25 @@ class CodeManager extends AbstractFile
} }
} }
// ---------------------------------------------------------------------------------//
private int checkAlignment (int ptr) private int checkAlignment (int ptr)
// ---------------------------------------------------------------------------------//
{ {
if (ptr % 2 == 1) // routine must start on a word boundary if (ptr % 2 == 1) // routine must start on a word boundary
++ptr; ++ptr;
return ptr; return ptr;
} }
// ---------------------------------------------------------------------------------//
private void addGlobalRoutines () private void addGlobalRoutines ()
// ---------------------------------------------------------------------------------//
{ {
} }
// ---------------------------------------------------------------------------------//
private void addMissingRoutines () private void addMissingRoutines ()
// ---------------------------------------------------------------------------------//
{ {
System.out.printf ("%nWalking the code block%n%n"); System.out.printf ("%nWalking the code block%n%n");
int total = routines.size (); int total = routines.size ();
@ -158,7 +174,9 @@ class CodeManager extends AbstractFile
routines.size () - total); routines.size () - total);
} }
// ---------------------------------------------------------------------------------//
private int findNextRoutine (int address) private int findNextRoutine (int address)
// ---------------------------------------------------------------------------------//
{ {
for (Routine routine : routines.values ()) for (Routine routine : routines.values ())
if (routine.startPtr > address) if (routine.startPtr > address)
@ -166,8 +184,10 @@ class CodeManager extends AbstractFile
return 0; return 0;
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String getText () public String getText ()
// ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
int count = 0; int count = 0;
@ -188,7 +208,9 @@ class CodeManager extends AbstractFile
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------//
private void addCodeRoutines () private void addCodeRoutines ()
// ---------------------------------------------------------------------------------//
{ {
List<Integer> routines = header.objectManager.getCodeRoutines (); List<Integer> routines = header.objectManager.getCodeRoutines ();
System.out.println ("Adding " + routines.size () + " code routines"); System.out.println ("Adding " + routines.size () + " code routines");
@ -196,7 +218,9 @@ class CodeManager extends AbstractFile
addRoutine (address, 0); addRoutine (address, 0);
} }
// ---------------------------------------------------------------------------------//
private void addActionRoutines () private void addActionRoutines ()
// ---------------------------------------------------------------------------------//
{ {
int total = routines.size (); int total = routines.size ();
@ -211,7 +235,9 @@ class CodeManager extends AbstractFile
System.out.printf ("Added %d action routines%n", routines.size () - total); System.out.printf ("Added %d action routines%n", routines.size () - total);
} }
// ---------------------------------------------------------------------------------//
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;
@ -240,13 +266,17 @@ class CodeManager extends AbstractFile
return routine; return routine;
} }
// ---------------------------------------------------------------------------------//
Routine getRoutine (int address) Routine getRoutine (int address)
// ---------------------------------------------------------------------------------//
{ {
return routines.get (address); return routines.get (address);
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String getHexDump () public String getHexDump ()
// ---------------------------------------------------------------------------------//
{ {
// this depends on codeSize being set after the strings have been processed // this depends on codeSize being set after the strings have been processed
return HexFormatter.format (buffer, header.highMemory, codeSize); return HexFormatter.format (buffer, header.highMemory, codeSize);

View File

@ -1,344 +1,362 @@
package com.bytezone.diskbrowser.infocom; package com.bytezone.diskbrowser.infocom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
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 Dictionary extends AbstractFile // -----------------------------------------------------------------------------------//
{ class Dictionary extends AbstractFile
private final Map<Integer, ZString> dictionary; // -----------------------------------------------------------------------------------//
private final int totalEntries; {
private final int totalSeparators; private final Map<Integer, ZString> dictionary;
private final int dictionaryPtr, dictionarySize; private final int totalEntries;
private final int entryLength; private final int totalSeparators;
private final String separators; private final int dictionaryPtr, dictionarySize;
private final int entryLength;
Map<Integer, List<WordEntry>> synonymList = new TreeMap<> (); private final String separators;
public Dictionary (Header header) Map<Integer, List<WordEntry>> synonymList = new TreeMap<> ();
{
super ("Dictionary", header.buffer); // ---------------------------------------------------------------------------------//
Dictionary (Header header)
dictionaryPtr = header.dictionaryOffset; // ---------------------------------------------------------------------------------//
dictionary = new TreeMap<> (); {
super ("Dictionary", header.buffer);
totalSeparators = buffer[dictionaryPtr] & 0xFF;
dictionaryPtr = header.dictionaryOffset;
StringBuilder sep = new StringBuilder (); dictionary = new TreeMap<> ();
for (int i = 0; i < totalSeparators; i++)
sep.append ((char) (buffer[dictionaryPtr + i + 1] & 0xFF)); totalSeparators = buffer[dictionaryPtr] & 0xFF;
separators = sep.toString ();
StringBuilder sep = new StringBuilder ();
int ptr = dictionaryPtr + totalSeparators + 1; for (int i = 0; i < totalSeparators; i++)
entryLength = buffer[ptr++] & 0xFF; sep.append ((char) (buffer[dictionaryPtr + i + 1] & 0xFF));
separators = sep.toString ();
totalEntries = header.getWord (ptr);
int ptr = dictionaryPtr + totalSeparators + 1;
ptr += 2; entryLength = buffer[ptr++] & 0xFF;
int count = 0;
for (int i = 0; i < totalEntries; i++) totalEntries = header.getWord (ptr);
{
ZString string = new ZString (header, ptr); ptr += 2;
dictionary.put (ptr, string); int count = 0;
WordEntry wordEntry = new WordEntry (string, count++); for (int i = 0; i < totalEntries; i++)
{
// add the WordEntry to the appropriate list ZString string = new ZString (header, ptr);
List<WordEntry> wordEntryList = synonymList.get (wordEntry.key); dictionary.put (ptr, string);
if (wordEntryList == null) WordEntry wordEntry = new WordEntry (string, count++);
{
wordEntryList = new ArrayList<> (); // add the WordEntry to the appropriate list
synonymList.put (wordEntry.key, wordEntryList); List<WordEntry> wordEntryList = synonymList.get (wordEntry.key);
} if (wordEntryList == null)
wordEntryList.add (wordEntry); {
wordEntryList = new ArrayList<> ();
// check for words with the direction flag synonymList.put (wordEntry.key, wordEntryList);
if ((buffer[ptr + 4] & 0x10) != 0) }
{ wordEntryList.add (wordEntry);
int b1 = buffer[ptr + 5] & 0xFF;
int b2 = buffer[ptr + 6] & 0xFF; // check for words with the direction flag
int property = b2 == 0 ? b1 : b2; if ((buffer[ptr + 4] & 0x10) != 0)
String propertyName = header.getPropertyName (property); {
System.out.printf ("%02X %s%n", property, string.value); int b1 = buffer[ptr + 5] & 0xFF;
if (propertyName == null || propertyName.length () > string.value.length ()) int b2 = buffer[ptr + 6] & 0xFF;
header.propertyNames[property] = string.value; int property = b2 == 0 ? b1 : b2;
} String propertyName = header.getPropertyName (property);
ptr += entryLength; System.out.printf ("%02X %s%n", property, string.value);
} if (propertyName == null || propertyName.length () > string.value.length ())
header.propertyNames[property] = string.value;
dictionarySize = totalSeparators + 3 + entryLength * totalEntries; }
ptr += entryLength;
for (int i = 1; i < header.propertyNames.length; i++) }
if (header.propertyNames[i] == null)
header.propertyNames[i] = i + ""; dictionarySize = totalSeparators + 3 + entryLength * totalEntries;
// testing (only works in Zork 1) for (int i = 1; i < header.propertyNames.length; i++)
if (true) if (header.propertyNames[i] == null)
{ header.propertyNames[i] = i + "";
if (header.propertyNames[4].equals ("4"))
header.propertyNames[4] = "PSEUDO"; // testing (only works in Zork 1)
if (header.propertyNames[5].equals ("5")) if (true)
header.propertyNames[5] = "GLOBAL"; {
if (header.propertyNames[6].equals ("6")) if (header.propertyNames[4].equals ("4"))
header.propertyNames[6] = "VTYPE"; header.propertyNames[4] = "PSEUDO";
if (header.propertyNames[7].equals ("7")) if (header.propertyNames[5].equals ("5"))
header.propertyNames[7] = "STRENGTH"; header.propertyNames[5] = "GLOBAL";
if (header.propertyNames[10].equals ("10")) if (header.propertyNames[6].equals ("6"))
header.propertyNames[10] = "CAPACITY"; header.propertyNames[6] = "VTYPE";
if (header.propertyNames[12].equals ("12")) if (header.propertyNames[7].equals ("7"))
header.propertyNames[12] = "TVALU"; header.propertyNames[7] = "STRENGTH";
if (header.propertyNames[13].equals ("13")) if (header.propertyNames[10].equals ("10"))
header.propertyNames[13] = "VALUE"; header.propertyNames[10] = "CAPACITY";
if (header.propertyNames[15].equals ("15")) if (header.propertyNames[12].equals ("12"))
header.propertyNames[15] = "SIZE"; header.propertyNames[12] = "TVALU";
if (header.propertyNames[16].equals ("16")) if (header.propertyNames[13].equals ("13"))
header.propertyNames[16] = "ADJ"; header.propertyNames[13] = "VALUE";
} if (header.propertyNames[15].equals ("15"))
header.propertyNames[15] = "SIZE";
// 04 = PSEUDO (property 4) if (header.propertyNames[16].equals ("16"))
// 05 = GLOBAL (property 5) header.propertyNames[16] = "ADJ";
// 06 = VTYPE (property 6) }
// 07 = STRENGTH (property 7)
// STR3 = TEXT (property 8) // 04 = PSEUDO (property 4)
// CODE2 = DESCFCN (property 9) // 05 = GLOBAL (property 5)
// 0A = CAPACITY (property 10) // 06 = VTYPE (property 6)
// STR1 = LDESC (property 11) // 07 = STRENGTH (property 7)
// 0C = TVALUE (property 12) value in trophy case // STR3 = TEXT (property 8)
// 0D = VALUE (property 13) // CODE2 = DESCFCN (property 9)
// STR2 = FDESC (property 14) // 0A = CAPACITY (property 10)
// 0F = SIZE (property 15) // STR1 = LDESC (property 11)
// 10 = ADJ (property 16) // 0C = TVALUE (property 12) value in trophy case
// CODE1 = ACTION (property 17) // 0D = VALUE (property 13)
// 12 = DICT (property 18) // STR2 = FDESC (property 14)
// 0F = SIZE (property 15)
// 13 land // 10 = ADJ (property 16)
// 14 out // CODE1 = ACTION (property 17)
// 15 in, inside, into // 12 = DICT (property 18)
// 16 d, down
// 17 u, up // 13 land
// 18 sw, southw // 14 out
// 19 se, southe // 15 in, inside, into
// 1A nw, northw // 16 d, down
// 1B ne, northe // 17 u, up
// 1C s, south // 18 sw, southw
// 1D w, west // 19 se, southe
// 1E e, east // 1A nw, northw
// 1F n, north // 1B ne, northe
} // 1C s, south
// 1D w, west
public boolean containsWordAt (int address) // 1E e, east
{ // 1F n, north
return dictionary.containsKey (address); }
}
// ---------------------------------------------------------------------------------//
public String wordAt (int address) public boolean containsWordAt (int address)
{ // ---------------------------------------------------------------------------------//
if (dictionary.containsKey (address)) {
return dictionary.get (address).value; return dictionary.containsKey (address);
return "dictionary can't find word @ " + address; }
}
// ---------------------------------------------------------------------------------//
public List<String> getVerbs (int value) public String wordAt (int address)
{ // ---------------------------------------------------------------------------------//
List<String> words = new ArrayList<> (); {
int ptr = dictionaryPtr + totalSeparators + 4; if (dictionary.containsKey (address))
return dictionary.get (address).value;
for (ZString word : dictionary.values ()) return "dictionary can't find word @ " + address;
{ }
int b1 = buffer[ptr + 4] & 0xFF;
int b2 = buffer[ptr + 5] & 0xFF; // ---------------------------------------------------------------------------------//
int b3 = buffer[ptr + 6] & 0xFF; public List<String> getVerbs (int value)
// mask seems to be 0x40 // ---------------------------------------------------------------------------------//
if ((b1 == 0x41 && b2 == value) {
|| ((b1 == 0x62 || b1 == 0xC0 || b1 == 0x44) && b3 == value)) List<String> words = new ArrayList<> ();
words.add (word.value); int ptr = dictionaryPtr + totalSeparators + 4;
ptr += entryLength;
} for (ZString word : dictionary.values ())
return words; {
} int b1 = buffer[ptr + 4] & 0xFF;
int b2 = buffer[ptr + 5] & 0xFF;
public List<String> getPrepositions (int value) int b3 = buffer[ptr + 6] & 0xFF;
{ // mask seems to be 0x40
List<String> words = new ArrayList<> (); if ((b1 == 0x41 && b2 == value)
int ptr = dictionaryPtr + totalSeparators + 4; || ((b1 == 0x62 || b1 == 0xC0 || b1 == 0x44) && b3 == value))
words.add (word.value);
for (ZString word : dictionary.values ()) ptr += entryLength;
{ }
int b1 = buffer[ptr + 4] & 0xFF; return words;
int b2 = buffer[ptr + 5] & 0xFF; }
int b3 = buffer[ptr + 6] & 0xFF;
// mask seems to be 0x08 // ---------------------------------------------------------------------------------//
if (((b1 == 0x08 || b1 == 0x18 || b1 == 0x48) && b2 == value) public List<String> getPrepositions (int value)
|| ((b1 == 0x1B || b1 == 0x0C || b1 == 0x2A) && b3 == value)) // ---------------------------------------------------------------------------------//
words.add (word.value); {
ptr += entryLength; List<String> words = new ArrayList<> ();
} int ptr = dictionaryPtr + totalSeparators + 4;
return words;
} for (ZString word : dictionary.values ())
{
@Override int b1 = buffer[ptr + 4] & 0xFF;
public String getHexDump () int b2 = buffer[ptr + 5] & 0xFF;
{ int b3 = buffer[ptr + 6] & 0xFF;
StringBuilder text = new StringBuilder (); // mask seems to be 0x08
text.append (HexFormatter.format (buffer, dictionaryPtr, dictionarySize)); if (((b1 == 0x08 || b1 == 0x18 || b1 == 0x48) && b2 == value)
return text.toString (); || ((b1 == 0x1B || b1 == 0x0C || b1 == 0x2A) && b3 == value))
} words.add (word.value);
ptr += entryLength;
@Override }
public String getText () return words;
{ }
StringBuilder text = new StringBuilder ();
// ---------------------------------------------------------------------------------//
text.append (String.format ("Entries : %,6d%n", totalEntries)); @Override
text.append (String.format ("Separators : %s%n", separators)); public String getHexDump ()
text.append ( // ---------------------------------------------------------------------------------//
String.format ("Offset : %,6d %04X%n%n", dictionaryPtr, dictionaryPtr)); {
StringBuilder text = new StringBuilder ();
int count = 0; text.append (HexFormatter.format (buffer, dictionaryPtr, dictionarySize));
int ptr = dictionaryPtr + totalSeparators + 4; return text.toString ();
}
for (ZString word : dictionary.values ())
{ // ---------------------------------------------------------------------------------//
String bits = Integer.toBinaryString (buffer[ptr + 4] & 0xFF); @Override
if (bits.length () < 8) public String getText ()
bits = "00000000".substring (bits.length ()) + bits; // ---------------------------------------------------------------------------------//
{
text.append (String.format ("%04X %3d %-6s %s %s", ptr, count++, word.value, StringBuilder text = new StringBuilder ();
bits, HexFormatter.getHexString (buffer, ptr + 4, entryLength - 4)));
int b1 = buffer[ptr + 4] & 0xFF; text.append (String.format ("Entries : %,6d%n", totalEntries));
int b2 = buffer[ptr + 5] & 0xFF; text.append (String.format ("Separators : %s%n", separators));
int b3 = buffer[ptr + 6] & 0xFF; text.append (
if (b1 == 65) String.format ("Offset : %,6d %04X%n%n", dictionaryPtr, dictionaryPtr));
text.append (String.format (" %3d%n", b2));
else if (b1 == 98 || b1 == 0xC0 || b1 == 0x44) int count = 0;
text.append (String.format (" %3d%n", b3)); int ptr = dictionaryPtr + totalSeparators + 4;
else
text.append ("\n"); for (ZString word : dictionary.values ())
ptr += entryLength; {
} String bits = Integer.toBinaryString (buffer[ptr + 4] & 0xFF);
if (bits.length () < 8)
if (false) bits = "00000000".substring (bits.length ()) + bits;
{
int lastValue = 0; text.append (String.format ("%04X %3d %-6s %s %s", ptr, count++, word.value,
for (List<WordEntry> list : synonymList.values ()) bits, HexFormatter.getHexString (buffer, ptr + 4, entryLength - 4)));
{ int b1 = buffer[ptr + 4] & 0xFF;
WordEntry wordEntry = list.get (0); int b2 = buffer[ptr + 5] & 0xFF;
if (wordEntry.flags != lastValue) int b3 = buffer[ptr + 6] & 0xFF;
{ if (b1 == 65)
lastValue = wordEntry.flags; text.append (String.format (" %3d%n", b2));
text.append ("\n"); else if (b1 == 98 || b1 == 0xC0 || b1 == 0x44)
} text.append (String.format (" %3d%n", b3));
else
if (wordEntry.flags == 0x80) // nouns are all in one entry text.append ("\n");
{ ptr += entryLength;
for (WordEntry we : list) }
text.append (we + "\n");
text.deleteCharAt (text.length () - 1); if (false)
} {
else int lastValue = 0;
text.append (wordEntry); for (List<WordEntry> list : synonymList.values ())
{
if ((buffer[wordEntry.word.startPtr + 4] & 0x10) != 0) WordEntry wordEntry = list.get (0);
text.append (" direction"); if (wordEntry.flags != lastValue)
{
text.append ("\n"); lastValue = wordEntry.flags;
} text.append ("\n");
} }
if (true) if (wordEntry.flags == 0x80) // nouns are all in one entry
{ {
text.append ("\n"); for (WordEntry we : list)
int lastValue = 0; text.append (we + "\n");
text.deleteCharAt (text.length () - 1);
for (int bit = 1; bit < 256; bit *= 2) }
{ else
String bits = Integer.toBinaryString (bit & 0xFF); text.append (wordEntry);
if (bits.length () < 8)
bits = "00000000".substring (bits.length ()) + bits; if ((buffer[wordEntry.word.startPtr + 4] & 0x10) != 0)
text.append (" direction");
text.append (String.format ("Bits: %s%n", bits));
for (List<WordEntry> list : synonymList.values ()) text.append ("\n");
{ }
WordEntry wordEntry = list.get (0); }
if ((wordEntry.flags & bit) != 0)
{ if (true)
if (wordEntry.flags != lastValue) {
{ text.append ("\n");
lastValue = wordEntry.flags; int lastValue = 0;
text.append ("\n");
} for (int bit = 1; bit < 256; bit *= 2)
if (wordEntry.flags == 0x80) // nouns are all in one entry {
{ String bits = Integer.toBinaryString (bit & 0xFF);
for (WordEntry we : list) if (bits.length () < 8)
text.append (we + "\n"); bits = "00000000".substring (bits.length ()) + bits;
}
else text.append (String.format ("Bits: %s%n", bits));
text.append (wordEntry + "\n"); for (List<WordEntry> list : synonymList.values ())
} {
} WordEntry wordEntry = list.get (0);
text.append ("\n"); if ((wordEntry.flags & bit) != 0)
} {
} if (wordEntry.flags != lastValue)
{
text.deleteCharAt (text.length () - 1); lastValue = wordEntry.flags;
return text.toString (); text.append ("\n");
} }
if (wordEntry.flags == 0x80) // nouns are all in one entry
private class WordEntry implements Comparable<WordEntry> {
{ for (WordEntry we : list)
ZString word; text.append (we + "\n");
int seq; }
int flags; else
int key; text.append (wordEntry + "\n");
String bits; }
}
public WordEntry (ZString word, int seq) text.append ("\n");
{ }
this.word = word; }
this.seq = seq;
text.deleteCharAt (text.length () - 1);
// build key from 3 bytes following the word characters return text.toString ();
int b1 = buffer[word.startPtr + 4] & 0xFF; }
int b2 = buffer[word.startPtr + 5] & 0xFF;
int b3 = buffer[word.startPtr + 6] & 0xFF; // ---------------------------------------------------------------------------------//
private class WordEntry implements Comparable<WordEntry>
this.key = (b1 << 16) | (b2 << 8) | b3; // ---------------------------------------------------------------------------------//
this.flags = b1; {
this.bits = Integer.toBinaryString (b1); ZString word;
if (bits.length () < 8) int seq;
bits = "00000000".substring (bits.length ()) + bits; int flags;
} int key;
String bits;
@Override
public int compareTo (WordEntry o) public WordEntry (ZString word, int seq)
{ {
return this.flags - o.flags; this.word = word;
} this.seq = seq;
@Override // build key from 3 bytes following the word characters
public String toString () int b1 = buffer[word.startPtr + 4] & 0xFF;
{ int b2 = buffer[word.startPtr + 5] & 0xFF;
StringBuilder list = new StringBuilder ("["); int b3 = buffer[word.startPtr + 6] & 0xFF;
if ((key & 0x0800000) == 0)
{ this.key = (b1 << 16) | (b2 << 8) | b3;
for (WordEntry we : synonymList.get (key)) this.flags = b1;
list.append (we.word.value + ", "); this.bits = Integer.toBinaryString (b1);
list.deleteCharAt (list.length () - 1); if (bits.length () < 8)
list.deleteCharAt (list.length () - 1); bits = "00000000".substring (bits.length ()) + bits;
} }
else
list.append (word.value); @Override
list.append ("]"); public int compareTo (WordEntry o)
{
StringBuilder text = new StringBuilder (); return this.flags - o.flags;
text.append (String.format ("%04X %3d %-6s %s %s %s", word.startPtr, seq, }
word.value, bits,
HexFormatter.getHexString (buffer, word.startPtr + 4, entryLength - 4), @Override
list.toString ())); public String toString ()
return text.toString (); {
} StringBuilder list = new StringBuilder ("[");
} if ((key & 0x0800000) == 0)
{
for (WordEntry we : synonymList.get (key))
list.append (we.word.value + ", ");
list.deleteCharAt (list.length () - 1);
list.deleteCharAt (list.length () - 1);
}
else
list.append (word.value);
list.append ("]");
StringBuilder text = new StringBuilder ();
text.append (String.format ("%04X %3d %-6s %s %s %s", word.startPtr, seq,
word.value, bits,
HexFormatter.getHexString (buffer, word.startPtr + 4, entryLength - 4),
list.toString ()));
return text.toString ();
}
}
} }

View File

@ -5,7 +5,9 @@ import java.util.List;
import com.bytezone.diskbrowser.infocom.Instruction.Operand; import com.bytezone.diskbrowser.infocom.Instruction.Operand;
// -----------------------------------------------------------------------------------//
class Globals extends InfocomAbstractFile class Globals extends InfocomAbstractFile
// -----------------------------------------------------------------------------------//
{ {
private static final int TOTAL_GLOBALS = 240; private static final int TOTAL_GLOBALS = 240;
private final Header header; private final Header header;
@ -13,7 +15,9 @@ class Globals extends InfocomAbstractFile
private final int arrayPtr, arraySize; private final int arrayPtr, arraySize;
private final List<List<Routine>> globalRoutines; private final List<List<Routine>> globalRoutines;
// ---------------------------------------------------------------------------------//
Globals (Header header) Globals (Header header)
// ---------------------------------------------------------------------------------//
{ {
super ("Globals", header.buffer); super ("Globals", header.buffer);
this.header = header; this.header = header;
@ -32,15 +36,19 @@ class Globals extends InfocomAbstractFile
globalRoutines.add (new ArrayList<> ()); globalRoutines.add (new ArrayList<> ());
} }
// ---------------------------------------------------------------------------------//
void addRoutine (Routine routine, Operand operand) void addRoutine (Routine routine, Operand operand)
// ---------------------------------------------------------------------------------//
{ {
List<Routine> list = globalRoutines.get (operand.value - 16); List<Routine> list = globalRoutines.get (operand.value - 16);
if (!list.contains (routine)) if (!list.contains (routine))
list.add (routine); list.add (routine);
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String getText () public String getText ()
// ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder ("GLB Value Routines\n"); StringBuilder text = new StringBuilder ("GLB Value Routines\n");
for (int i = 0; i < TOTAL_GLOBALS; i++) for (int i = 0; i < TOTAL_GLOBALS; i++)

View File

@ -1,215 +1,215 @@
package com.bytezone.diskbrowser.infocom; package com.bytezone.diskbrowser.infocom;
import java.io.File; import java.io.File;
import com.bytezone.diskbrowser.disk.Disk; import com.bytezone.diskbrowser.disk.Disk;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class Header extends InfocomAbstractFile class Header extends InfocomAbstractFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
final String[] propertyNames = new String[32]; final String[] propertyNames = new String[32];
private final File file; private final File file;
int version; int version;
int highMemory; int highMemory;
int programCounter; int programCounter;
int dictionaryOffset; int dictionaryOffset;
int objectTableOffset; int objectTableOffset;
int globalsOffset; int globalsOffset;
int staticMemory; int staticMemory;
int abbreviationsTable; int abbreviationsTable;
int fileLength; int fileLength;
int checksum; int checksum;
int stringPointer; int stringPointer;
final Abbreviations abbreviations; final Abbreviations abbreviations;
final ObjectManager objectManager; final ObjectManager objectManager;
final Globals globals; final Globals globals;
final Grammar grammar; final Grammar grammar;
final Dictionary dictionary; final Dictionary dictionary;
final CodeManager codeManager; final CodeManager codeManager;
final StringManager stringManager; final StringManager stringManager;
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public Header (String name, byte[] buffer, Disk disk) Header (String name, byte[] buffer, Disk disk)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (name, buffer); super (name, buffer);
this.file = disk.getFile (); this.file = disk.getFile ();
version = getByte (00); version = getByte (00);
highMemory = getWord (0x04); highMemory = getWord (0x04);
programCounter = getWord (0x06); programCounter = getWord (0x06);
dictionaryOffset = getWord (0x08); dictionaryOffset = getWord (0x08);
objectTableOffset = getWord (0x0A); objectTableOffset = getWord (0x0A);
globalsOffset = getWord (0x0C); globalsOffset = getWord (0x0C);
staticMemory = getWord (0x0E); staticMemory = getWord (0x0E);
abbreviationsTable = getWord (0x18); abbreviationsTable = getWord (0x18);
fileLength = getWord (0x1A) * 2; // 2 for versions 1-3 fileLength = getWord (0x1A) * 2; // 2 for versions 1-3
checksum = getWord (0x1C); checksum = getWord (0x1C);
int interpreterNumber = getByte (0x1E); int interpreterNumber = getByte (0x1E);
int interpreterVersion = getByte (0x1F); int interpreterVersion = getByte (0x1F);
int revision = getWord (0x30); int revision = getWord (0x30);
System.out.printf ("Version : %d%n", version); System.out.printf ("Version : %d%n", version);
System.out.printf ("Interpreter: %d.%d%n", interpreterNumber, interpreterVersion); System.out.printf ("Interpreter: %d.%d%n", interpreterNumber, interpreterVersion);
System.out.printf ("Revision : %d%n", revision); System.out.printf ("Revision : %d%n", revision);
if (fileLength == 0) if (fileLength == 0)
fileLength = buffer.length; fileLength = buffer.length;
// do the basic managers // do the basic managers
abbreviations = new Abbreviations (this); abbreviations = new Abbreviations (this);
dictionary = new Dictionary (this); dictionary = new Dictionary (this);
globals = new Globals (this); // may display ZStrings globals = new Globals (this); // may display ZStrings
// set up an empty object to store Routines in // set up an empty object to store Routines in
codeManager = new CodeManager (this); codeManager = new CodeManager (this);
grammar = new Grammar ("Grammar", buffer, this); grammar = new Grammar ("Grammar", buffer, this);
// add all the ZObjects, and analyse them to find stringPtr, DICT etc. // add all the ZObjects, and analyse them to find stringPtr, DICT etc.
objectManager = new ObjectManager (this); objectManager = new ObjectManager (this);
// add all the ZStrings // add all the ZStrings
stringManager = new StringManager ("Strings", buffer, this); stringManager = new StringManager ("Strings", buffer, this);
codeManager.addRoutines (programCounter); codeManager.addRoutines (programCounter);
// add entries for AbstractFile.getHexDump () // add entries for AbstractFile.getHexDump ()
hexBlocks.add (new HexBlock (0, 64, "Header data:")); hexBlocks.add (new HexBlock (0, 64, "Header data:"));
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
String getPropertyName (int id) String getPropertyName (int id)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return propertyNames[id]; return propertyNames[id];
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public String getAbbreviation (int index) public String getAbbreviation (int index)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return abbreviations.getAbbreviation (index); return abbreviations.getAbbreviation (index);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public boolean containsWordAt (int address) public boolean containsWordAt (int address)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return dictionary.containsWordAt (address); return dictionary.containsWordAt (address);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public String wordAt (int address) public String wordAt (int address)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return dictionary.wordAt (address); return dictionary.wordAt (address);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@Override @Override
public String getText () public String getText ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append (String.format ("Disk name %s%n", file.getName ())); text.append (String.format ("Disk name %s%n", file.getName ()));
text.append (String.format ("Version %d%n", version)); text.append (String.format ("Version %d%n", version));
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", text.append (String.format (" Objects table %04X %,6d%n",
objectTableOffset, objectTableOffset)); objectTableOffset, objectTableOffset));
text.append (String.format (" Global variables %04X %,6d%n", globalsOffset, text.append (String.format (" Global variables %04X %,6d%n", globalsOffset,
globalsOffset)); globalsOffset));
text.append ("\nStatic memory:\n"); text.append ("\nStatic memory:\n");
text.append (String.format (" Grammar table etc %04X %,6d%n", staticMemory, text.append (String.format (" Grammar table etc %04X %,6d%n", staticMemory,
staticMemory)); staticMemory));
text.append (String.format (" Dictionary %04X %,6d%n", dictionaryOffset, text.append (String.format (" Dictionary %04X %,6d%n", dictionaryOffset,
dictionaryOffset)); dictionaryOffset));
text.append ("\nHigh memory:\n"); text.append ("\nHigh memory:\n");
text.append ( text.append (
String.format (" ZCode %04X %,6d%n", highMemory, highMemory)); String.format (" ZCode %04X %,6d%n", highMemory, highMemory));
text.append (String.format (" Program counter %04X %,6d%n", programCounter, text.append (String.format (" Program counter %04X %,6d%n", programCounter,
programCounter)); programCounter));
text.append ( text.append (
String.format ("\nFile length %05X %,7d%n", fileLength, fileLength)); String.format ("\nFile length %05X %,7d%n", fileLength, fileLength));
text.append ( text.append (
String.format ("Checksum %04X %,6d%n", checksum, checksum)); String.format ("Checksum %04X %,6d%n", checksum, checksum));
text.append (String.format ("%nZString offset %05X %,7d%n", stringPointer, text.append (String.format ("%nZString offset %05X %,7d%n", stringPointer,
stringPointer)); stringPointer));
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.getObjects ().size ())); objectManager.getObjects ().size ()));
text.append (getAlternate ()); text.append (getAlternate ());
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private String getAlternate () private String getAlternate ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder ("\n\n"); StringBuilder text = new StringBuilder ("\n\n");
text.append (getLine (0, 1, "version")); text.append (getLine (0, 1, "version"));
text.append (getLine (1, 3, "flags 1")); text.append (getLine (1, 3, "flags 1"));
text.append (getLine (4, 2, "high memory")); text.append (getLine (4, 2, "high memory"));
text.append (getLine (6, 2, "program counter")); text.append (getLine (6, 2, "program counter"));
text.append (getLine (8, 2, "dictionary")); text.append (getLine (8, 2, "dictionary"));
text.append (getLine (10, 2, "object table")); text.append (getLine (10, 2, "object table"));
text.append (getLine (12, 2, "global variables")); text.append (getLine (12, 2, "global variables"));
text.append (getLine (14, 2, "static memory")); text.append (getLine (14, 2, "static memory"));
text.append (getLine (16, 2, "flags 2")); text.append (getLine (16, 2, "flags 2"));
text.append (getLine (24, 2, "abbreviations table")); text.append (getLine (24, 2, "abbreviations table"));
text.append (getLine (26, 2, "length of file (x2 = " + fileLength + ")")); text.append (getLine (26, 2, "length of file (x2 = " + fileLength + ")"));
text.append (getLine (28, 2, "checksum")); text.append (getLine (28, 2, "checksum"));
text.append (getLine (50, 1, "revision number")); text.append (getLine (50, 1, "revision number"));
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private String getLine (int offset, int size, String description) private String getLine (int offset, int size, String description)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append (String.format ("%04X - %04X ", offset, offset + size - 1)); text.append (String.format ("%04X - %04X ", offset, offset + size - 1));
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
text.append (String.format ("%02X ", buffer[offset + i])); text.append (String.format ("%02X ", buffer[offset + i]));
while (text.length () < 24) while (text.length () < 24)
text.append (" "); text.append (" ");
text.append (description); text.append (description);
text.append ("\n"); text.append ("\n");
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
ZObject getObject (int index) ZObject getObject (int index)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return objectManager.getObject (index); return objectManager.getObject (index);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
int getByte (int offset) int getByte (int offset)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return buffer[offset] & 0xFF; return buffer[offset] & 0xFF;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
int getWord (int offset) int getWord (int offset)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return ((buffer[offset] << 8) & 0xFF00) | ((buffer[offset + 1]) & 0xFF); return ((buffer[offset] << 8) & 0xFF00) | ((buffer[offset + 1]) & 0xFF);
} }
} }

View File

@ -7,13 +7,13 @@ import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class InfocomAbstractFile extends AbstractFile class InfocomAbstractFile extends AbstractFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
protected List<HexBlock> hexBlocks = new ArrayList<> (); protected List<HexBlock> hexBlocks = new ArrayList<> ();
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public InfocomAbstractFile (String name, byte[] buffer) InfocomAbstractFile (String name, byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (name, buffer); super (name, buffer);

View File

@ -1,298 +1,324 @@
package com.bytezone.diskbrowser.infocom; package com.bytezone.diskbrowser.infocom;
import java.awt.Color; import java.awt.Color;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import com.bytezone.diskbrowser.applefile.AppleFileSource; import com.bytezone.diskbrowser.applefile.AppleFileSource;
import com.bytezone.diskbrowser.disk.AbstractFormattedDisk; import com.bytezone.diskbrowser.disk.AbstractFormattedDisk;
import com.bytezone.diskbrowser.disk.AppleDisk; import com.bytezone.diskbrowser.disk.AppleDisk;
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
import com.bytezone.diskbrowser.disk.Disk; import com.bytezone.diskbrowser.disk.Disk;
import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.disk.SectorType; import com.bytezone.diskbrowser.disk.SectorType;
import com.bytezone.diskbrowser.gui.DataSource; import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
// https://mud.co.uk/richard/htflpism.htm // https://mud.co.uk/richard/htflpism.htm
// https://inform-fiction.org/zmachine/standards/ // https://inform-fiction.org/zmachine/standards/
// https://github.com/historicalsource?tab=repositories // https://github.com/historicalsource?tab=repositories
public class InfocomDisk extends AbstractFormattedDisk // -----------------------------------------------------------------------------------//
{ public class InfocomDisk extends AbstractFormattedDisk
private static final int BLOCK_SIZE = 256; // -----------------------------------------------------------------------------------//
private static final boolean TYPE_NODE = true; {
private static final boolean TYPE_LEAF = false; private static final int BLOCK_SIZE = 256;
private byte[] data; private static final boolean TYPE_NODE = true;
private final Header header; private static final boolean TYPE_LEAF = false;
private byte[] data;
Color green = new Color (0, 200, 0); private final Header header;
SectorType bootSector = new SectorType ("ZIP code", Color.lightGray); Color green = new Color (0, 200, 0);
SectorType stringsSector = new SectorType ("Strings", Color.magenta);
SectorType objectsSector = new SectorType ("Objects", green); SectorType bootSector = new SectorType ("ZIP code", Color.lightGray);
SectorType dictionarySector = new SectorType ("Dictionary", Color.blue); SectorType stringsSector = new SectorType ("Strings", Color.magenta);
SectorType abbreviationsSector = new SectorType ("Abbreviations", Color.red); SectorType objectsSector = new SectorType ("Objects", green);
SectorType codeSector = new SectorType ("Code", Color.orange); SectorType dictionarySector = new SectorType ("Dictionary", Color.blue);
SectorType headerSector = new SectorType ("Header", Color.cyan); SectorType abbreviationsSector = new SectorType ("Abbreviations", Color.red);
SectorType globalsSector = new SectorType ("Globals", Color.darkGray); SectorType codeSector = new SectorType ("Code", Color.orange);
SectorType grammarSector = new SectorType ("Grammar", Color.gray); SectorType headerSector = new SectorType ("Header", Color.cyan);
SectorType globalsSector = new SectorType ("Globals", Color.darkGray);
public InfocomDisk (Disk disk) SectorType grammarSector = new SectorType ("Grammar", Color.gray);
{
super (disk); // ---------------------------------------------------------------------------------//
public InfocomDisk (Disk disk)
setInfocomSectorTypes (); // ---------------------------------------------------------------------------------//
{
data = disk.readSector (3, 0); // read first sector to get file size super (disk);
data = getBuffer (getWord (26) * 2); // read entire file into data buffer
setInfocomSectorTypes ();
if (false)
createStoryFile ("Zork1.sf"); data = disk.readSector (3, 0); // read first sector to get file size
data = getBuffer (getWord (26) * 2); // read entire file into data buffer
DefaultMutableTreeNode root = getCatalogTreeRoot ();
DefaultMutableTreeNode headerNode = null; if (false)
DefaultMutableTreeNode abbreviationsNode = null; createStoryFile ("Zork1.sf");
DefaultMutableTreeNode codeNode = null;
DefaultMutableTreeNode objectNode = null; DefaultMutableTreeNode root = getCatalogTreeRoot ();
DefaultMutableTreeNode globalsNode = null; DefaultMutableTreeNode headerNode = null;
DefaultMutableTreeNode grammarNode = null; DefaultMutableTreeNode abbreviationsNode = null;
DefaultMutableTreeNode dictionaryNode = null; DefaultMutableTreeNode codeNode = null;
DefaultMutableTreeNode stringsNode = null; DefaultMutableTreeNode objectNode = null;
DefaultMutableTreeNode globalsNode = null;
header = new Header ("Header", data, disk); DefaultMutableTreeNode grammarNode = null;
DefaultMutableTreeNode dictionaryNode = null;
headerNode = addToTree (root, "Header", header, TYPE_LEAF); DefaultMutableTreeNode stringsNode = null;
DefaultAppleFileSource dafs = (DefaultAppleFileSource) headerNode.getUserObject ();
List<DiskAddress> blocks = new ArrayList<> (); header = new Header ("Header", data, disk);
blocks.add (disk.getDiskAddress (3, 0));
dafs.setSectors (blocks); headerNode = addToTree (root, "Header", header, TYPE_LEAF);
DefaultAppleFileSource dafs = (DefaultAppleFileSource) headerNode.getUserObject ();
abbreviationsNode = List<DiskAddress> blocks = new ArrayList<> ();
addToTree (root, "Abbreviations", header.abbreviations, TYPE_LEAF); blocks.add (disk.getDiskAddress (3, 0));
dafs.setSectors (blocks);
objectNode = addToTree (root, "Objects", header.objectManager, TYPE_NODE);
header.objectManager.addNodes (objectNode, this); abbreviationsNode =
addToTree (root, "Abbreviations", header.abbreviations, TYPE_LEAF);
globalsNode = addToTree (root, "Globals", header.globals, TYPE_LEAF);
grammarNode = addToTree (root, "Grammar", header.grammar, TYPE_LEAF); objectNode = addToTree (root, "Objects", header.objectManager, TYPE_NODE);
dictionaryNode = addToTree (root, "Dictionary", header.dictionary, TYPE_LEAF); header.objectManager.addNodes (objectNode, this);
codeNode = addToTree (root, "Code", header.codeManager, TYPE_NODE); globalsNode = addToTree (root, "Globals", header.globals, TYPE_LEAF);
header.codeManager.addNodes (codeNode, this); grammarNode = addToTree (root, "Grammar", header.grammar, TYPE_LEAF);
dictionaryNode = addToTree (root, "Dictionary", header.dictionary, TYPE_LEAF);
stringsNode = addToTree (root, "Strings", header.stringManager, TYPE_LEAF);
codeNode = addToTree (root, "Code", header.codeManager, TYPE_NODE);
PropertyManager pm = new PropertyManager ("Properties", data, header); header.codeManager.addNodes (codeNode, this);
pm.addNodes (addToTree (root, "Properties", pm, TYPE_NODE), this);
stringsNode = addToTree (root, "Strings", header.stringManager, TYPE_LEAF);
AttributeManager am = new AttributeManager ("Attributes", data, header);
am.addNodes (addToTree (root, "Attributes", am, TYPE_NODE), this); PropertyManager pm = new PropertyManager ("Properties", data, header);
pm.addNodes (addToTree (root, "Properties", pm, TYPE_NODE), this);
sectorTypes[48] = headerSector;
AttributeManager am = new AttributeManager ("Attributes", data, header);
setSectorTypes (header.abbreviationsTable, header.objectTableOffset, am.addNodes (addToTree (root, "Attributes", am, TYPE_NODE), this);
abbreviationsSector, abbreviationsNode);
setSectorTypes (header.objectTableOffset, header.globalsOffset, objectsSector, sectorTypes[48] = headerSector;
objectNode);
setSectorTypes (header.globalsOffset, header.staticMemory, globalsSector, setSectorTypes (header.abbreviationsTable, header.objectTableOffset,
globalsNode); abbreviationsSector, abbreviationsNode);
setSectorTypes (header.staticMemory, header.dictionaryOffset, grammarSector, setSectorTypes (header.objectTableOffset, header.globalsOffset, objectsSector,
grammarNode); objectNode);
setSectorTypes (header.dictionaryOffset, header.highMemory, dictionarySector, setSectorTypes (header.globalsOffset, header.staticMemory, globalsSector,
dictionaryNode); globalsNode);
setSectorTypes (header.highMemory, header.stringPointer, codeSector, codeNode); setSectorTypes (header.staticMemory, header.dictionaryOffset, grammarSector,
setSectorTypes (header.stringPointer, header.fileLength, stringsSector, stringsNode); grammarNode);
} setSectorTypes (header.dictionaryOffset, header.highMemory, dictionarySector,
dictionaryNode);
protected void setInfocomSectorTypes () setSectorTypes (header.highMemory, header.stringPointer, codeSector, codeNode);
{ setSectorTypes (header.stringPointer, header.fileLength, stringsSector, stringsNode);
sectorTypesList.add (bootSector); }
sectorTypesList.add (headerSector);
sectorTypesList.add (abbreviationsSector); // ---------------------------------------------------------------------------------//
sectorTypesList.add (objectsSector); protected void setInfocomSectorTypes ()
sectorTypesList.add (globalsSector); // ---------------------------------------------------------------------------------//
sectorTypesList.add (grammarSector); {
sectorTypesList.add (dictionarySector); sectorTypesList.add (bootSector);
sectorTypesList.add (codeSector); sectorTypesList.add (headerSector);
sectorTypesList.add (stringsSector); sectorTypesList.add (abbreviationsSector);
sectorTypesList.add (objectsSector);
for (int track = 0; track < 3; track++) sectorTypesList.add (globalsSector);
for (int sector = 0; sector < 16; sector++) sectorTypesList.add (grammarSector);
if (!disk.isSectorEmpty (track, sector)) sectorTypesList.add (dictionarySector);
sectorTypes[track * 16 + sector] = bootSector; sectorTypesList.add (codeSector);
} sectorTypesList.add (stringsSector);
private void setSectorTypes (int sectorFrom, int sectorTo, SectorType type, for (int track = 0; track < 3; track++)
DefaultMutableTreeNode node) for (int sector = 0; sector < 16; sector++)
{ if (!disk.isSectorEmpty (track, sector))
DefaultAppleFileSource dafs = (DefaultAppleFileSource) node.getUserObject (); sectorTypes[track * 16 + sector] = bootSector;
List<DiskAddress> blocks = new ArrayList<> (); }
int blockNo = sectorFrom / disk.getBlockSize () + 48; // ---------------------------------------------------------------------------------//
int blockTo = sectorTo / disk.getBlockSize () + 48; private void setSectorTypes (int sectorFrom, int sectorTo, SectorType type,
while (blockNo <= blockTo) DefaultMutableTreeNode node)
{ // ---------------------------------------------------------------------------------//
blocks.add (disk.getDiskAddress (blockNo)); {
if (!disk.isSectorEmpty (blockNo)) DefaultAppleFileSource dafs = (DefaultAppleFileSource) node.getUserObject ();
sectorTypes[blockNo] = type; List<DiskAddress> blocks = new ArrayList<> ();
blockNo++;
} int blockNo = sectorFrom / disk.getBlockSize () + 48;
dafs.setSectors (blocks); int blockTo = sectorTo / disk.getBlockSize () + 48;
} while (blockNo <= blockTo)
{
private int getFileSize () blocks.add (disk.getDiskAddress (blockNo));
{ if (!disk.isSectorEmpty (blockNo))
byte[] buffer = null; sectorTypes[blockNo] = type;
int startBlock = getWord (4) / 256 + 48; blockNo++;
int fileSize = 0; }
for (DiskAddress da : disk) dafs.setSectors (blocks);
{ }
if (da.getBlock () > startBlock && disk.isSectorEmpty (da))
{ // ---------------------------------------------------------------------------------//
System.out.println ("Empty : " + da); private int getFileSize ()
buffer = disk.readSector (da.getBlock () - 1); // ---------------------------------------------------------------------------------//
fileSize = (da.getBlock () - 48) * disk.getBlockSize (); {
break; byte[] buffer = null;
} int startBlock = getWord (4) / 256 + 48;
} int fileSize = 0;
for (DiskAddress da : disk)
if (buffer != null) {
{ if (da.getBlock () > startBlock && disk.isSectorEmpty (da))
int ptr = 255; {
while (buffer[ptr--] == 0) System.out.println ("Empty : " + da);
fileSize--; buffer = disk.readSector (da.getBlock () - 1);
} fileSize = (da.getBlock () - 48) * disk.getBlockSize ();
return fileSize; break;
} }
}
private byte[] getBuffer (int fileSize)
{ if (buffer != null)
if (fileSize == 0) {
fileSize = getFileSize (); int ptr = 255;
data = new byte[fileSize]; while (buffer[ptr--] == 0)
fileSize--;
for (int track = 3, ptr = 0; track < 35; track++) }
for (int sector = 0; sector < 16; sector++, ptr += BLOCK_SIZE) return fileSize;
{ }
byte[] temp = disk.readSector (track, sector);
int spaceLeft = fileSize - ptr; // ---------------------------------------------------------------------------------//
if (spaceLeft <= BLOCK_SIZE) private byte[] getBuffer (int fileSize)
{ // ---------------------------------------------------------------------------------//
System.arraycopy (temp, 0, data, ptr, spaceLeft); {
return data; if (fileSize == 0)
} fileSize = getFileSize ();
System.arraycopy (temp, 0, data, ptr, BLOCK_SIZE); data = new byte[fileSize];
}
return data; for (int track = 3, ptr = 0; track < 35; track++)
} for (int sector = 0; sector < 16; sector++, ptr += BLOCK_SIZE)
{
private DefaultMutableTreeNode addToTree (DefaultMutableTreeNode root, String title, byte[] temp = disk.readSector (track, sector);
DataSource af, boolean allowsChildren) int spaceLeft = fileSize - ptr;
{ if (spaceLeft <= BLOCK_SIZE)
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, af, this); {
System.arraycopy (temp, 0, data, ptr, spaceLeft);
// dafs.setSectors (blocks); return data;
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs); }
node.setAllowsChildren (allowsChildren); System.arraycopy (temp, 0, data, ptr, BLOCK_SIZE);
root.add (node); }
return node; return data;
} }
@Override // ---------------------------------------------------------------------------------//
public List<DiskAddress> getFileSectors (int fileNo) private DefaultMutableTreeNode addToTree (DefaultMutableTreeNode root, String title,
{ DataSource af, boolean allowsChildren)
return null; // ---------------------------------------------------------------------------------//
} {
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, af, this);
@Override
public AppleFileSource getCatalog () // dafs.setSectors (blocks);
{ DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
return new DefaultAppleFileSource (header.getText (), this); node.setAllowsChildren (allowsChildren);
} root.add (node);
return node;
public static boolean isCorrectFormat (AppleDisk disk) }
{
disk.setInterleave (2); // ---------------------------------------------------------------------------------//
return checkFormat (disk); @Override
} public List<DiskAddress> getFileSectors (int fileNo)
// ---------------------------------------------------------------------------------//
public static boolean checkFormat (AppleDisk disk) {
{ return null;
byte[] buffer = disk.readSector (3, 0); }
int version = buffer[0] & 0xFF; // ---------------------------------------------------------------------------------//
int highMemory = HexFormatter.intValue (buffer[5], buffer[4]); @Override
int programCounter = HexFormatter.intValue (buffer[7], buffer[6]); public AppleFileSource getCatalog ()
int dictionary = HexFormatter.intValue (buffer[9], buffer[8]); // ---------------------------------------------------------------------------------//
int objectTable = HexFormatter.intValue (buffer[11], buffer[10]); {
int globals = HexFormatter.intValue (buffer[13], buffer[12]); return new DefaultAppleFileSource (header.getText (), this);
int staticMemory = HexFormatter.intValue (buffer[15], buffer[14]); }
int abbreviationsTable = HexFormatter.intValue (buffer[25], buffer[24]);
int fileLength = HexFormatter.intValue (buffer[27], buffer[26]); // ---------------------------------------------------------------------------------//
public static boolean isCorrectFormat (AppleDisk disk)
if (true) // ---------------------------------------------------------------------------------//
{ {
System.out.printf ("Version %,6d%n", version); disk.setInterleave (2);
System.out.printf ("Abbreviations %,6d%n", abbreviationsTable); return checkFormat (disk);
System.out.printf ("Objects %,6d%n", objectTable); }
System.out.printf ("Globals %,6d%n", globals);
System.out.printf ("Static memory %,6d%n", staticMemory); // ---------------------------------------------------------------------------------//
System.out.printf ("Dictionary %,6d%n", dictionary); public static boolean checkFormat (AppleDisk disk)
System.out.printf ("High memory %,6d%n", highMemory); // ---------------------------------------------------------------------------------//
System.out.printf ("Program counter %,6d%n", programCounter); {
System.out.printf ("File length %,6d%n", fileLength); byte[] buffer = disk.readSector (3, 0);
}
int version = buffer[0] & 0xFF;
if (abbreviationsTable >= objectTable) int highMemory = HexFormatter.intValue (buffer[5], buffer[4]);
return false; int programCounter = HexFormatter.intValue (buffer[7], buffer[6]);
// if (objectTable >= globals) int dictionary = HexFormatter.intValue (buffer[9], buffer[8]);
// return false; int objectTable = HexFormatter.intValue (buffer[11], buffer[10]);
if (globals >= staticMemory) int globals = HexFormatter.intValue (buffer[13], buffer[12]);
return false; int staticMemory = HexFormatter.intValue (buffer[15], buffer[14]);
if (staticMemory >= dictionary) int abbreviationsTable = HexFormatter.intValue (buffer[25], buffer[24]);
return false; int fileLength = HexFormatter.intValue (buffer[27], buffer[26]);
if (dictionary >= highMemory)
return false; if (true)
// if (highMemory > programCounter) {
// return false; System.out.printf ("Version %,6d%n", version);
System.out.printf ("Abbreviations %,6d%n", abbreviationsTable);
if (version < 2 || version > 3) System.out.printf ("Objects %,6d%n", objectTable);
{ System.out.printf ("Globals %,6d%n", globals);
System.out.println ("Incorrect format : " + version); System.out.printf ("Static memory %,6d%n", staticMemory);
JOptionPane.showMessageDialog (null, System.out.printf ("Dictionary %,6d%n", dictionary);
"This appears to be an Infocom disk," + " but version " + version System.out.printf ("High memory %,6d%n", highMemory);
+ " is not supported", System.out.printf ("Program counter %,6d%n", programCounter);
"Unknown disk format", JOptionPane.INFORMATION_MESSAGE); System.out.printf ("File length %,6d%n", fileLength);
return false; }
}
if (abbreviationsTable >= objectTable)
return true; return false;
} // if (objectTable >= globals)
// return false;
private int getWord (int offset) if (globals >= staticMemory)
{ return false;
return (((data[offset] << 8) & 0xFF00) | ((data[offset + 1]) & 0xFF)); if (staticMemory >= dictionary)
} return false;
if (dictionary >= highMemory)
private void createStoryFile (String fileName) return false;
{ // if (highMemory > programCounter)
File f = new File (fileName); // return false;
try
{ if (version < 2 || version > 3)
FileOutputStream fos = new FileOutputStream (f); {
fos.write (data); System.out.println ("Incorrect format : " + version);
fos.close (); JOptionPane.showMessageDialog (null,
} "This appears to be an Infocom disk," + " but version " + version
catch (IOException e) + " is not supported",
{ "Unknown disk format", JOptionPane.INFORMATION_MESSAGE);
e.printStackTrace (); return false;
} }
}
return true;
}
// ---------------------------------------------------------------------------------//
private int getWord (int offset)
// ---------------------------------------------------------------------------------//
{
return (((data[offset] << 8) & 0xFF00) | ((data[offset + 1]) & 0xFF));
}
// ---------------------------------------------------------------------------------//
private void createStoryFile (String fileName)
// ---------------------------------------------------------------------------------//
{
File f = new File (fileName);
try
{
FileOutputStream fos = new FileOutputStream (f);
fos.write (data);
fos.close ();
}
catch (IOException e)
{
e.printStackTrace ();
}
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -6,14 +6,18 @@ import java.util.List;
import com.bytezone.diskbrowser.infocom.ZObject.Property; 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;
@ -31,7 +35,9 @@ class ObjectAnalyser
checkThreeByteProperties (); checkThreeByteProperties ();
} }
// ---------------------------------------------------------------------------------//
public void setStringPointer () public void setStringPointer ()
// ---------------------------------------------------------------------------------//
{ {
PropertyTester pt = new PropertyTester (parent.getObjects ()); PropertyTester pt = new PropertyTester (parent.getObjects ());
pt.addTest (new LengthTwoCondition ()); pt.addTest (new LengthTwoCondition ());
@ -58,7 +64,9 @@ class ObjectAnalyser
} }
} }
// ---------------------------------------------------------------------------------//
public void createPropertyLinks () public void createPropertyLinks ()
// ---------------------------------------------------------------------------------//
{ {
int sCount = 0; int sCount = 0;
int rCount = 0; int rCount = 0;
@ -85,7 +93,9 @@ class ObjectAnalyser
System.out.println ("Routines found : " + totRoutines); System.out.println ("Routines found : " + totRoutines);
} }
// ---------------------------------------------------------------------------------//
private void checkThreeByteProperties () private void checkThreeByteProperties ()
// ---------------------------------------------------------------------------------//
{ {
System.out.printf ("Checking %d objects%n", parent.getObjects ().size ()); System.out.printf ("Checking %d objects%n", parent.getObjects ().size ());
for (ZObject object : parent.getObjects ()) for (ZObject object : parent.getObjects ())
@ -106,7 +116,9 @@ class ObjectAnalyser
} }
// 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.getObjects ()); PropertyTester pt = new PropertyTester (parent.getObjects ());
pt.addTest (new LengthEvenCondition ()); pt.addTest (new LengthEvenCondition ());
@ -118,7 +130,9 @@ class ObjectAnalyser
header.propertyNames[i] = "DICT"; // SYNONYM header.propertyNames[i] = "DICT"; // SYNONYM
} }
// ---------------------------------------------------------------------------------//
class Statistics implements Comparable<Statistics> class Statistics implements Comparable<Statistics>
// ---------------------------------------------------------------------------------//
{ {
int propertyNumber; int propertyNumber;
int lo; int lo;
@ -153,7 +167,9 @@ class ObjectAnalyser
} }
} }
// ---------------------------------------------------------------------------------//
class LengthTwoCondition extends Condition class LengthTwoCondition extends Condition
// ---------------------------------------------------------------------------------//
{ {
@Override @Override
boolean test (Property property) boolean test (Property property)
@ -162,7 +178,9 @@ class ObjectAnalyser
} }
} }
// ---------------------------------------------------------------------------------//
class LengthThreeCondition extends Condition class LengthThreeCondition extends Condition
// ---------------------------------------------------------------------------------//
{ {
@Override @Override
boolean test (Property property) boolean test (Property property)
@ -171,7 +189,9 @@ class ObjectAnalyser
} }
} }
// ---------------------------------------------------------------------------------//
class LengthEvenCondition extends Condition class LengthEvenCondition extends Condition
// ---------------------------------------------------------------------------------//
{ {
@Override @Override
boolean test (Property property) boolean test (Property property)
@ -180,7 +200,9 @@ class ObjectAnalyser
} }
} }
// ---------------------------------------------------------------------------------//
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
@ -202,7 +224,9 @@ class ObjectAnalyser
} }
} }
// ---------------------------------------------------------------------------------//
class ValidDictionaryCondition extends Condition class ValidDictionaryCondition extends Condition
// ---------------------------------------------------------------------------------//
{ {
@Override @Override
boolean test (Property property) boolean test (Property property)

View File

@ -1,133 +1,143 @@
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.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
import com.bytezone.diskbrowser.disk.FormattedDisk; import com.bytezone.diskbrowser.disk.FormattedDisk;
class ObjectManager extends InfocomAbstractFile implements Iterable<ZObject> // -----------------------------------------------------------------------------------//
{ class ObjectManager extends InfocomAbstractFile implements Iterable<ZObject>
// private final Header header; // -----------------------------------------------------------------------------------//
private final List<ZObject> list; {
private List<ZObject> sortedList; private final List<ZObject> list;
private final int defaultsPtr, defaultsSize; private List<ZObject> sortedList;
private final int tablePtr, tableSize; private final int defaultsPtr, defaultsSize;
private final int propertyPtr, propertySize; private final int tablePtr, tableSize;
private final ObjectAnalyser analyser; private final int propertyPtr, propertySize;
private final ObjectAnalyser analyser;
public ObjectManager (Header header)
{ // ---------------------------------------------------------------------------------//
super ("Objects", header.buffer); ObjectManager (Header header)
// this.header = header; // ---------------------------------------------------------------------------------//
{
defaultsPtr = header.objectTableOffset; super ("Objects", header.buffer);
defaultsSize = 62; // 31 words
tablePtr = header.objectTableOffset + 62; defaultsPtr = header.objectTableOffset;
propertyPtr = header.getWord (tablePtr + 7); defaultsSize = 62; // 31 words
propertySize = header.globalsOffset - propertyPtr; tablePtr = header.objectTableOffset + 62;
tableSize = (propertyPtr - tablePtr); propertyPtr = header.getWord (tablePtr + 7);
int totalObjects = tableSize / ZObject.HEADER_SIZE; propertySize = header.globalsOffset - propertyPtr;
list = new ArrayList<> (tableSize); tableSize = (propertyPtr - tablePtr);
int totalObjects = tableSize / ZObject.HEADER_SIZE;
for (int objectNo = 0; objectNo < totalObjects; objectNo++) list = new ArrayList<> (tableSize);
list.add (new ZObject (null, buffer, tablePtr + objectNo * ZObject.HEADER_SIZE,
objectNo + 1, header)); for (int objectNo = 0; objectNo < totalObjects; objectNo++)
list.add (new ZObject (null, buffer, tablePtr + objectNo * ZObject.HEADER_SIZE,
// analyse objects - set stringPtr etc. objectNo + 1, header));
analyser = new ObjectAnalyser (header, this);
// analyse objects - set stringPtr etc.
// add entries for AbstractFile.getHexDump () analyser = new ObjectAnalyser (header, this);
hexBlocks.add (new HexBlock (defaultsPtr, defaultsSize, "Property defaults:"));
hexBlocks.add (new HexBlock (tablePtr, tableSize, "Objects table:")); // add entries for AbstractFile.getHexDump ()
hexBlocks.add (new HexBlock (propertyPtr, propertySize, "Properties:")); hexBlocks.add (new HexBlock (defaultsPtr, defaultsSize, "Property defaults:"));
} hexBlocks.add (new HexBlock (tablePtr, tableSize, "Objects table:"));
hexBlocks.add (new HexBlock (propertyPtr, propertySize, "Properties:"));
List<ZObject> getObjects () }
{
return list; // ---------------------------------------------------------------------------------//
} List<ZObject> getObjects ()
// ---------------------------------------------------------------------------------//
ZObject getObject (int index) {
{ return list;
if (index < 0 || index >= list.size ()) }
{
System.out.printf ("Invalid index: %d / %d%n", index, list.size ()); // ---------------------------------------------------------------------------------//
return null; ZObject getObject (int index)
} // ---------------------------------------------------------------------------------//
return list.get (index); {
} if (index < 0 || index >= list.size ())
{
public void addNodes (DefaultMutableTreeNode root, FormattedDisk disk) System.out.printf ("Invalid index: %d / %d%n", index, list.size ());
{ return null;
root.setAllowsChildren (true); }
return list.get (index);
for (ZObject zo : list) }
if (zo.parent == 0)
buildObjectTree (zo, root, disk); // ---------------------------------------------------------------------------------//
} public void addNodes (DefaultMutableTreeNode root, FormattedDisk disk)
// ---------------------------------------------------------------------------------//
private void buildObjectTree (ZObject object, DefaultMutableTreeNode parentNode, {
FormattedDisk disk) root.setAllowsChildren (true);
{
DefaultMutableTreeNode child = new DefaultMutableTreeNode ( for (ZObject zo : list)
new DefaultAppleFileSource (object.getName (), object, disk)); if (zo.parent == 0)
parentNode.add (child); buildObjectTree (zo, root, disk);
if (object.sibling > 0) }
buildObjectTree (list.get (object.sibling - 1), parentNode, disk);
if (object.child > 0) // ---------------------------------------------------------------------------------//
buildObjectTree (list.get (object.child - 1), child, disk); private void buildObjectTree (ZObject object, DefaultMutableTreeNode parentNode,
else FormattedDisk disk)
child.setAllowsChildren (false); // ---------------------------------------------------------------------------------//
} {
DefaultMutableTreeNode child = new DefaultMutableTreeNode (
public List<Integer> getCodeRoutines () new DefaultAppleFileSource (object.getName (), object, disk));
{ parentNode.add (child);
return analyser.routines; if (object.sibling > 0)
} buildObjectTree (list.get (object.sibling - 1), parentNode, disk);
if (object.child > 0)
@Override buildObjectTree (list.get (object.child - 1), child, disk);
public String getText () else
{ child.setAllowsChildren (false);
// String header1 = "ID Attributes Pr Sb Ch Prop Title\n-- -----------" }
// + " -- -- -- ----- -----------------------------\n";
String underline = " ----------------------------------------"; // ---------------------------------------------------------------------------------//
String titles[] = public List<Integer> getCodeRoutines ()
{ "ID ", "Title ", // ---------------------------------------------------------------------------------//
"Parent ", {
"Sibling ", return analyser.routines;
"Child ", "Attributes Prop\n" }; }
String header2 = titles[0] + titles[1] + titles[2] + titles[3] + titles[4] + titles[5]
+ "-- " + underline + underline + underline + underline + " ----------- -----\n"; // ---------------------------------------------------------------------------------//
StringBuilder text = new StringBuilder (header2); @Override
public String getText ()
if (sortedList == null) // ---------------------------------------------------------------------------------//
sortedList = new ArrayList<> (list); {
Collections.sort (sortedList); String underline = " ----------------------------------------";
String titles[] =
// int objectNumber = 0; { "ID ", "Title ",
for (ZObject zo : list) "Parent ",
// if (false) "Sibling ",
// text.append (String.format ("%02X %s%n", ++objectNumber, zo)); "Child ", "Attributes Prop\n" };
// else String header2 = titles[0] + titles[1] + titles[2] + titles[3] + titles[4] + titles[5]
text.append (String.format ("%02X %s%n", zo.getId (), zo.getDescription (list))); + "-- " + underline + underline + underline + underline + " ----------- -----\n";
StringBuilder text = new StringBuilder (header2);
text.append ("\n\n");
text.append (header2); if (sortedList == null)
for (ZObject zo : sortedList) sortedList = new ArrayList<> (list);
text.append (String.format ("%02X %s%n", zo.getId (), zo.getDescription (list))); Collections.sort (sortedList);
text.deleteCharAt (text.length () - 1); for (ZObject zo : list)
return text.toString (); text.append (String.format ("%02X %s%n", zo.getId (), zo.getDescription (list)));
}
text.append ("\n\n");
@Override text.append (header2);
public Iterator<ZObject> iterator () for (ZObject zo : sortedList)
{ text.append (String.format ("%02X %s%n", zo.getId (), zo.getDescription (list)));
return list.iterator ();
} text.deleteCharAt (text.length () - 1);
return text.toString ();
}
// ---------------------------------------------------------------------------------//
@Override
public Iterator<ZObject> iterator ()
// ---------------------------------------------------------------------------------//
{
return list.iterator ();
}
} }

View File

@ -9,12 +9,16 @@ import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
import com.bytezone.diskbrowser.disk.FormattedDisk; import com.bytezone.diskbrowser.disk.FormattedDisk;
// -----------------------------------------------------------------------------------//
class PropertyManager extends AbstractFile class PropertyManager extends AbstractFile
// -----------------------------------------------------------------------------------//
{ {
List<Statistic> list = new ArrayList<> (); List<Statistic> list = new ArrayList<> ();
Header header; Header header;
public PropertyManager (String name, byte[] buffer, Header header) // ---------------------------------------------------------------------------------//
PropertyManager (String name, byte[] buffer, Header header)
// ---------------------------------------------------------------------------------//
{ {
super (name, buffer); super (name, buffer);
this.header = header; this.header = header;
@ -26,7 +30,9 @@ class PropertyManager extends AbstractFile
} }
} }
// ---------------------------------------------------------------------------------//
public void addNodes (DefaultMutableTreeNode node, FormattedDisk disk) public void addNodes (DefaultMutableTreeNode node, FormattedDisk disk)
// ---------------------------------------------------------------------------------//
{ {
node.setAllowsChildren (true); node.setAllowsChildren (true);
@ -41,8 +47,10 @@ class PropertyManager extends AbstractFile
} }
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String getText () public String getText ()
// ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder ("Property Type Frequency\n"); StringBuilder text = new StringBuilder ("Property Type Frequency\n");
text.append ("-------- ----- ---------\n"); text.append ("-------- ----- ---------\n");
@ -54,7 +62,9 @@ class PropertyManager extends AbstractFile
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------//
private class Statistic private class Statistic
// ---------------------------------------------------------------------------------//
{ {
int id; int id;
List<ZObject> list = new ArrayList<> (); List<ZObject> list = new ArrayList<> ();

View File

@ -6,23 +6,31 @@ import java.util.List;
import com.bytezone.diskbrowser.infocom.ZObject.Property; import com.bytezone.diskbrowser.infocom.ZObject.Property;
// -----------------------------------------------------------------------------------//
class PropertyTester implements Iterable<Integer> class PropertyTester implements Iterable<Integer>
// -----------------------------------------------------------------------------------//
{ {
List<ZObject> objects; List<ZObject> objects;
List<Condition> conditions = new ArrayList<> (); List<Condition> conditions = new ArrayList<> ();
List<Integer> matchedProperties; List<Integer> matchedProperties;
public PropertyTester (List<ZObject> objects) // ---------------------------------------------------------------------------------//
PropertyTester (List<ZObject> objects)
// ---------------------------------------------------------------------------------//
{ {
this.objects = objects; this.objects = objects;
} }
// ---------------------------------------------------------------------------------//
public void addTest (Condition test) public void addTest (Condition test)
// ---------------------------------------------------------------------------------//
{ {
conditions.add (test); conditions.add (test);
} }
// ---------------------------------------------------------------------------------//
public void doTests () public void doTests ()
// ---------------------------------------------------------------------------------//
{ {
boolean[] propFail = new boolean[32]; boolean[] propFail = new boolean[32];
int[] propTestCount = new int[32]; int[] propTestCount = new int[32];
@ -47,19 +55,25 @@ class PropertyTester implements Iterable<Integer>
matchedProperties.add (i); matchedProperties.add (i);
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public Iterator<Integer> iterator () public Iterator<Integer> iterator ()
// ---------------------------------------------------------------------------------//
{ {
return matchedProperties.iterator (); return matchedProperties.iterator ();
} }
// ---------------------------------------------------------------------------------//
public int totalSuccessfulProperties () public int totalSuccessfulProperties ()
// ---------------------------------------------------------------------------------//
{ {
return matchedProperties.size (); return matchedProperties.size ();
} }
} }
// ---------------------------------------------------------------------------------//
abstract class Condition abstract class Condition
// ---------------------------------------------------------------------------------//
{ {
abstract boolean test (Property property); abstract boolean test (Property property);
} }

View File

@ -8,8 +8,10 @@ import com.bytezone.diskbrowser.infocom.Instruction.Operand;
import com.bytezone.diskbrowser.infocom.Instruction.OperandType; import com.bytezone.diskbrowser.infocom.Instruction.OperandType;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
// -----------------------------------------------------------------------------------//
class Routine extends InfocomAbstractFile class Routine extends InfocomAbstractFile
implements Iterable<Instruction>, Comparable<Routine> implements Iterable<Instruction>, Comparable<Routine>
// -----------------------------------------------------------------------------------//
{ {
int startPtr, length, strings, locals; int startPtr, length, strings, locals;
@ -20,7 +22,9 @@ class Routine extends InfocomAbstractFile
List<Integer> actions = new ArrayList<> (); // not used yet List<Integer> actions = new ArrayList<> (); // not used yet
List<Integer> targets = new ArrayList<> (); List<Integer> targets = new ArrayList<> ();
public Routine (int ptr, Header header, int caller) // ---------------------------------------------------------------------------------//
Routine (int ptr, Header header, int caller)
// ---------------------------------------------------------------------------------//
{ {
super (String.format ("Routine %05X", ptr), header.buffer); super (String.format ("Routine %05X", ptr), header.buffer);
@ -104,7 +108,9 @@ class Routine extends InfocomAbstractFile
} }
} }
// ---------------------------------------------------------------------------------//
String dump () String dump ()
// ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append (String.format ("%05X : %s", startPtr, text.append (String.format ("%05X : %s", startPtr,
@ -118,13 +124,17 @@ class Routine extends InfocomAbstractFile
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------//
boolean isValid () boolean isValid ()
// ---------------------------------------------------------------------------------//
{ {
return startPtr > 0; return startPtr > 0;
} }
// test whether the routine contains any instructions pointing to this address // test whether the routine contains any instructions pointing to this address
// ---------------------------------------------------------------------------------//
private boolean isTarget (int ptr) private boolean isTarget (int ptr)
// ---------------------------------------------------------------------------------//
{ {
for (Instruction ins : instructions) for (Instruction ins : instructions)
{ {
@ -137,13 +147,17 @@ class Routine extends InfocomAbstractFile
return false; return false;
} }
// ---------------------------------------------------------------------------------//
public void addCaller (int caller) public void addCaller (int caller)
// ---------------------------------------------------------------------------------//
{ {
calledBy.add (caller); calledBy.add (caller);
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String getText () public String getText ()
// ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
@ -193,14 +207,18 @@ class Routine extends InfocomAbstractFile
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String toString () public String toString ()
// ---------------------------------------------------------------------------------//
{ {
return String.format ("[Start: %05X, Len: %4d, Strings: %2d, Locals: %2d]", startPtr, return String.format ("[Start: %05X, Len: %4d, Strings: %2d, Locals: %2d]", startPtr,
length, strings, locals); length, strings, locals);
} }
// ---------------------------------------------------------------------------------//
class Parameter class Parameter
// ---------------------------------------------------------------------------------//
{ {
int value; int value;
int sequence; int sequence;

View File

@ -6,12 +6,16 @@ import java.util.TreeMap;
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 StringManager extends AbstractFile class StringManager extends AbstractFile
// -----------------------------------------------------------------------------------//
{ {
Header header; Header header;
Map<Integer, ZString> strings = new TreeMap<Integer, ZString> (); Map<Integer, ZString> strings = new TreeMap<Integer, ZString> ();
public StringManager (String name, byte[] buffer, Header header) // ---------------------------------------------------------------------------------//
StringManager (String name, byte[] buffer, Header header)
// ---------------------------------------------------------------------------------//
{ {
super (name, buffer); super (name, buffer);
this.header = header; this.header = header;
@ -28,20 +32,26 @@ class StringManager extends AbstractFile
} }
} }
// ---------------------------------------------------------------------------------//
public boolean containsStringAt (int address) public boolean containsStringAt (int address)
// ---------------------------------------------------------------------------------//
{ {
return strings.containsKey (address); return strings.containsKey (address);
} }
// ---------------------------------------------------------------------------------//
public String stringAt (int address) public String stringAt (int address)
// ---------------------------------------------------------------------------------//
{ {
if (strings.containsKey (address)) if (strings.containsKey (address))
return strings.get (address).value; return strings.get (address).value;
return "String not found at : " + address; return "String not found at : " + address;
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String getText () public String getText ()
// ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
int count = 0; int count = 0;
@ -61,8 +71,10 @@ class StringManager extends AbstractFile
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String getHexDump () public String getHexDump ()
// ---------------------------------------------------------------------------------//
{ {
int size = header.fileLength - header.stringPointer; int size = header.fileLength - header.stringPointer;
return HexFormatter.format (buffer, header.stringPointer, size); return HexFormatter.format (buffer, header.stringPointer, size);

View File

@ -1,278 +1,298 @@
package com.bytezone.diskbrowser.infocom; package com.bytezone.diskbrowser.infocom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;
import java.util.List; 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 implements Comparable<ZObject> // -----------------------------------------------------------------------------------//
{ class ZObject extends AbstractFile implements Comparable<ZObject>
static final int HEADER_SIZE = 9; // -----------------------------------------------------------------------------------//
{
private final Header header; static final int HEADER_SIZE = 9;
private final int id;
private final int startPtr; private final Header header;
private final int id;
private final int propertyTablePtr; private final int startPtr;
private final int propertyTableLength;
private final int propertyTablePtr;
final int parent, sibling, child; private final int propertyTableLength;
final List<Property> properties = new ArrayList<> ();
final BitSet attributes = new BitSet (32); final int parent, sibling, child;
final List<Property> properties = new ArrayList<> ();
public ZObject (String name, byte[] buffer, int offset, int id, Header header) final BitSet attributes = new BitSet (32);
{
super (name, buffer); // ---------------------------------------------------------------------------------//
ZObject (String name, byte[] buffer, int offset, int id, Header header)
this.header = header; // ---------------------------------------------------------------------------------//
this.startPtr = offset; {
this.id = id; super (name, buffer);
// 32 attributes this.header = header;
int bitIndex = 0; this.startPtr = offset;
for (int i = 0; i < 4; i++) this.id = id;
{
byte b = buffer[offset + i]; // 32 attributes
for (int j = 0; j < 8; j++) int bitIndex = 0;
{ for (int i = 0; i < 4; i++)
if ((b & 0x80) != 0) {
attributes.set (bitIndex); byte b = buffer[offset + i];
b <<= 1; for (int j = 0; j < 8; j++)
++bitIndex; {
} if ((b & 0x80) != 0)
} attributes.set (bitIndex);
b <<= 1;
// object's relatives ++bitIndex;
parent = header.getByte (offset + 4); }
sibling = header.getByte (offset + 5); }
child = header.getByte (offset + 6);
// object's relatives
// the property header contains the object's short name parent = header.getByte (offset + 4);
propertyTablePtr = header.getWord (offset + 7); sibling = header.getByte (offset + 5);
int ptr = propertyTablePtr; child = header.getByte (offset + 6);
int nameLength = header.getByte (ptr) * 2;
this.name = nameLength == 0 ? "<<" + id + ">>" : new ZString (header, ++ptr).value; // the property header contains the object's short name
ptr += nameLength; propertyTablePtr = header.getWord (offset + 7);
int ptr = propertyTablePtr;
// read each property int nameLength = header.getByte (ptr) * 2;
while (buffer[ptr] != 0) this.name = nameLength == 0 ? "<<" + id + ">>" : new ZString (header, ++ptr).value;
{ ptr += nameLength;
Property p = new Property (ptr);
properties.add (p); // read each property
ptr += p.length + 1; while (buffer[ptr] != 0)
} {
propertyTableLength = ptr - propertyTablePtr; Property p = new Property (ptr);
} properties.add (p);
ptr += p.length + 1;
int getId () }
{ propertyTableLength = ptr - propertyTablePtr;
return id; }
}
// ---------------------------------------------------------------------------------//
@Override int getId ()
public String getText () // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); return id;
}
text.append (String.format ("ID : %02X (%<3d) %s%n%n", id, name));
// ---------------------------------------------------------------------------------//
String obj1 = parent == 0 ? "" : header.getObject (parent - 1).name; @Override
String obj2 = sibling == 0 ? "" : header.getObject (sibling - 1).name; public String getText ()
String obj3 = child == 0 ? "" : header.getObject (child - 1).name; // ---------------------------------------------------------------------------------//
{
text.append (String.format ("Parent : %02X (%<3d) %s%n", parent, obj1)); StringBuilder text = new StringBuilder ();
text.append (String.format ("Sibling : %02X (%<3d) %s%n", sibling, obj2));
text.append (String.format ("Child : %02X (%<3d) %s%n%n", child, obj3)); text.append (String.format ("ID : %02X (%<3d) %s%n%n", id, name));
text.append ("Attributes : "); String obj1 = parent == 0 ? "" : header.getObject (parent - 1).name;
text.append (HexFormatter.getHexString (buffer, startPtr, 4)); String obj2 = sibling == 0 ? "" : header.getObject (sibling - 1).name;
text.append (" " + attributes.toString () + "\n\n"); String obj3 = child == 0 ? "" : header.getObject (child - 1).name;
for (Property prop : properties) text.append (String.format ("Parent : %02X (%<3d) %s%n", parent, obj1));
text.append (prop + "\n"); text.append (String.format ("Sibling : %02X (%<3d) %s%n", sibling, obj2));
text.append (String.format ("Child : %02X (%<3d) %s%n%n", child, obj3));
return text.toString ();
} text.append ("Attributes : ");
text.append (HexFormatter.getHexString (buffer, startPtr, 4));
@Override text.append (" " + attributes.toString () + "\n\n");
public String getHexDump ()
{ for (Property prop : properties)
StringBuilder text = new StringBuilder ("Header :\n\n"); text.append (prop + "\n");
text.append (HexFormatter.formatNoHeader (buffer, startPtr, HEADER_SIZE));
text.append ("\n\nProperty table:\n\n"); return text.toString ();
text.append ( }
HexFormatter.formatNoHeader (buffer, propertyTablePtr, propertyTableLength));
return text.toString (); // ---------------------------------------------------------------------------------//
} @Override
public String getHexDump ()
Property getProperty (int id) // ---------------------------------------------------------------------------------//
{ {
for (Property p : properties) StringBuilder text = new StringBuilder ("Header :\n\n");
if (p.propertyNumber == id) text.append (HexFormatter.formatNoHeader (buffer, startPtr, HEADER_SIZE));
return p; text.append ("\n\nProperty table:\n\n");
return null; text.append (
} HexFormatter.formatNoHeader (buffer, propertyTablePtr, propertyTableLength));
return text.toString ();
@Override }
public String toString ()
{ // ---------------------------------------------------------------------------------//
return HexFormatter.getHexString (buffer, startPtr, HEADER_SIZE) + " " + name; Property getProperty (int id)
} // ---------------------------------------------------------------------------------//
{
public String getDescription (List<ZObject> list) for (Property p : properties)
{ if (p.propertyNumber == id)
StringBuilder text = new StringBuilder (String.format (" %-40s", getName ())); return p;
return null;
for (int i = 4; i < 7; i++) }
{
int index = buffer[startPtr + i] & 0xFF; // ---------------------------------------------------------------------------------//
String name = index > 0 ? list.get (index - 1).getName () : ""; @Override
text.append (String.format (" %-40s", name)); public String toString ()
} // ---------------------------------------------------------------------------------//
{
text.append (" "); return HexFormatter.getHexString (buffer, startPtr, HEADER_SIZE) + " " + name;
text.append (HexFormatter.getHexString (buffer, startPtr, 4)); }
text.append (" ");
text.append (HexFormatter.getHexString (buffer, startPtr + 7, 2)); // ---------------------------------------------------------------------------------//
public String getDescription (List<ZObject> list)
return text.toString (); // ---------------------------------------------------------------------------------//
} {
StringBuilder text = new StringBuilder (String.format (" %-40s", getName ()));
class Property
{ for (int i = 4; i < 7; i++)
int propertyNumber; {
int ptr; int index = buffer[startPtr + i] & 0xFF;
int length; String name = index > 0 ? list.get (index - 1).getName () : "";
int offset; // only used if length == 2 text.append (String.format (" %-40s", name));
}
public Property (int ptr)
{ text.append (" ");
this.ptr = ptr; text.append (HexFormatter.getHexString (buffer, startPtr, 4));
length = header.getByte (ptr) / 32 + 1; text.append (" ");
propertyNumber = header.getByte (ptr) % 32; text.append (HexFormatter.getHexString (buffer, startPtr + 7, 2));
if (length == 2) return text.toString ();
offset = header.getWord (ptr + 1) * 2; }
}
// ---------------------------------------------------------------------------------//
private ZObject getObject () class Property
{ // ---------------------------------------------------------------------------------//
return header.getObject ((buffer[ptr + 1] & 0xFF) - 1); {
} int propertyNumber;
int ptr;
private ZObject getObject (int id) int length;
{ int offset; // only used if length == 2
return header.getObject (id - 1);
} public Property (int ptr)
{
@Override this.ptr = ptr;
public String toString () length = header.getByte (ptr) / 32 + 1;
{ propertyNumber = header.getByte (ptr) % 32;
StringBuilder text = new StringBuilder (
String.format ("%8s : ", header.getPropertyName (propertyNumber))); if (length == 2)
offset = header.getWord (ptr + 1) * 2;
String propertyType = header.getPropertyName (propertyNumber); }
if (!(propertyType.equals ("DICT") || propertyType.startsWith ("STR"))) private ZObject getObject ()
text.append ( {
String.format ("%-20s", HexFormatter.getHexString (buffer, ptr + 1, length))); return header.getObject ((buffer[ptr + 1] & 0xFF) - 1);
}
if (propertyNumber >= 19) // directions
{ private ZObject getObject (int id)
switch (length) {
{ return header.getObject (id - 1);
case 1: // UEXIT - unconditional exit }
text.append (getObject ().name);
break; @Override
case 2: public String toString ()
text.append ("\"" + header.stringManager.stringAt (offset) + "\""); {
break; StringBuilder text = new StringBuilder (
case 3: // FEXIT - function exit String.format ("%8s : ", header.getPropertyName (propertyNumber)));
int address = header.getWord (ptr + 1) * 2;
text.append (String.format ("R:%05X", address)); String propertyType = header.getPropertyName (propertyNumber);
appendRoutine (text, address);
break; if (!(propertyType.equals ("DICT") || propertyType.startsWith ("STR")))
case 4: text.append (
text.append (String.format ("%s : IF G%02X ELSE ", getObject ().name, String.format ("%-20s", HexFormatter.getHexString (buffer, ptr + 1, length)));
header.getByte (ptr + 2)));
address = header.getWord (ptr + 3) * 2; if (propertyNumber >= 19) // directions
if (address > 0) {
text.append ("\"" + header.stringManager.stringAt (address) + "\""); switch (length)
break; {
case 5: case 1: // UEXIT - unconditional exit
text.append (String.format ("%s : IF G%02X ", getObject ().name, text.append (getObject ().name);
header.getByte (ptr + 2))); break;
break; case 2:
default: text.append ("\"" + header.stringManager.stringAt (offset) + "\"");
break; break;
} case 3: // FEXIT - function exit
} int address = header.getWord (ptr + 1) * 2;
else if (propertyType.equals ("DICT")) text.append (String.format ("R:%05X", address));
{ appendRoutine (text, address);
for (int i = 1; i <= length; i += 2) break;
{ case 4:
int address = header.getWord (ptr + i); text.append (String.format ("%s : IF G%02X ELSE ", getObject ().name,
text.append (String.format ("%02X: %s, ", address, header.wordAt (address))); header.getByte (ptr + 2)));
} address = header.getWord (ptr + 3) * 2;
text.deleteCharAt (text.length () - 1); if (address > 0)
text.deleteCharAt (text.length () - 1); text.append ("\"" + header.stringManager.stringAt (address) + "\"");
} break;
else if (propertyType.startsWith ("CODE")) case 5:
{ text.append (String.format ("%s : IF G%02X ", getObject ().name,
if (offset > 0) // cretin contains 00 00 header.getByte (ptr + 2)));
appendRoutine (text, offset); break;
} default:
else if (propertyType.startsWith ("STR")) break;
{ }
text.append (String.format ("(%4X) \"%s\"", offset, }
header.stringManager.stringAt (offset))); else if (propertyType.equals ("DICT"))
} {
else if (propertyType.equals ("ADJ")) for (int i = 1; i <= length; i += 2)
{ {
int address = header.getWord (ptr + i);
} text.append (String.format ("%02X: %s, ", address, header.wordAt (address)));
else if (propertyType.equals ("SIZE")) }
{ text.deleteCharAt (text.length () - 1);
text.deleteCharAt (text.length () - 1);
} }
else if (propertyType.equals ("VALUE")) else if (propertyType.startsWith ("CODE"))
{ {
if (offset > 0) // cretin contains 00 00
} appendRoutine (text, offset);
else if (propertyType.equals ("TVALU")) }
{ else if (propertyType.startsWith ("STR"))
{
} text.append (String.format ("(%4X) \"%s\"", offset,
else if (propertyType.equals ("GLBL")) header.stringManager.stringAt (offset)));
{ }
for (int i = 0; i < length; i++) else if (propertyType.equals ("ADJ"))
{ {
int objectId = header.getByte (ptr + i + 1);
text.append ( }
String.format ("%s%s", (i == 0 ? "" : ", "), getObject (objectId).name)); else if (propertyType.equals ("SIZE"))
} {
}
// else }
// text.append ("Unknown property type: " + propertyType); else if (propertyType.equals ("VALUE"))
{
return text.toString ();
} }
else if (propertyType.equals ("TVALU"))
private void appendRoutine (StringBuilder text, int offset) {
{
Routine r = header.codeManager.getRoutine (offset); }
if (r != null) else if (propertyType.equals ("GLBL"))
text.append ("\n\n" + r.getText ()); {
else // this can happen if the property is mislabelled as code for (int i = 0; i < length; i++)
text.append ("\n\n****** null routine\n"); {
} int objectId = header.getByte (ptr + i + 1);
} text.append (
String.format ("%s%s", (i == 0 ? "" : ", "), getObject (objectId).name));
@Override }
public int compareTo (ZObject o) }
{ // else
return this.name.compareTo (o.name); // text.append ("Unknown property type: " + propertyType);
}
return text.toString ();
}
private void appendRoutine (StringBuilder text, int offset)
{
Routine r = header.codeManager.getRoutine (offset);
if (r != null)
text.append ("\n\n" + r.getText ());
else // this can happen if the property is mislabelled as code
text.append ("\n\n****** null routine\n");
}
}
// ---------------------------------------------------------------------------------//
@Override
public int compareTo (ZObject o)
// ---------------------------------------------------------------------------------//
{
return this.name.compareTo (o.name);
}
} }

View File

@ -1,158 +1,166 @@
package com.bytezone.diskbrowser.infocom; package com.bytezone.diskbrowser.infocom;
class ZString // -----------------------------------------------------------------------------------//
{ class ZString
private static String[] letters = // -----------------------------------------------------------------------------------//
{ " abcdefghijklmnopqrstuvwxyz", " ABCDEFGHIJKLMNOPQRSTUVWXYZ", {
" 0123456789.,!?_#\'\"/\\-:()" }; private static String[] letters =
String value; { " abcdefghijklmnopqrstuvwxyz", " ABCDEFGHIJKLMNOPQRSTUVWXYZ",
Header header; " 0123456789.,!?_#\'\"/\\-:()" };
int startPtr; String value;
int length; Header header;
int startPtr;
public ZString (Header header, int offset) int length;
{
ZStringBuilder text = new ZStringBuilder (); // ---------------------------------------------------------------------------------//
this.header = header; ZString (Header header, int offset)
this.startPtr = offset; // ---------------------------------------------------------------------------------//
{
while (true) ZStringBuilder text = new ZStringBuilder ();
{ this.header = header;
if (offset >= header.buffer.length - 1) this.startPtr = offset;
{
System.out.println ("********" + text.toString ()); while (true)
break; {
} if (offset >= header.buffer.length - 1)
{
// get the next two bytes System.out.println ("********" + text.toString ());
int val = header.getWord (offset); break;
}
// process each zChar as a 5-bit value
text.processZChar ((byte) ((val >>> 10) & 0x1F)); // get the next two bytes
text.processZChar ((byte) ((val >>> 5) & 0x1F)); int val = header.getWord (offset);
text.processZChar ((byte) (val & 0x1F));
// process each zChar as a 5-bit value
if ((val & 0x8000) != 0) // bit 15 = finished flag text.processZChar ((byte) ((val >>> 10) & 0x1F));
{ text.processZChar ((byte) ((val >>> 5) & 0x1F));
length = offset - startPtr + 2; text.processZChar ((byte) (val & 0x1F));
value = text.toString ();
break; if ((val & 0x8000) != 0) // bit 15 = finished flag
} {
offset += 2; length = offset - startPtr + 2;
} value = text.toString ();
} break;
}
@Override offset += 2;
public String toString () }
{ }
return value;
} // ---------------------------------------------------------------------------------//
@Override
private class ZStringBuilder public String toString ()
{ // ---------------------------------------------------------------------------------//
int alphabet; {
boolean shift; return value;
int shiftAlphabet; }
int synonym;
int buildingLevel; // ---------------------------------------------------------------------------------//
int builtLetter; private class ZStringBuilder
StringBuilder text = new StringBuilder (); // ---------------------------------------------------------------------------------//
{
private void processZChar (byte zchar) int alphabet;
{ boolean shift;
// A flag to indicate that we are building a character not in the alphabet. The int shiftAlphabet;
// value indicates which half of the character the current zchar goes into. Once int synonym;
// both halves are full, we use the ascii value in builtLetter. int buildingLevel;
if (buildingLevel > 0) int builtLetter;
{ StringBuilder text = new StringBuilder ();
builtLetter = (short) ((builtLetter << 5) | zchar);
if (++buildingLevel == 3) private void processZChar (byte zchar)
{ {
text.append ((char) builtLetter); // A flag to indicate that we are building a character not in the alphabet. The
buildingLevel = 0; // value indicates which half of the character the current zchar goes into. Once
} // both halves are full, we use the ascii value in builtLetter.
return; if (buildingLevel > 0)
} {
builtLetter = (short) ((builtLetter << 5) | zchar);
// A flag to indicate that we need to insert an abbreviation. The synonym value if (++buildingLevel == 3)
// (1-3) indicates which abbreviation block to use, and the current zchar is the {
// offset within that block. text.append ((char) builtLetter);
if (synonym > 0) buildingLevel = 0;
{ }
text.append (header.getAbbreviation ((synonym - 1) * 32 + zchar)); return;
synonym = 0; }
return;
} // 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
if ((shift && shiftAlphabet == 2) || (!shift && alphabet == 2)) // offset within that block.
{ if (synonym > 0)
if (zchar == 6) {
{ text.append (header.getAbbreviation ((synonym - 1) * 32 + zchar));
buildingLevel = 1; synonym = 0;
builtLetter = 0; return;
shift = false; }
return;
} if ((shift && shiftAlphabet == 2) || (!shift && alphabet == 2))
if (zchar == 7) {
{ if (zchar == 6)
text.append ("\n"); {
shift = false; buildingLevel = 1;
return; builtLetter = 0;
} shift = false;
} return;
}
// zChar values 0-5 have special meanings, and 6-7 are special only in alphabet #2. if (zchar == 7)
// Otherwise it's just a straight lookup into the current alphabet. {
switch (zchar) text.append ("\n");
{ shift = false;
case 0: return;
text.append (" "); }
shift = false; }
return;
// zChar values 0-5 have special meanings, and 6-7 are special only in alphabet #2.
case 1: // Otherwise it's just a straight lookup into the current alphabet.
synonym = zchar; switch (zchar)
return; {
case 0:
case 2: text.append (" ");
case 3: shift = false;
if (header.version >= 3) return;
{
synonym = zchar; case 1:
return; synonym = zchar;
} return;
// version 1 or 2
shiftAlphabet = (alphabet + zchar - 1) % 3; case 2:
shift = true; case 3:
return; if (header.version >= 3)
{
case 4: synonym = zchar;
case 5: return;
if (header.version >= 3) // shift key }
{ // version 1 or 2
shiftAlphabet = zchar - 3; shiftAlphabet = (alphabet + zchar - 1) % 3;
shift = true; shift = true;
} return;
else // shift lock key
alphabet = (alphabet + zchar - 3) % 3; case 4:
return; case 5:
if (header.version >= 3) // shift key
default: {
if (shift) shiftAlphabet = zchar - 3;
{ shift = true;
text.append (letters[shiftAlphabet].charAt (zchar)); }
shift = false; else // shift lock key
} alphabet = (alphabet + zchar - 3) % 3;
else return;
text.append (letters[alphabet].charAt (zchar));
return; default:
} if (shift)
} {
text.append (letters[shiftAlphabet].charAt (zchar));
@Override shift = false;
public String toString () }
{ else
return text.toString (); text.append (letters[alphabet].charAt (zchar));
} return;
} }
}
@Override
public String toString ()
{
return text.toString ();
}
}
} }