dmolony-DiskBrowser/src/com/bytezone/diskbrowser/infocom/InfocomDisk.java

293 lines
10 KiB
Java
Raw Normal View History

2015-06-01 09:35:51 +00:00
package com.bytezone.diskbrowser.infocom;
import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
2016-07-19 07:44:42 +00:00
import java.util.ArrayList;
2015-06-01 09:35:51 +00:00
import java.util.List;
import javax.swing.JOptionPane;
import javax.swing.tree.DefaultMutableTreeNode;
import com.bytezone.diskbrowser.applefile.AppleFileSource;
2016-02-24 12:39:09 +00:00
import com.bytezone.diskbrowser.disk.*;
2015-06-01 09:35:51 +00:00
import com.bytezone.diskbrowser.gui.DataSource;
2016-02-24 21:11:14 +00:00
import com.bytezone.diskbrowser.utilities.HexFormatter;
2015-06-01 09:35:51 +00:00
2018-10-01 09:34:38 +00:00
// https://mud.co.uk/richard/htflpism.htm
// https://inform-fiction.org/zmachine/standards/
2019-04-19 21:15:12 +00:00
// https://github.com/historicalsource?tab=repositories
2018-10-01 09:34:38 +00:00
2015-06-01 09:35:51 +00:00
public class InfocomDisk extends AbstractFormattedDisk
{
2016-02-25 07:45:24 +00:00
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 int version;
2016-02-29 01:54:44 +00:00
private final Header header;
2016-02-25 07:45:24 +00:00
Color green = new Color (0, 200, 0);
SectorType bootSector = new SectorType ("Boot 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);
2016-02-29 01:54:44 +00:00
setInfocomSectorTypes ();
2016-02-25 07:45:24 +00:00
2016-03-01 00:16:31 +00:00
data = disk.readSector (3, 0); // read first sector to get file size
data = getBuffer (getWord (26) * 2); // read entire file into data buffer
2016-02-25 07:45:24 +00:00
if (false)
createStoryFile ("Zork1.sf");
DefaultMutableTreeNode root = getCatalogTreeRoot ();
2016-07-19 07:44:42 +00:00
DefaultMutableTreeNode headerNode = null;
DefaultMutableTreeNode abbreviationsNode = null;
2016-02-25 07:45:24 +00:00
DefaultMutableTreeNode codeNode = null;
DefaultMutableTreeNode objectNode = null;
2016-07-19 07:44:42 +00:00
DefaultMutableTreeNode globalsNode = null;
DefaultMutableTreeNode grammarNode = null;
DefaultMutableTreeNode dictionaryNode = null;
DefaultMutableTreeNode stringsNode = null;
2016-02-25 07:45:24 +00:00
2016-07-20 05:22:33 +00:00
header = new Header ("Header", data, disk);
2016-02-25 07:45:24 +00:00
2016-07-19 07:44:42 +00:00
headerNode = addToTree (root, "Header", header, TYPE_LEAF);
DefaultAppleFileSource dafs = (DefaultAppleFileSource) headerNode.getUserObject ();
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
blocks.add (disk.getDiskAddress (3, 0));
dafs.setSectors (blocks);
abbreviationsNode =
addToTree (root, "Abbreviations", header.abbreviations, TYPE_LEAF);
2016-02-25 07:45:24 +00:00
objectNode = addToTree (root, "Objects", header.objectManager, TYPE_NODE);
header.objectManager.addNodes (objectNode, this);
2016-07-19 07:44:42 +00:00
globalsNode = addToTree (root, "Globals", header.globals, TYPE_LEAF);
grammarNode = addToTree (root, "Grammar", header.grammar, TYPE_LEAF);
dictionaryNode = addToTree (root, "Dictionary", header.dictionary, TYPE_LEAF);
2016-02-25 07:45:24 +00:00
codeNode = addToTree (root, "Code", header.codeManager, TYPE_NODE);
header.codeManager.addNodes (codeNode, this);
2016-07-19 07:44:42 +00:00
stringsNode = addToTree (root, "Strings", header.stringManager, TYPE_LEAF);
2016-02-25 07:45:24 +00:00
PropertyManager pm = new PropertyManager ("Properties", data, header);
pm.addNodes (addToTree (objectNode, "Properties", pm, TYPE_NODE), this);
AttributeManager am = new AttributeManager ("Attributes", data, header);
am.addNodes (addToTree (objectNode, "Attributes", am, TYPE_NODE), this);
sectorTypes[48] = headerSector;
2016-07-19 07:44:42 +00:00
setSectorTypes (header.abbreviationsTable, header.objectTable, abbreviationsSector,
2016-11-28 00:45:17 +00:00
abbreviationsNode);
2016-07-19 07:44:42 +00:00
setSectorTypes (header.objectTable, header.globalsOffset, objectsSector, objectNode);
setSectorTypes (header.globalsOffset, header.staticMemory, globalsSector,
2016-11-28 00:45:17 +00:00
globalsNode);
2016-07-19 07:44:42 +00:00
setSectorTypes (header.staticMemory, header.dictionaryOffset, grammarSector,
2016-11-28 00:45:17 +00:00
grammarNode);
2016-07-19 07:44:42 +00:00
setSectorTypes (header.dictionaryOffset, header.highMemory, dictionarySector,
2016-11-28 00:45:17 +00:00
dictionaryNode);
2016-07-19 07:44:42 +00:00
setSectorTypes (header.highMemory, header.stringPointer, codeSector, codeNode);
setSectorTypes (header.stringPointer, header.fileLength, stringsSector, stringsNode);
2016-02-25 07:45:24 +00:00
}
2016-02-29 01:54:44 +00:00
protected void setInfocomSectorTypes ()
2016-02-25 07:45:24 +00:00
{
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;
}
2016-07-19 07:44:42 +00:00
private void setSectorTypes (int sectorFrom, int sectorTo, SectorType type,
DefaultMutableTreeNode node)
2016-02-25 07:45:24 +00:00
{
2016-07-19 07:44:42 +00:00
DefaultAppleFileSource dafs = (DefaultAppleFileSource) node.getUserObject ();
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
2016-02-25 07:45:24 +00:00
int blockNo = sectorFrom / disk.getBlockSize () + 48;
int blockTo = sectorTo / disk.getBlockSize () + 48;
while (blockNo <= blockTo)
{
2016-07-19 07:44:42 +00:00
blocks.add (disk.getDiskAddress (blockNo));
2016-02-25 07:45:24 +00:00
if (!disk.isSectorEmpty (blockNo))
sectorTypes[blockNo] = type;
blockNo++;
}
2016-07-19 07:44:42 +00:00
dafs.setSectors (blocks);
2016-02-25 07:45:24 +00:00
}
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))
{
2016-02-29 01:54:44 +00:00
System.out.println ("Empty : " + da);
2016-02-25 07:45:24 +00:00
buffer = disk.readSector (da.getBlock () - 1);
fileSize = (da.getBlock () - 48) * disk.getBlockSize ();
break;
}
}
2016-03-23 23:37:59 +00:00
if (buffer != null)
{
int ptr = 255;
while (buffer[ptr--] == 0)
fileSize--;
}
2016-02-25 07:45:24 +00:00
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)
{
2016-07-19 07:44:42 +00:00
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, af, this);
// dafs.setSectors (blocks);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
2016-02-25 07:45:24 +00:00
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 (false)
{
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);
2016-11-28 00:45:17 +00:00
JOptionPane.showMessageDialog (null,
"This appears to be an Infocom disk," + " but version " + version
+ " is not supported",
"Unknown disk format", JOptionPane.INFORMATION_MESSAGE);
2016-02-25 07:45:24 +00:00
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 ();
}
}
2015-06-01 09:35:51 +00:00
}