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;
import java.util.ArrayList;
import java.util.List;
class Abbreviations extends InfocomAbstractFile
{
List<ZString> list;
Header header;
int dataPtr;
int dataSize;
int tablePtr;
int tableSize;
public Abbreviations (Header header)
{
super ("Abbreviations", header.buffer);
this.header = header;
dataPtr = header.getWord (header.abbreviationsTable) * 2;
dataSize = header.abbreviationsTable - dataPtr;
tablePtr = header.abbreviationsTable;
tableSize = header.objectTableOffset - header.abbreviationsTable;
// prepare hex dump
hexBlocks.add (new HexBlock (dataPtr, dataSize, "Abbreviations data:"));
hexBlocks.add (new HexBlock (tablePtr, tableSize, "Abbreviations table:"));
}
private void populate ()
{
list = new ArrayList<> ();
for (int i = header.abbreviationsTable; i < header.objectTableOffset; i += 2)
list.add (new ZString (header, header.getWord (i) * 2));
}
public String getAbbreviation (int abbreviationNumber)
{
if (list == null)
populate ();
return list.get (abbreviationNumber).value;
}
@Override
public String getText ()
{
if (list == null)
populate ();
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));
// 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 ();
}
package com.bytezone.diskbrowser.infocom;
import java.util.ArrayList;
import java.util.List;
// -----------------------------------------------------------------------------------//
class Abbreviations extends InfocomAbstractFile
// -----------------------------------------------------------------------------------//
{
List<ZString> list;
Header header;
int dataPtr;
int dataSize;
int tablePtr;
int tableSize;
// ---------------------------------------------------------------------------------//
Abbreviations (Header header)
// ---------------------------------------------------------------------------------//
{
super ("Abbreviations", header.buffer);
this.header = header;
dataPtr = header.getWord (header.abbreviationsTable) * 2;
dataSize = header.abbreviationsTable - dataPtr;
tablePtr = header.abbreviationsTable;
tableSize = header.objectTableOffset - header.abbreviationsTable;
// prepare hex dump
hexBlocks.add (new HexBlock (dataPtr, dataSize, "Abbreviations data:"));
hexBlocks.add (new HexBlock (tablePtr, tableSize, "Abbreviations table:"));
}
// ---------------------------------------------------------------------------------//
private void populate ()
// ---------------------------------------------------------------------------------//
{
list = new ArrayList<> ();
for (int i = header.abbreviationsTable; i < header.objectTableOffset; i += 2)
list.add (new ZString (header, header.getWord (i) * 2));
}
// ---------------------------------------------------------------------------------//
String getAbbreviation (int abbreviationNumber)
// ---------------------------------------------------------------------------------//
{
if (list == null)
populate ();
return list.get (abbreviationNumber).value;
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
if (list == null)
populate ();
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));
// 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.FormattedDisk;
// -----------------------------------------------------------------------------------//
class AttributeManager extends AbstractFile
// -----------------------------------------------------------------------------------//
{
List<Statistic> list = new ArrayList<> ();
Header header;
// ---------------------------------------------------------------------------------//
public AttributeManager (String name, byte[] buffer, Header header)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
this.header = header;
@ -23,7 +27,9 @@ class AttributeManager extends AbstractFile
list.add (new Statistic (attrNo));
}
// ---------------------------------------------------------------------------------//
public void addNodes (DefaultMutableTreeNode node, FormattedDisk disk)
// ---------------------------------------------------------------------------------//
{
node.setAllowsChildren (true);
@ -37,8 +43,10 @@ class AttributeManager extends AbstractFile
}
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ("Attribute Frequency\n");
text.append ("--------- ---------\n");
@ -50,7 +58,9 @@ class AttributeManager extends AbstractFile
return text.toString ();
}
// ---------------------------------------------------------------------------------//
private class Statistic
// ---------------------------------------------------------------------------------//
{
int id;
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.utilities.HexFormatter;
// -----------------------------------------------------------------------------------//
class CodeManager extends AbstractFile
// -----------------------------------------------------------------------------------//
{
private final Header header;
private int codeSize;
private final Map<Integer, Routine> routines = new TreeMap<> ();
public CodeManager (Header header)
// ---------------------------------------------------------------------------------//
CodeManager (Header header)
// ---------------------------------------------------------------------------------//
{
super ("Code", header.buffer);
this.header = header;
}
// ---------------------------------------------------------------------------------//
void addNodes (DefaultMutableTreeNode root, InfocomDisk disk)
// ---------------------------------------------------------------------------------//
{
root.setAllowsChildren (true);
@ -48,7 +54,9 @@ class CodeManager extends AbstractFile
}
}
// ---------------------------------------------------------------------------------//
private List<DiskAddress> getSectors (Routine routine, Disk disk)
// ---------------------------------------------------------------------------------//
{
int blockNo = routine.startPtr / 256 + 48;
int size = routine.length;
@ -62,7 +70,9 @@ class CodeManager extends AbstractFile
return blocks;
}
// ---------------------------------------------------------------------------------//
void addRoutines (int programCounter)
// ---------------------------------------------------------------------------------//
{
addRoutine (programCounter - 1, -1);
addActionRoutines (); // obtained from Grammar
@ -111,19 +121,25 @@ class CodeManager extends AbstractFile
}
}
// ---------------------------------------------------------------------------------//
private int checkAlignment (int ptr)
// ---------------------------------------------------------------------------------//
{
if (ptr % 2 == 1) // routine must start on a word boundary
++ptr;
return ptr;
}
// ---------------------------------------------------------------------------------//
private void addGlobalRoutines ()
// ---------------------------------------------------------------------------------//
{
}
// ---------------------------------------------------------------------------------//
private void addMissingRoutines ()
// ---------------------------------------------------------------------------------//
{
System.out.printf ("%nWalking the code block%n%n");
int total = routines.size ();
@ -158,7 +174,9 @@ class CodeManager extends AbstractFile
routines.size () - total);
}
// ---------------------------------------------------------------------------------//
private int findNextRoutine (int address)
// ---------------------------------------------------------------------------------//
{
for (Routine routine : routines.values ())
if (routine.startPtr > address)
@ -166,8 +184,10 @@ class CodeManager extends AbstractFile
return 0;
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
int count = 0;
@ -188,7 +208,9 @@ class CodeManager extends AbstractFile
return text.toString ();
}
// ---------------------------------------------------------------------------------//
private void addCodeRoutines ()
// ---------------------------------------------------------------------------------//
{
List<Integer> routines = header.objectManager.getCodeRoutines ();
System.out.println ("Adding " + routines.size () + " code routines");
@ -196,7 +218,9 @@ class CodeManager extends AbstractFile
addRoutine (address, 0);
}
// ---------------------------------------------------------------------------------//
private void addActionRoutines ()
// ---------------------------------------------------------------------------------//
{
int total = routines.size ();
@ -211,7 +235,9 @@ class CodeManager extends AbstractFile
System.out.printf ("Added %d action routines%n", routines.size () - total);
}
// ---------------------------------------------------------------------------------//
Routine addRoutine (int address, int caller)
// ---------------------------------------------------------------------------------//
{
if (address == 0) // stack-based call
return null;
@ -240,13 +266,17 @@ class CodeManager extends AbstractFile
return routine;
}
// ---------------------------------------------------------------------------------//
Routine getRoutine (int address)
// ---------------------------------------------------------------------------------//
{
return routines.get (address);
}
// ---------------------------------------------------------------------------------//
@Override
public String getHexDump ()
// ---------------------------------------------------------------------------------//
{
// this depends on codeSize being set after the strings have been processed
return HexFormatter.format (buffer, header.highMemory, codeSize);

View File

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

View File

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

View File

@ -1,298 +1,324 @@
package com.bytezone.diskbrowser.infocom;
import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;
import javax.swing.tree.DefaultMutableTreeNode;
import com.bytezone.diskbrowser.applefile.AppleFileSource;
import com.bytezone.diskbrowser.disk.AbstractFormattedDisk;
import com.bytezone.diskbrowser.disk.AppleDisk;
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
import com.bytezone.diskbrowser.disk.Disk;
import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.disk.SectorType;
import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.utilities.HexFormatter;
// https://mud.co.uk/richard/htflpism.htm
// https://inform-fiction.org/zmachine/standards/
// https://github.com/historicalsource?tab=repositories
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 byte[] data;
private final Header header;
Color green = new Color (0, 200, 0);
SectorType bootSector = new SectorType ("ZIP code", Color.lightGray);
SectorType stringsSector = new SectorType ("Strings", Color.magenta);
SectorType objectsSector = new SectorType ("Objects", green);
SectorType dictionarySector = new SectorType ("Dictionary", Color.blue);
SectorType abbreviationsSector = new SectorType ("Abbreviations", Color.red);
SectorType codeSector = new SectorType ("Code", Color.orange);
SectorType headerSector = new SectorType ("Header", Color.cyan);
SectorType globalsSector = new SectorType ("Globals", Color.darkGray);
SectorType grammarSector = new SectorType ("Grammar", Color.gray);
public InfocomDisk (Disk disk)
{
super (disk);
setInfocomSectorTypes ();
data = disk.readSector (3, 0); // read first sector to get file size
data = getBuffer (getWord (26) * 2); // read entire file into data buffer
if (false)
createStoryFile ("Zork1.sf");
DefaultMutableTreeNode root = getCatalogTreeRoot ();
DefaultMutableTreeNode headerNode = null;
DefaultMutableTreeNode abbreviationsNode = null;
DefaultMutableTreeNode codeNode = null;
DefaultMutableTreeNode objectNode = null;
DefaultMutableTreeNode globalsNode = null;
DefaultMutableTreeNode grammarNode = null;
DefaultMutableTreeNode dictionaryNode = null;
DefaultMutableTreeNode stringsNode = null;
header = new Header ("Header", data, disk);
headerNode = addToTree (root, "Header", header, TYPE_LEAF);
DefaultAppleFileSource dafs = (DefaultAppleFileSource) headerNode.getUserObject ();
List<DiskAddress> blocks = new ArrayList<> ();
blocks.add (disk.getDiskAddress (3, 0));
dafs.setSectors (blocks);
abbreviationsNode =
addToTree (root, "Abbreviations", header.abbreviations, TYPE_LEAF);
objectNode = addToTree (root, "Objects", header.objectManager, TYPE_NODE);
header.objectManager.addNodes (objectNode, this);
globalsNode = addToTree (root, "Globals", header.globals, TYPE_LEAF);
grammarNode = addToTree (root, "Grammar", header.grammar, TYPE_LEAF);
dictionaryNode = addToTree (root, "Dictionary", header.dictionary, TYPE_LEAF);
codeNode = addToTree (root, "Code", header.codeManager, TYPE_NODE);
header.codeManager.addNodes (codeNode, this);
stringsNode = addToTree (root, "Strings", header.stringManager, TYPE_LEAF);
PropertyManager pm = new PropertyManager ("Properties", data, header);
pm.addNodes (addToTree (root, "Properties", pm, TYPE_NODE), this);
AttributeManager am = new AttributeManager ("Attributes", data, header);
am.addNodes (addToTree (root, "Attributes", am, TYPE_NODE), this);
sectorTypes[48] = headerSector;
setSectorTypes (header.abbreviationsTable, header.objectTableOffset,
abbreviationsSector, abbreviationsNode);
setSectorTypes (header.objectTableOffset, header.globalsOffset, objectsSector,
objectNode);
setSectorTypes (header.globalsOffset, header.staticMemory, globalsSector,
globalsNode);
setSectorTypes (header.staticMemory, header.dictionaryOffset, grammarSector,
grammarNode);
setSectorTypes (header.dictionaryOffset, header.highMemory, dictionarySector,
dictionaryNode);
setSectorTypes (header.highMemory, header.stringPointer, codeSector, codeNode);
setSectorTypes (header.stringPointer, header.fileLength, stringsSector, stringsNode);
}
protected void setInfocomSectorTypes ()
{
sectorTypesList.add (bootSector);
sectorTypesList.add (headerSector);
sectorTypesList.add (abbreviationsSector);
sectorTypesList.add (objectsSector);
sectorTypesList.add (globalsSector);
sectorTypesList.add (grammarSector);
sectorTypesList.add (dictionarySector);
sectorTypesList.add (codeSector);
sectorTypesList.add (stringsSector);
for (int track = 0; track < 3; track++)
for (int sector = 0; sector < 16; sector++)
if (!disk.isSectorEmpty (track, sector))
sectorTypes[track * 16 + sector] = bootSector;
}
private void setSectorTypes (int sectorFrom, int sectorTo, SectorType type,
DefaultMutableTreeNode node)
{
DefaultAppleFileSource dafs = (DefaultAppleFileSource) node.getUserObject ();
List<DiskAddress> blocks = new ArrayList<> ();
int blockNo = sectorFrom / disk.getBlockSize () + 48;
int blockTo = sectorTo / disk.getBlockSize () + 48;
while (blockNo <= blockTo)
{
blocks.add (disk.getDiskAddress (blockNo));
if (!disk.isSectorEmpty (blockNo))
sectorTypes[blockNo] = type;
blockNo++;
}
dafs.setSectors (blocks);
}
private int getFileSize ()
{
byte[] buffer = null;
int startBlock = getWord (4) / 256 + 48;
int fileSize = 0;
for (DiskAddress da : disk)
{
if (da.getBlock () > startBlock && disk.isSectorEmpty (da))
{
System.out.println ("Empty : " + da);
buffer = disk.readSector (da.getBlock () - 1);
fileSize = (da.getBlock () - 48) * disk.getBlockSize ();
break;
}
}
if (buffer != null)
{
int ptr = 255;
while (buffer[ptr--] == 0)
fileSize--;
}
return fileSize;
}
private byte[] getBuffer (int fileSize)
{
if (fileSize == 0)
fileSize = getFileSize ();
data = new byte[fileSize];
for (int track = 3, ptr = 0; track < 35; track++)
for (int sector = 0; sector < 16; sector++, ptr += BLOCK_SIZE)
{
byte[] temp = disk.readSector (track, sector);
int spaceLeft = fileSize - ptr;
if (spaceLeft <= BLOCK_SIZE)
{
System.arraycopy (temp, 0, data, ptr, spaceLeft);
return data;
}
System.arraycopy (temp, 0, data, ptr, BLOCK_SIZE);
}
return data;
}
private DefaultMutableTreeNode addToTree (DefaultMutableTreeNode root, String title,
DataSource af, boolean allowsChildren)
{
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, af, this);
// dafs.setSectors (blocks);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
node.setAllowsChildren (allowsChildren);
root.add (node);
return node;
}
@Override
public List<DiskAddress> getFileSectors (int fileNo)
{
return null;
}
@Override
public AppleFileSource getCatalog ()
{
return new DefaultAppleFileSource (header.getText (), this);
}
public static boolean isCorrectFormat (AppleDisk disk)
{
disk.setInterleave (2);
return checkFormat (disk);
}
public static boolean checkFormat (AppleDisk disk)
{
byte[] buffer = disk.readSector (3, 0);
int version = buffer[0] & 0xFF;
int highMemory = HexFormatter.intValue (buffer[5], buffer[4]);
int programCounter = HexFormatter.intValue (buffer[7], buffer[6]);
int dictionary = HexFormatter.intValue (buffer[9], buffer[8]);
int objectTable = HexFormatter.intValue (buffer[11], buffer[10]);
int globals = HexFormatter.intValue (buffer[13], buffer[12]);
int staticMemory = HexFormatter.intValue (buffer[15], buffer[14]);
int abbreviationsTable = HexFormatter.intValue (buffer[25], buffer[24]);
int fileLength = HexFormatter.intValue (buffer[27], buffer[26]);
if (true)
{
System.out.printf ("Version %,6d%n", version);
System.out.printf ("Abbreviations %,6d%n", abbreviationsTable);
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);
System.out.printf ("High memory %,6d%n", highMemory);
System.out.printf ("Program counter %,6d%n", programCounter);
System.out.printf ("File length %,6d%n", fileLength);
}
if (abbreviationsTable >= objectTable)
return false;
// if (objectTable >= globals)
// return false;
if (globals >= staticMemory)
return false;
if (staticMemory >= dictionary)
return false;
if (dictionary >= highMemory)
return false;
// if (highMemory > programCounter)
// return false;
if (version < 2 || version > 3)
{
System.out.println ("Incorrect format : " + version);
JOptionPane.showMessageDialog (null,
"This appears to be an Infocom disk," + " but version " + version
+ " is not supported",
"Unknown disk format", JOptionPane.INFORMATION_MESSAGE);
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 ();
}
}
package com.bytezone.diskbrowser.infocom;
import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;
import javax.swing.tree.DefaultMutableTreeNode;
import com.bytezone.diskbrowser.applefile.AppleFileSource;
import com.bytezone.diskbrowser.disk.AbstractFormattedDisk;
import com.bytezone.diskbrowser.disk.AppleDisk;
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
import com.bytezone.diskbrowser.disk.Disk;
import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.disk.SectorType;
import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.utilities.HexFormatter;
// https://mud.co.uk/richard/htflpism.htm
// https://inform-fiction.org/zmachine/standards/
// https://github.com/historicalsource?tab=repositories
// -----------------------------------------------------------------------------------//
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 byte[] data;
private final Header header;
Color green = new Color (0, 200, 0);
SectorType bootSector = new SectorType ("ZIP code", Color.lightGray);
SectorType stringsSector = new SectorType ("Strings", Color.magenta);
SectorType objectsSector = new SectorType ("Objects", green);
SectorType dictionarySector = new SectorType ("Dictionary", Color.blue);
SectorType abbreviationsSector = new SectorType ("Abbreviations", Color.red);
SectorType codeSector = new SectorType ("Code", Color.orange);
SectorType headerSector = new SectorType ("Header", Color.cyan);
SectorType globalsSector = new SectorType ("Globals", Color.darkGray);
SectorType grammarSector = new SectorType ("Grammar", Color.gray);
// ---------------------------------------------------------------------------------//
public InfocomDisk (Disk disk)
// ---------------------------------------------------------------------------------//
{
super (disk);
setInfocomSectorTypes ();
data = disk.readSector (3, 0); // read first sector to get file size
data = getBuffer (getWord (26) * 2); // read entire file into data buffer
if (false)
createStoryFile ("Zork1.sf");
DefaultMutableTreeNode root = getCatalogTreeRoot ();
DefaultMutableTreeNode headerNode = null;
DefaultMutableTreeNode abbreviationsNode = null;
DefaultMutableTreeNode codeNode = null;
DefaultMutableTreeNode objectNode = null;
DefaultMutableTreeNode globalsNode = null;
DefaultMutableTreeNode grammarNode = null;
DefaultMutableTreeNode dictionaryNode = null;
DefaultMutableTreeNode stringsNode = null;
header = new Header ("Header", data, disk);
headerNode = addToTree (root, "Header", header, TYPE_LEAF);
DefaultAppleFileSource dafs = (DefaultAppleFileSource) headerNode.getUserObject ();
List<DiskAddress> blocks = new ArrayList<> ();
blocks.add (disk.getDiskAddress (3, 0));
dafs.setSectors (blocks);
abbreviationsNode =
addToTree (root, "Abbreviations", header.abbreviations, TYPE_LEAF);
objectNode = addToTree (root, "Objects", header.objectManager, TYPE_NODE);
header.objectManager.addNodes (objectNode, this);
globalsNode = addToTree (root, "Globals", header.globals, TYPE_LEAF);
grammarNode = addToTree (root, "Grammar", header.grammar, TYPE_LEAF);
dictionaryNode = addToTree (root, "Dictionary", header.dictionary, TYPE_LEAF);
codeNode = addToTree (root, "Code", header.codeManager, TYPE_NODE);
header.codeManager.addNodes (codeNode, this);
stringsNode = addToTree (root, "Strings", header.stringManager, TYPE_LEAF);
PropertyManager pm = new PropertyManager ("Properties", data, header);
pm.addNodes (addToTree (root, "Properties", pm, TYPE_NODE), this);
AttributeManager am = new AttributeManager ("Attributes", data, header);
am.addNodes (addToTree (root, "Attributes", am, TYPE_NODE), this);
sectorTypes[48] = headerSector;
setSectorTypes (header.abbreviationsTable, header.objectTableOffset,
abbreviationsSector, abbreviationsNode);
setSectorTypes (header.objectTableOffset, header.globalsOffset, objectsSector,
objectNode);
setSectorTypes (header.globalsOffset, header.staticMemory, globalsSector,
globalsNode);
setSectorTypes (header.staticMemory, header.dictionaryOffset, grammarSector,
grammarNode);
setSectorTypes (header.dictionaryOffset, header.highMemory, dictionarySector,
dictionaryNode);
setSectorTypes (header.highMemory, header.stringPointer, codeSector, codeNode);
setSectorTypes (header.stringPointer, header.fileLength, stringsSector, stringsNode);
}
// ---------------------------------------------------------------------------------//
protected void setInfocomSectorTypes ()
// ---------------------------------------------------------------------------------//
{
sectorTypesList.add (bootSector);
sectorTypesList.add (headerSector);
sectorTypesList.add (abbreviationsSector);
sectorTypesList.add (objectsSector);
sectorTypesList.add (globalsSector);
sectorTypesList.add (grammarSector);
sectorTypesList.add (dictionarySector);
sectorTypesList.add (codeSector);
sectorTypesList.add (stringsSector);
for (int track = 0; track < 3; track++)
for (int sector = 0; sector < 16; sector++)
if (!disk.isSectorEmpty (track, sector))
sectorTypes[track * 16 + sector] = bootSector;
}
// ---------------------------------------------------------------------------------//
private void setSectorTypes (int sectorFrom, int sectorTo, SectorType type,
DefaultMutableTreeNode node)
// ---------------------------------------------------------------------------------//
{
DefaultAppleFileSource dafs = (DefaultAppleFileSource) node.getUserObject ();
List<DiskAddress> blocks = new ArrayList<> ();
int blockNo = sectorFrom / disk.getBlockSize () + 48;
int blockTo = sectorTo / disk.getBlockSize () + 48;
while (blockNo <= blockTo)
{
blocks.add (disk.getDiskAddress (blockNo));
if (!disk.isSectorEmpty (blockNo))
sectorTypes[blockNo] = type;
blockNo++;
}
dafs.setSectors (blocks);
}
// ---------------------------------------------------------------------------------//
private int getFileSize ()
// ---------------------------------------------------------------------------------//
{
byte[] buffer = null;
int startBlock = getWord (4) / 256 + 48;
int fileSize = 0;
for (DiskAddress da : disk)
{
if (da.getBlock () > startBlock && disk.isSectorEmpty (da))
{
System.out.println ("Empty : " + da);
buffer = disk.readSector (da.getBlock () - 1);
fileSize = (da.getBlock () - 48) * disk.getBlockSize ();
break;
}
}
if (buffer != null)
{
int ptr = 255;
while (buffer[ptr--] == 0)
fileSize--;
}
return fileSize;
}
// ---------------------------------------------------------------------------------//
private byte[] getBuffer (int fileSize)
// ---------------------------------------------------------------------------------//
{
if (fileSize == 0)
fileSize = getFileSize ();
data = new byte[fileSize];
for (int track = 3, ptr = 0; track < 35; track++)
for (int sector = 0; sector < 16; sector++, ptr += BLOCK_SIZE)
{
byte[] temp = disk.readSector (track, sector);
int spaceLeft = fileSize - ptr;
if (spaceLeft <= BLOCK_SIZE)
{
System.arraycopy (temp, 0, data, ptr, spaceLeft);
return data;
}
System.arraycopy (temp, 0, data, ptr, BLOCK_SIZE);
}
return data;
}
// ---------------------------------------------------------------------------------//
private DefaultMutableTreeNode addToTree (DefaultMutableTreeNode root, String title,
DataSource af, boolean allowsChildren)
// ---------------------------------------------------------------------------------//
{
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, af, this);
// dafs.setSectors (blocks);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
node.setAllowsChildren (allowsChildren);
root.add (node);
return node;
}
// ---------------------------------------------------------------------------------//
@Override
public List<DiskAddress> getFileSectors (int fileNo)
// ---------------------------------------------------------------------------------//
{
return null;
}
// ---------------------------------------------------------------------------------//
@Override
public AppleFileSource getCatalog ()
// ---------------------------------------------------------------------------------//
{
return new DefaultAppleFileSource (header.getText (), this);
}
// ---------------------------------------------------------------------------------//
public static boolean isCorrectFormat (AppleDisk disk)
// ---------------------------------------------------------------------------------//
{
disk.setInterleave (2);
return checkFormat (disk);
}
// ---------------------------------------------------------------------------------//
public static boolean checkFormat (AppleDisk disk)
// ---------------------------------------------------------------------------------//
{
byte[] buffer = disk.readSector (3, 0);
int version = buffer[0] & 0xFF;
int highMemory = HexFormatter.intValue (buffer[5], buffer[4]);
int programCounter = HexFormatter.intValue (buffer[7], buffer[6]);
int dictionary = HexFormatter.intValue (buffer[9], buffer[8]);
int objectTable = HexFormatter.intValue (buffer[11], buffer[10]);
int globals = HexFormatter.intValue (buffer[13], buffer[12]);
int staticMemory = HexFormatter.intValue (buffer[15], buffer[14]);
int abbreviationsTable = HexFormatter.intValue (buffer[25], buffer[24]);
int fileLength = HexFormatter.intValue (buffer[27], buffer[26]);
if (true)
{
System.out.printf ("Version %,6d%n", version);
System.out.printf ("Abbreviations %,6d%n", abbreviationsTable);
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);
System.out.printf ("High memory %,6d%n", highMemory);
System.out.printf ("Program counter %,6d%n", programCounter);
System.out.printf ("File length %,6d%n", fileLength);
}
if (abbreviationsTable >= objectTable)
return false;
// if (objectTable >= globals)
// return false;
if (globals >= staticMemory)
return false;
if (staticMemory >= dictionary)
return false;
if (dictionary >= highMemory)
return false;
// if (highMemory > programCounter)
// return false;
if (version < 2 || version > 3)
{
System.out.println ("Incorrect format : " + version);
JOptionPane.showMessageDialog (null,
"This appears to be an Infocom disk," + " but version " + version
+ " is not supported",
"Unknown disk format", JOptionPane.INFORMATION_MESSAGE);
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;
// -----------------------------------------------------------------------------------//
class ObjectAnalyser
// -----------------------------------------------------------------------------------//
{
Header header;
ObjectManager parent;
List<Statistics> list = new ArrayList<Statistics> ();
List<Integer> routines = new ArrayList<Integer> ();
// ---------------------------------------------------------------------------------//
public ObjectAnalyser (Header header, ObjectManager parent)
// ---------------------------------------------------------------------------------//
{
this.header = header;
this.parent = parent;
@ -31,7 +35,9 @@ class ObjectAnalyser
checkThreeByteProperties ();
}
// ---------------------------------------------------------------------------------//
public void setStringPointer ()
// ---------------------------------------------------------------------------------//
{
PropertyTester pt = new PropertyTester (parent.getObjects ());
pt.addTest (new LengthTwoCondition ());
@ -58,7 +64,9 @@ class ObjectAnalyser
}
}
// ---------------------------------------------------------------------------------//
public void createPropertyLinks ()
// ---------------------------------------------------------------------------------//
{
int sCount = 0;
int rCount = 0;
@ -85,7 +93,9 @@ class ObjectAnalyser
System.out.println ("Routines found : " + totRoutines);
}
// ---------------------------------------------------------------------------------//
private void checkThreeByteProperties ()
// ---------------------------------------------------------------------------------//
{
System.out.printf ("Checking %d objects%n", parent.getObjects ().size ());
for (ZObject object : parent.getObjects ())
@ -106,7 +116,9 @@ class ObjectAnalyser
}
// find the property with only dictionary entries
// ---------------------------------------------------------------------------------//
public void setDictionary ()
// ---------------------------------------------------------------------------------//
{
PropertyTester pt = new PropertyTester (parent.getObjects ());
pt.addTest (new LengthEvenCondition ());
@ -118,7 +130,9 @@ class ObjectAnalyser
header.propertyNames[i] = "DICT"; // SYNONYM
}
// ---------------------------------------------------------------------------------//
class Statistics implements Comparable<Statistics>
// ---------------------------------------------------------------------------------//
{
int propertyNumber;
int lo;
@ -153,7 +167,9 @@ class ObjectAnalyser
}
}
// ---------------------------------------------------------------------------------//
class LengthTwoCondition extends Condition
// ---------------------------------------------------------------------------------//
{
@Override
boolean test (Property property)
@ -162,7 +178,9 @@ class ObjectAnalyser
}
}
// ---------------------------------------------------------------------------------//
class LengthThreeCondition extends Condition
// ---------------------------------------------------------------------------------//
{
@Override
boolean test (Property property)
@ -171,7 +189,9 @@ class ObjectAnalyser
}
}
// ---------------------------------------------------------------------------------//
class LengthEvenCondition extends Condition
// ---------------------------------------------------------------------------------//
{
@Override
boolean test (Property property)
@ -180,7 +200,9 @@ class ObjectAnalyser
}
}
// ---------------------------------------------------------------------------------//
class HighMemoryCondition extends Condition
// ---------------------------------------------------------------------------------//
{
int lo, hi;
Statistics[] statistics = new Statistics[32]; // note there is no property #0
@ -202,7 +224,9 @@ class ObjectAnalyser
}
}
// ---------------------------------------------------------------------------------//
class ValidDictionaryCondition extends Condition
// ---------------------------------------------------------------------------------//
{
@Override
boolean test (Property property)

View File

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

View File

@ -6,23 +6,31 @@ import java.util.List;
import com.bytezone.diskbrowser.infocom.ZObject.Property;
// -----------------------------------------------------------------------------------//
class PropertyTester implements Iterable<Integer>
// -----------------------------------------------------------------------------------//
{
List<ZObject> objects;
List<Condition> conditions = new ArrayList<> ();
List<Integer> matchedProperties;
public PropertyTester (List<ZObject> objects)
// ---------------------------------------------------------------------------------//
PropertyTester (List<ZObject> objects)
// ---------------------------------------------------------------------------------//
{
this.objects = objects;
}
// ---------------------------------------------------------------------------------//
public void addTest (Condition test)
// ---------------------------------------------------------------------------------//
{
conditions.add (test);
}
// ---------------------------------------------------------------------------------//
public void doTests ()
// ---------------------------------------------------------------------------------//
{
boolean[] propFail = new boolean[32];
int[] propTestCount = new int[32];
@ -47,19 +55,25 @@ class PropertyTester implements Iterable<Integer>
matchedProperties.add (i);
}
// ---------------------------------------------------------------------------------//
@Override
public Iterator<Integer> iterator ()
// ---------------------------------------------------------------------------------//
{
return matchedProperties.iterator ();
}
// ---------------------------------------------------------------------------------//
public int totalSuccessfulProperties ()
// ---------------------------------------------------------------------------------//
{
return matchedProperties.size ();
}
}
// ---------------------------------------------------------------------------------//
abstract class Condition
// ---------------------------------------------------------------------------------//
{
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.utilities.HexFormatter;
// -----------------------------------------------------------------------------------//
class Routine extends InfocomAbstractFile
implements Iterable<Instruction>, Comparable<Routine>
// -----------------------------------------------------------------------------------//
{
int startPtr, length, strings, locals;
@ -20,7 +22,9 @@ class Routine extends InfocomAbstractFile
List<Integer> actions = new ArrayList<> (); // not used yet
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);
@ -104,7 +108,9 @@ class Routine extends InfocomAbstractFile
}
}
// ---------------------------------------------------------------------------------//
String dump ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("%05X : %s", startPtr,
@ -118,13 +124,17 @@ class Routine extends InfocomAbstractFile
return text.toString ();
}
// ---------------------------------------------------------------------------------//
boolean isValid ()
// ---------------------------------------------------------------------------------//
{
return startPtr > 0;
}
// test whether the routine contains any instructions pointing to this address
// ---------------------------------------------------------------------------------//
private boolean isTarget (int ptr)
// ---------------------------------------------------------------------------------//
{
for (Instruction ins : instructions)
{
@ -137,13 +147,17 @@ class Routine extends InfocomAbstractFile
return false;
}
// ---------------------------------------------------------------------------------//
public void addCaller (int caller)
// ---------------------------------------------------------------------------------//
{
calledBy.add (caller);
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
@ -193,14 +207,18 @@ class Routine extends InfocomAbstractFile
return text.toString ();
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
return String.format ("[Start: %05X, Len: %4d, Strings: %2d, Locals: %2d]", startPtr,
length, strings, locals);
}
// ---------------------------------------------------------------------------------//
class Parameter
// ---------------------------------------------------------------------------------//
{
int value;
int sequence;

View File

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

View File

@ -1,278 +1,298 @@
package com.bytezone.diskbrowser.infocom;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.HexFormatter;
class ZObject extends AbstractFile implements Comparable<ZObject>
{
static final int HEADER_SIZE = 9;
private final Header header;
private final int id;
private final int startPtr;
private final int propertyTablePtr;
private final int propertyTableLength;
final int parent, sibling, child;
final List<Property> properties = new ArrayList<> ();
final BitSet attributes = new BitSet (32);
public ZObject (String name, byte[] buffer, int offset, int id, Header header)
{
super (name, buffer);
this.header = header;
this.startPtr = offset;
this.id = id;
// 32 attributes
int bitIndex = 0;
for (int i = 0; i < 4; i++)
{
byte b = buffer[offset + i];
for (int j = 0; j < 8; j++)
{
if ((b & 0x80) != 0)
attributes.set (bitIndex);
b <<= 1;
++bitIndex;
}
}
// object's relatives
parent = header.getByte (offset + 4);
sibling = header.getByte (offset + 5);
child = header.getByte (offset + 6);
// the property header contains the object's short name
propertyTablePtr = header.getWord (offset + 7);
int ptr = propertyTablePtr;
int nameLength = header.getByte (ptr) * 2;
this.name = nameLength == 0 ? "<<" + id + ">>" : new ZString (header, ++ptr).value;
ptr += nameLength;
// read each property
while (buffer[ptr] != 0)
{
Property p = new Property (ptr);
properties.add (p);
ptr += p.length + 1;
}
propertyTableLength = ptr - propertyTablePtr;
}
int getId ()
{
return id;
}
@Override
public String getText ()
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("ID : %02X (%<3d) %s%n%n", id, name));
String obj1 = parent == 0 ? "" : header.getObject (parent - 1).name;
String obj2 = sibling == 0 ? "" : header.getObject (sibling - 1).name;
String obj3 = child == 0 ? "" : header.getObject (child - 1).name;
text.append (String.format ("Parent : %02X (%<3d) %s%n", parent, obj1));
text.append (String.format ("Sibling : %02X (%<3d) %s%n", sibling, obj2));
text.append (String.format ("Child : %02X (%<3d) %s%n%n", child, obj3));
text.append ("Attributes : ");
text.append (HexFormatter.getHexString (buffer, startPtr, 4));
text.append (" " + attributes.toString () + "\n\n");
for (Property prop : properties)
text.append (prop + "\n");
return text.toString ();
}
@Override
public String getHexDump ()
{
StringBuilder text = new StringBuilder ("Header :\n\n");
text.append (HexFormatter.formatNoHeader (buffer, startPtr, HEADER_SIZE));
text.append ("\n\nProperty table:\n\n");
text.append (
HexFormatter.formatNoHeader (buffer, propertyTablePtr, propertyTableLength));
return text.toString ();
}
Property getProperty (int id)
{
for (Property p : properties)
if (p.propertyNumber == id)
return p;
return null;
}
@Override
public String toString ()
{
return HexFormatter.getHexString (buffer, startPtr, HEADER_SIZE) + " " + name;
}
public String getDescription (List<ZObject> list)
{
StringBuilder text = new StringBuilder (String.format (" %-40s", getName ()));
for (int i = 4; i < 7; i++)
{
int index = buffer[startPtr + i] & 0xFF;
String name = index > 0 ? list.get (index - 1).getName () : "";
text.append (String.format (" %-40s", name));
}
text.append (" ");
text.append (HexFormatter.getHexString (buffer, startPtr, 4));
text.append (" ");
text.append (HexFormatter.getHexString (buffer, startPtr + 7, 2));
return text.toString ();
}
class Property
{
int propertyNumber;
int ptr;
int length;
int offset; // only used if length == 2
public Property (int ptr)
{
this.ptr = ptr;
length = header.getByte (ptr) / 32 + 1;
propertyNumber = header.getByte (ptr) % 32;
if (length == 2)
offset = header.getWord (ptr + 1) * 2;
}
private ZObject getObject ()
{
return header.getObject ((buffer[ptr + 1] & 0xFF) - 1);
}
private ZObject getObject (int id)
{
return header.getObject (id - 1);
}
@Override
public String toString ()
{
StringBuilder text = new StringBuilder (
String.format ("%8s : ", header.getPropertyName (propertyNumber)));
String propertyType = header.getPropertyName (propertyNumber);
if (!(propertyType.equals ("DICT") || propertyType.startsWith ("STR")))
text.append (
String.format ("%-20s", HexFormatter.getHexString (buffer, ptr + 1, length)));
if (propertyNumber >= 19) // directions
{
switch (length)
{
case 1: // UEXIT - unconditional exit
text.append (getObject ().name);
break;
case 2:
text.append ("\"" + header.stringManager.stringAt (offset) + "\"");
break;
case 3: // FEXIT - function exit
int address = header.getWord (ptr + 1) * 2;
text.append (String.format ("R:%05X", address));
appendRoutine (text, address);
break;
case 4:
text.append (String.format ("%s : IF G%02X ELSE ", getObject ().name,
header.getByte (ptr + 2)));
address = header.getWord (ptr + 3) * 2;
if (address > 0)
text.append ("\"" + header.stringManager.stringAt (address) + "\"");
break;
case 5:
text.append (String.format ("%s : IF G%02X ", getObject ().name,
header.getByte (ptr + 2)));
break;
default:
break;
}
}
else if (propertyType.equals ("DICT"))
{
for (int i = 1; i <= length; i += 2)
{
int address = header.getWord (ptr + i);
text.append (String.format ("%02X: %s, ", address, header.wordAt (address)));
}
text.deleteCharAt (text.length () - 1);
text.deleteCharAt (text.length () - 1);
}
else if (propertyType.startsWith ("CODE"))
{
if (offset > 0) // cretin contains 00 00
appendRoutine (text, offset);
}
else if (propertyType.startsWith ("STR"))
{
text.append (String.format ("(%4X) \"%s\"", offset,
header.stringManager.stringAt (offset)));
}
else if (propertyType.equals ("ADJ"))
{
}
else if (propertyType.equals ("SIZE"))
{
}
else if (propertyType.equals ("VALUE"))
{
}
else if (propertyType.equals ("TVALU"))
{
}
else if (propertyType.equals ("GLBL"))
{
for (int i = 0; i < length; i++)
{
int objectId = header.getByte (ptr + i + 1);
text.append (
String.format ("%s%s", (i == 0 ? "" : ", "), getObject (objectId).name));
}
}
// else
// text.append ("Unknown property type: " + propertyType);
return text.toString ();
}
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);
}
package com.bytezone.diskbrowser.infocom;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.HexFormatter;
// -----------------------------------------------------------------------------------//
class ZObject extends AbstractFile implements Comparable<ZObject>
// -----------------------------------------------------------------------------------//
{
static final int HEADER_SIZE = 9;
private final Header header;
private final int id;
private final int startPtr;
private final int propertyTablePtr;
private final int propertyTableLength;
final int parent, sibling, child;
final List<Property> properties = new ArrayList<> ();
final BitSet attributes = new BitSet (32);
// ---------------------------------------------------------------------------------//
ZObject (String name, byte[] buffer, int offset, int id, Header header)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
this.header = header;
this.startPtr = offset;
this.id = id;
// 32 attributes
int bitIndex = 0;
for (int i = 0; i < 4; i++)
{
byte b = buffer[offset + i];
for (int j = 0; j < 8; j++)
{
if ((b & 0x80) != 0)
attributes.set (bitIndex);
b <<= 1;
++bitIndex;
}
}
// object's relatives
parent = header.getByte (offset + 4);
sibling = header.getByte (offset + 5);
child = header.getByte (offset + 6);
// the property header contains the object's short name
propertyTablePtr = header.getWord (offset + 7);
int ptr = propertyTablePtr;
int nameLength = header.getByte (ptr) * 2;
this.name = nameLength == 0 ? "<<" + id + ">>" : new ZString (header, ++ptr).value;
ptr += nameLength;
// read each property
while (buffer[ptr] != 0)
{
Property p = new Property (ptr);
properties.add (p);
ptr += p.length + 1;
}
propertyTableLength = ptr - propertyTablePtr;
}
// ---------------------------------------------------------------------------------//
int getId ()
// ---------------------------------------------------------------------------------//
{
return id;
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("ID : %02X (%<3d) %s%n%n", id, name));
String obj1 = parent == 0 ? "" : header.getObject (parent - 1).name;
String obj2 = sibling == 0 ? "" : header.getObject (sibling - 1).name;
String obj3 = child == 0 ? "" : header.getObject (child - 1).name;
text.append (String.format ("Parent : %02X (%<3d) %s%n", parent, obj1));
text.append (String.format ("Sibling : %02X (%<3d) %s%n", sibling, obj2));
text.append (String.format ("Child : %02X (%<3d) %s%n%n", child, obj3));
text.append ("Attributes : ");
text.append (HexFormatter.getHexString (buffer, startPtr, 4));
text.append (" " + attributes.toString () + "\n\n");
for (Property prop : properties)
text.append (prop + "\n");
return text.toString ();
}
// ---------------------------------------------------------------------------------//
@Override
public String getHexDump ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ("Header :\n\n");
text.append (HexFormatter.formatNoHeader (buffer, startPtr, HEADER_SIZE));
text.append ("\n\nProperty table:\n\n");
text.append (
HexFormatter.formatNoHeader (buffer, propertyTablePtr, propertyTableLength));
return text.toString ();
}
// ---------------------------------------------------------------------------------//
Property getProperty (int id)
// ---------------------------------------------------------------------------------//
{
for (Property p : properties)
if (p.propertyNumber == id)
return p;
return null;
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
return HexFormatter.getHexString (buffer, startPtr, HEADER_SIZE) + " " + name;
}
// ---------------------------------------------------------------------------------//
public String getDescription (List<ZObject> list)
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder (String.format (" %-40s", getName ()));
for (int i = 4; i < 7; i++)
{
int index = buffer[startPtr + i] & 0xFF;
String name = index > 0 ? list.get (index - 1).getName () : "";
text.append (String.format (" %-40s", name));
}
text.append (" ");
text.append (HexFormatter.getHexString (buffer, startPtr, 4));
text.append (" ");
text.append (HexFormatter.getHexString (buffer, startPtr + 7, 2));
return text.toString ();
}
// ---------------------------------------------------------------------------------//
class Property
// ---------------------------------------------------------------------------------//
{
int propertyNumber;
int ptr;
int length;
int offset; // only used if length == 2
public Property (int ptr)
{
this.ptr = ptr;
length = header.getByte (ptr) / 32 + 1;
propertyNumber = header.getByte (ptr) % 32;
if (length == 2)
offset = header.getWord (ptr + 1) * 2;
}
private ZObject getObject ()
{
return header.getObject ((buffer[ptr + 1] & 0xFF) - 1);
}
private ZObject getObject (int id)
{
return header.getObject (id - 1);
}
@Override
public String toString ()
{
StringBuilder text = new StringBuilder (
String.format ("%8s : ", header.getPropertyName (propertyNumber)));
String propertyType = header.getPropertyName (propertyNumber);
if (!(propertyType.equals ("DICT") || propertyType.startsWith ("STR")))
text.append (
String.format ("%-20s", HexFormatter.getHexString (buffer, ptr + 1, length)));
if (propertyNumber >= 19) // directions
{
switch (length)
{
case 1: // UEXIT - unconditional exit
text.append (getObject ().name);
break;
case 2:
text.append ("\"" + header.stringManager.stringAt (offset) + "\"");
break;
case 3: // FEXIT - function exit
int address = header.getWord (ptr + 1) * 2;
text.append (String.format ("R:%05X", address));
appendRoutine (text, address);
break;
case 4:
text.append (String.format ("%s : IF G%02X ELSE ", getObject ().name,
header.getByte (ptr + 2)));
address = header.getWord (ptr + 3) * 2;
if (address > 0)
text.append ("\"" + header.stringManager.stringAt (address) + "\"");
break;
case 5:
text.append (String.format ("%s : IF G%02X ", getObject ().name,
header.getByte (ptr + 2)));
break;
default:
break;
}
}
else if (propertyType.equals ("DICT"))
{
for (int i = 1; i <= length; i += 2)
{
int address = header.getWord (ptr + i);
text.append (String.format ("%02X: %s, ", address, header.wordAt (address)));
}
text.deleteCharAt (text.length () - 1);
text.deleteCharAt (text.length () - 1);
}
else if (propertyType.startsWith ("CODE"))
{
if (offset > 0) // cretin contains 00 00
appendRoutine (text, offset);
}
else if (propertyType.startsWith ("STR"))
{
text.append (String.format ("(%4X) \"%s\"", offset,
header.stringManager.stringAt (offset)));
}
else if (propertyType.equals ("ADJ"))
{
}
else if (propertyType.equals ("SIZE"))
{
}
else if (propertyType.equals ("VALUE"))
{
}
else if (propertyType.equals ("TVALU"))
{
}
else if (propertyType.equals ("GLBL"))
{
for (int i = 0; i < length; i++)
{
int objectId = header.getByte (ptr + i + 1);
text.append (
String.format ("%s%s", (i == 0 ? "" : ", "), getObject (objectId).name));
}
}
// else
// text.append ("Unknown property type: " + propertyType);
return text.toString ();
}
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;
class ZString
{
private static String[] letters =
{ " abcdefghijklmnopqrstuvwxyz", " ABCDEFGHIJKLMNOPQRSTUVWXYZ",
" 0123456789.,!?_#\'\"/\\-:()" };
String value;
Header header;
int startPtr;
int length;
public ZString (Header header, int offset)
{
ZStringBuilder text = new ZStringBuilder ();
this.header = header;
this.startPtr = offset;
while (true)
{
if (offset >= header.buffer.length - 1)
{
System.out.println ("********" + text.toString ());
break;
}
// get the next two bytes
int val = header.getWord (offset);
// process each zChar as a 5-bit value
text.processZChar ((byte) ((val >>> 10) & 0x1F));
text.processZChar ((byte) ((val >>> 5) & 0x1F));
text.processZChar ((byte) (val & 0x1F));
if ((val & 0x8000) != 0) // bit 15 = finished flag
{
length = offset - startPtr + 2;
value = text.toString ();
break;
}
offset += 2;
}
}
@Override
public String toString ()
{
return value;
}
private class ZStringBuilder
{
int alphabet;
boolean shift;
int shiftAlphabet;
int synonym;
int buildingLevel;
int builtLetter;
StringBuilder text = new StringBuilder ();
private void processZChar (byte zchar)
{
// A flag to indicate that we are building a character not in the alphabet. The
// value indicates which half of the character the current zchar goes into. Once
// both halves are full, we use the ascii value in builtLetter.
if (buildingLevel > 0)
{
builtLetter = (short) ((builtLetter << 5) | zchar);
if (++buildingLevel == 3)
{
text.append ((char) builtLetter);
buildingLevel = 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
// offset within that block.
if (synonym > 0)
{
text.append (header.getAbbreviation ((synonym - 1) * 32 + zchar));
synonym = 0;
return;
}
if ((shift && shiftAlphabet == 2) || (!shift && alphabet == 2))
{
if (zchar == 6)
{
buildingLevel = 1;
builtLetter = 0;
shift = false;
return;
}
if (zchar == 7)
{
text.append ("\n");
shift = false;
return;
}
}
// zChar values 0-5 have special meanings, and 6-7 are special only in alphabet #2.
// Otherwise it's just a straight lookup into the current alphabet.
switch (zchar)
{
case 0:
text.append (" ");
shift = false;
return;
case 1:
synonym = zchar;
return;
case 2:
case 3:
if (header.version >= 3)
{
synonym = zchar;
return;
}
// version 1 or 2
shiftAlphabet = (alphabet + zchar - 1) % 3;
shift = true;
return;
case 4:
case 5:
if (header.version >= 3) // shift key
{
shiftAlphabet = zchar - 3;
shift = true;
}
else // shift lock key
alphabet = (alphabet + zchar - 3) % 3;
return;
default:
if (shift)
{
text.append (letters[shiftAlphabet].charAt (zchar));
shift = false;
}
else
text.append (letters[alphabet].charAt (zchar));
return;
}
}
@Override
public String toString ()
{
return text.toString ();
}
}
package com.bytezone.diskbrowser.infocom;
// -----------------------------------------------------------------------------------//
class ZString
// -----------------------------------------------------------------------------------//
{
private static String[] letters =
{ " abcdefghijklmnopqrstuvwxyz", " ABCDEFGHIJKLMNOPQRSTUVWXYZ",
" 0123456789.,!?_#\'\"/\\-:()" };
String value;
Header header;
int startPtr;
int length;
// ---------------------------------------------------------------------------------//
ZString (Header header, int offset)
// ---------------------------------------------------------------------------------//
{
ZStringBuilder text = new ZStringBuilder ();
this.header = header;
this.startPtr = offset;
while (true)
{
if (offset >= header.buffer.length - 1)
{
System.out.println ("********" + text.toString ());
break;
}
// get the next two bytes
int val = header.getWord (offset);
// process each zChar as a 5-bit value
text.processZChar ((byte) ((val >>> 10) & 0x1F));
text.processZChar ((byte) ((val >>> 5) & 0x1F));
text.processZChar ((byte) (val & 0x1F));
if ((val & 0x8000) != 0) // bit 15 = finished flag
{
length = offset - startPtr + 2;
value = text.toString ();
break;
}
offset += 2;
}
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
return value;
}
// ---------------------------------------------------------------------------------//
private class ZStringBuilder
// ---------------------------------------------------------------------------------//
{
int alphabet;
boolean shift;
int shiftAlphabet;
int synonym;
int buildingLevel;
int builtLetter;
StringBuilder text = new StringBuilder ();
private void processZChar (byte zchar)
{
// A flag to indicate that we are building a character not in the alphabet. The
// value indicates which half of the character the current zchar goes into. Once
// both halves are full, we use the ascii value in builtLetter.
if (buildingLevel > 0)
{
builtLetter = (short) ((builtLetter << 5) | zchar);
if (++buildingLevel == 3)
{
text.append ((char) builtLetter);
buildingLevel = 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
// offset within that block.
if (synonym > 0)
{
text.append (header.getAbbreviation ((synonym - 1) * 32 + zchar));
synonym = 0;
return;
}
if ((shift && shiftAlphabet == 2) || (!shift && alphabet == 2))
{
if (zchar == 6)
{
buildingLevel = 1;
builtLetter = 0;
shift = false;
return;
}
if (zchar == 7)
{
text.append ("\n");
shift = false;
return;
}
}
// zChar values 0-5 have special meanings, and 6-7 are special only in alphabet #2.
// Otherwise it's just a straight lookup into the current alphabet.
switch (zchar)
{
case 0:
text.append (" ");
shift = false;
return;
case 1:
synonym = zchar;
return;
case 2:
case 3:
if (header.version >= 3)
{
synonym = zchar;
return;
}
// version 1 or 2
shiftAlphabet = (alphabet + zchar - 1) % 3;
shift = true;
return;
case 4:
case 5:
if (header.version >= 3) // shift key
{
shiftAlphabet = zchar - 3;
shift = true;
}
else // shift lock key
alphabet = (alphabet + zchar - 3) % 3;
return;
default:
if (shift)
{
text.append (letters[shiftAlphabet].charAt (zchar));
shift = false;
}
else
text.append (letters[alphabet].charAt (zchar));
return;
}
}
@Override
public String toString ()
{
return text.toString ();
}
}
}