mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-09-30 13:58:30 +00:00
217 lines
4.8 KiB
Java
217 lines
4.8 KiB
Java
|
package com.bytezone.diskbrowser.infocom;
|
||
|
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Collections;
|
||
|
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;
|
||
|
|
||
|
// assign the DICT property for each object
|
||
|
setDictionary ();
|
||
|
|
||
|
// find the point where code ends and strings begin
|
||
|
setStringPointer ();
|
||
|
|
||
|
// add routines called from object properties (requires stringPointer)
|
||
|
createPropertyLinks ();
|
||
|
|
||
|
// assumes that all properties with exactly three bytes are routine addresses
|
||
|
// checkThreeByteProperties ();
|
||
|
}
|
||
|
|
||
|
public void setStringPointer ()
|
||
|
{
|
||
|
PropertyTester pt = new PropertyTester (parent.list);
|
||
|
pt.addTest (new LengthTwoCondition ());
|
||
|
HighMemoryCondition hmc = new HighMemoryCondition ();
|
||
|
pt.addTest (hmc);
|
||
|
pt.doTests ();
|
||
|
|
||
|
System.out.println ("\nSetting the string pointer\n");
|
||
|
|
||
|
for (Integer propertyNo : pt)
|
||
|
// list of all properties that passed all tests
|
||
|
list.add (hmc.statistics[propertyNo]);
|
||
|
Collections.sort (list);
|
||
|
|
||
|
// Calculate lowest string pointer
|
||
|
int lo = list.get (0).lo;
|
||
|
for (Statistics s : list)
|
||
|
{
|
||
|
System.out.println (s);
|
||
|
if (s.hi > lo && s.lo < lo)
|
||
|
lo = s.lo;
|
||
|
if (s.hi < lo)
|
||
|
{
|
||
|
header.stringPointer = lo;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void createPropertyLinks ()
|
||
|
{
|
||
|
int sCount = 0;
|
||
|
int rCount = 0;
|
||
|
int totStrings = 0;
|
||
|
int totRoutines = 0;
|
||
|
|
||
|
for (Statistics s : list)
|
||
|
{
|
||
|
if (header.propertyNames[s.propertyNumber].charAt (0) >= 'a')
|
||
|
continue;
|
||
|
if (s.lo >= header.stringPointer)
|
||
|
{
|
||
|
header.propertyNames[s.propertyNumber] = "STR" + ++sCount;
|
||
|
totStrings += s.offsets.size ();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
header.propertyNames[s.propertyNumber] = "CODE" + ++rCount;
|
||
|
routines.addAll (s.offsets);
|
||
|
totRoutines += s.offsets.size ();
|
||
|
}
|
||
|
}
|
||
|
System.out.println ("Strings found : " + totStrings);
|
||
|
System.out.println ("Routines found : " + totRoutines);
|
||
|
}
|
||
|
|
||
|
public void checkThreeByteProperties ()
|
||
|
{
|
||
|
for (ZObject object : parent.list)
|
||
|
{
|
||
|
for (Property property : object.properties)
|
||
|
{
|
||
|
if (header.propertyNames[property.propertyNumber].charAt (0) < 'a' && property.length == 3)
|
||
|
{
|
||
|
int address = header.getWord (property.ptr + 1) * 2;
|
||
|
System.out.println ("checking " + address);
|
||
|
header.codeManager.addRoutine (address, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// find the property with only dictionary entries
|
||
|
public void setDictionary ()
|
||
|
{
|
||
|
PropertyTester pt = new PropertyTester (parent.list);
|
||
|
pt.addTest (new LengthEvenCondition ());
|
||
|
pt.addTest (new ValidDictionaryCondition ());
|
||
|
pt.doTests ();
|
||
|
|
||
|
for (Integer i : pt)
|
||
|
// should only be one
|
||
|
header.propertyNames[i] = "DICT";
|
||
|
}
|
||
|
|
||
|
class Statistics implements Comparable<Statistics>
|
||
|
{
|
||
|
int propertyNumber;
|
||
|
int lo;
|
||
|
int hi;
|
||
|
List<Integer> offsets = new ArrayList<Integer> ();
|
||
|
|
||
|
public Statistics (int propertyNumber)
|
||
|
{
|
||
|
this.propertyNumber = propertyNumber;
|
||
|
}
|
||
|
|
||
|
public void increment (Property property)
|
||
|
{
|
||
|
offsets.add (property.offset);
|
||
|
if (property.offset > hi)
|
||
|
hi = property.offset;
|
||
|
if (property.offset < lo || lo == 0)
|
||
|
lo = property.offset;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString ()
|
||
|
{
|
||
|
return String.format ("%2d %3d %,7d %,7d", propertyNumber, offsets.size (), lo, hi);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int compareTo (Statistics o)
|
||
|
{
|
||
|
return o.hi - hi;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class LengthTwoCondition extends Condition
|
||
|
{
|
||
|
@Override
|
||
|
boolean test (Property property)
|
||
|
{
|
||
|
return property.length == 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class LengthThreeCondition extends Condition
|
||
|
{
|
||
|
@Override
|
||
|
boolean test (Property property)
|
||
|
{
|
||
|
return property.length == 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class LengthEvenCondition extends Condition
|
||
|
{
|
||
|
@Override
|
||
|
boolean test (Property property)
|
||
|
{
|
||
|
return (property.length % 2) == 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class HighMemoryCondition extends Condition
|
||
|
{
|
||
|
int lo, hi;
|
||
|
Statistics[] statistics = new Statistics[32]; // note there is no property #0
|
||
|
|
||
|
public HighMemoryCondition ()
|
||
|
{
|
||
|
lo = header.highMemory;
|
||
|
hi = header.fileLength;
|
||
|
for (int i = 1; i < statistics.length; i++)
|
||
|
statistics[i] = new Statistics (i);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
boolean test (Property property)
|
||
|
{
|
||
|
statistics[property.propertyNumber].increment (property);
|
||
|
int address = header.getWord (property.ptr + 1) * 2;
|
||
|
return (address >= lo && address < hi) || address == 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class ValidDictionaryCondition extends Condition
|
||
|
{
|
||
|
@Override
|
||
|
boolean test (Property property)
|
||
|
{
|
||
|
for (int i = 1; i <= property.length; i += 2)
|
||
|
{
|
||
|
int address = header.getWord (property.ptr + i);
|
||
|
if (!header.containsWordAt (address))
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|