mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-11-25 16:34:00 +00:00
Wiz 4 maps
This commit is contained in:
parent
2036ca4b96
commit
c0adaef3e2
@ -3,7 +3,6 @@ package com.bytezone.diskbrowser.applefile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bytezone.diskbrowser.applefile.Relocator.MultiDiskAddress;
|
||||
import com.bytezone.diskbrowser.utilities.FileFormatException;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
|
||||
@ -12,8 +11,9 @@ public class PascalSegment extends AbstractFile implements PascalConstants
|
||||
private final static int BLOCK_SIZE = 512;
|
||||
final int segmentNoHeader;
|
||||
private int segmentNoBody;
|
||||
private final int blockOffset;
|
||||
// private final int blockOffset;
|
||||
// private final Relocator relocator;
|
||||
boolean debug = false;
|
||||
|
||||
public int blockNo;
|
||||
// public int newBlockNo;
|
||||
@ -28,14 +28,14 @@ public class PascalSegment extends AbstractFile implements PascalConstants
|
||||
private final int slot;
|
||||
private int totalProcedures;
|
||||
private List<PascalProcedure> procedures;
|
||||
private List<MultiDiskAddress> addresses;
|
||||
// private List<MultiDiskAddress> addresses;
|
||||
|
||||
public PascalSegment (String name, byte[] fullBuffer, int seq, int blockOffset)
|
||||
{
|
||||
super (name, fullBuffer); // sets this.buffer to the full buffer temporarily
|
||||
|
||||
this.slot = seq;
|
||||
this.blockOffset = blockOffset;
|
||||
// this.blockOffset = blockOffset;
|
||||
// this.relocator = relocator;
|
||||
|
||||
this.blockNo = HexFormatter.intValue (fullBuffer[seq * 4], fullBuffer[seq * 4 + 1]);
|
||||
@ -89,18 +89,19 @@ public class PascalSegment extends AbstractFile implements PascalConstants
|
||||
{
|
||||
buffer = new byte[0];
|
||||
}
|
||||
else if (offset < fullBuffer.length)
|
||||
else if ((offset + size) < fullBuffer.length)
|
||||
{
|
||||
buffer = new byte[size]; // replaces this.buffer with the segment buffer only
|
||||
System.arraycopy (fullBuffer, offset, buffer, 0, size);
|
||||
totalProcedures = buffer[size - 1] & 0xFF;
|
||||
segmentNoBody = buffer[size - 2] & 0xFF;
|
||||
|
||||
if (segmentNoHeader == 0)
|
||||
System.out.printf ("Zero segment header in %s seq %d%n", name, seq);
|
||||
else if (segmentNoBody != segmentNoHeader)
|
||||
System.out.println (
|
||||
"Segment number mismatch : " + segmentNoBody + " / " + segmentNoHeader);
|
||||
if (debug)
|
||||
if (segmentNoHeader == 0)
|
||||
System.out.printf ("Zero segment header in %s seq %d%n", name, seq);
|
||||
else if (segmentNoBody != segmentNoHeader)
|
||||
System.out.println (
|
||||
"Segment number mismatch : " + segmentNoBody + " / " + segmentNoHeader);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -108,10 +109,10 @@ public class PascalSegment extends AbstractFile implements PascalConstants
|
||||
}
|
||||
}
|
||||
|
||||
void setMultiDiskAddresses (List<MultiDiskAddress> addresses)
|
||||
{
|
||||
this.addresses = addresses;
|
||||
}
|
||||
// void setMultiDiskAddresses (List<MultiDiskAddress> addresses)
|
||||
// {
|
||||
// this.addresses = addresses;
|
||||
// }
|
||||
|
||||
private void buildProcedureList ()
|
||||
{
|
||||
|
@ -1,364 +0,0 @@
|
||||
package com.bytezone.diskbrowser.applefile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.bytezone.diskbrowser.disk.AppleDisk;
|
||||
import com.bytezone.diskbrowser.disk.Disk;
|
||||
import com.bytezone.diskbrowser.disk.DiskAddress;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
|
||||
public class Relocator extends AbstractFile
|
||||
{
|
||||
private final int checkByte;
|
||||
private final List<DiskRecord> diskRecords = new ArrayList<DiskRecord> ();
|
||||
private final List<MultiDiskAddress> addresses = new ArrayList<MultiDiskAddress> ();
|
||||
|
||||
private final List<MultiDiskAddress> newAddresses = new ArrayList<MultiDiskAddress> ();
|
||||
private final List<MultiDiskAddress> oldAddresses = new ArrayList<MultiDiskAddress> ();
|
||||
|
||||
private final List<MultiDiskAddress> logicalAddresses =
|
||||
new ArrayList<MultiDiskAddress> ();
|
||||
|
||||
private final byte[] diskBlocks = new byte[0x800];
|
||||
private final int[] diskOffsets = new int[0x800];
|
||||
private final int[] diskOffsets2 = new int[0x800];
|
||||
private final Disk[] dataDisks = new Disk[5];
|
||||
|
||||
public Relocator (String name, byte[] buffer)
|
||||
{
|
||||
super (name, buffer);
|
||||
|
||||
checkByte = HexFormatter.intValue (buffer[0], buffer[1]);
|
||||
|
||||
int ptr = 2; // skip checkByte
|
||||
|
||||
while (buffer[ptr] != 0)
|
||||
{
|
||||
DiskRecord diskRecord = new DiskRecord (buffer, ptr);
|
||||
diskRecords.add (diskRecord);
|
||||
ptr += diskRecord.size ();
|
||||
}
|
||||
|
||||
logicalAddresses.add (new MultiDiskAddress (0, 0, 0, 0x800));
|
||||
|
||||
for (DiskRecord diskRecord : diskRecords)
|
||||
for (DiskSegment diskSegment : diskRecord.diskSegments)
|
||||
{
|
||||
addresses
|
||||
.add (new MultiDiskAddress (diskRecord.diskNumber, diskSegment.logicalBlock,
|
||||
diskSegment.physicalBlock, diskSegment.segmentLength));
|
||||
addLogicalBlock ((byte) diskRecord.diskNumber, diskSegment);
|
||||
}
|
||||
|
||||
getMultiDiskAddress ("BOOT", 0, 2);
|
||||
getMultiDiskAddress ("CATALOG", 2, 4);
|
||||
}
|
||||
|
||||
public void list ()
|
||||
{
|
||||
for (MultiDiskAddress multiDiskAddress : addresses)
|
||||
System.out.printf ("%d %03X %03X %03X %s%n", multiDiskAddress.diskNumber,
|
||||
multiDiskAddress.logicalBlockNumber, multiDiskAddress.physicalBlockNumber,
|
||||
multiDiskAddress.totalBlocks, multiDiskAddress.name);
|
||||
}
|
||||
|
||||
private void addLogicalBlock (byte disk, DiskSegment diskSegment)
|
||||
{
|
||||
int lo = diskSegment.logicalBlock;
|
||||
int hi = diskSegment.logicalBlock + diskSegment.segmentLength;
|
||||
int count = 0;
|
||||
for (int i = lo; i < hi; i++)
|
||||
if (diskBlocks[i] == 0)
|
||||
{
|
||||
diskBlocks[i] = disk;
|
||||
diskOffsets[i] = diskSegment.physicalBlock;
|
||||
diskOffsets2[i] = diskSegment.physicalBlock + count++;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getLogicalBuffer (DiskAddress da)
|
||||
{
|
||||
int block = da.getBlock ();
|
||||
System.out.println (diskBlocks[block]);
|
||||
Disk disk = dataDisks[diskBlocks[block] - 1];
|
||||
System.out.println (diskOffsets2[block]);
|
||||
System.out.println (disk);
|
||||
return disk.readSector (diskOffsets2[block]);
|
||||
}
|
||||
|
||||
public List<MultiDiskAddress> getMultiDiskAddress (String name, int blockNumber,
|
||||
int length)
|
||||
{
|
||||
List<MultiDiskAddress> foundAddresses = new ArrayList<MultiDiskAddress> ();
|
||||
newAddresses.clear ();
|
||||
oldAddresses.clear ();
|
||||
// System.out.printf ("%04X %04X %s%n", blockNumber, length, name);
|
||||
|
||||
for (MultiDiskAddress multiDiskAddress : addresses)
|
||||
{
|
||||
if (multiDiskAddress.logicalBlockNumber == blockNumber)
|
||||
{
|
||||
if (multiDiskAddress.totalBlocks == length)
|
||||
{
|
||||
foundAddresses.add (multiDiskAddress);
|
||||
if (multiDiskAddress.name.isEmpty ())
|
||||
multiDiskAddress.name = name;
|
||||
}
|
||||
else if (multiDiskAddress.totalBlocks > length)
|
||||
{
|
||||
MultiDiskAddress newAddress1 = new MultiDiskAddress (
|
||||
multiDiskAddress.diskNumber, multiDiskAddress.logicalBlockNumber,
|
||||
multiDiskAddress.physicalBlockNumber, length, name);
|
||||
MultiDiskAddress newAddress2 = new MultiDiskAddress (
|
||||
multiDiskAddress.diskNumber, multiDiskAddress.logicalBlockNumber + length,
|
||||
multiDiskAddress.physicalBlockNumber + length,
|
||||
multiDiskAddress.totalBlocks - length);
|
||||
oldAddresses.add (multiDiskAddress);
|
||||
newAddresses.add (newAddress1);
|
||||
newAddresses.add (newAddress2);
|
||||
foundAddresses.add (newAddress1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newAddresses.size () > 0)
|
||||
{
|
||||
addresses.addAll (newAddresses);
|
||||
addresses.removeAll (oldAddresses);
|
||||
Collections.sort (addresses);
|
||||
}
|
||||
|
||||
return foundAddresses;
|
||||
}
|
||||
|
||||
public void setDisks (Disk[] disks)
|
||||
{
|
||||
for (Disk disk : disks)
|
||||
{
|
||||
byte[] buffer = disk.readSector (1);
|
||||
int diskNo = buffer[510] & 0xFF;
|
||||
if (diskNo > 0 && diskNo <= 5)
|
||||
dataDisks[diskNo - 1] = disk;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasData ()
|
||||
{
|
||||
for (Disk disk : dataDisks)
|
||||
if (disk == null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void createNewBuffer (Disk[] dataDisks)
|
||||
{
|
||||
AppleDisk master = (AppleDisk) dataDisks[0];
|
||||
|
||||
for (int logicalBlock = 0; logicalBlock < diskBlocks.length; logicalBlock++)
|
||||
{
|
||||
int physicalBlock = diskOffsets2[logicalBlock];
|
||||
int diskNo = diskBlocks[logicalBlock];
|
||||
if (diskNo > 0)
|
||||
{
|
||||
Disk disk = dataDisks[diskNo];
|
||||
byte[] temp = disk.readSector (physicalBlock);
|
||||
DiskAddress da = master.getDiskAddress (logicalBlock);
|
||||
master.writeSector (da, temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText ()
|
||||
{
|
||||
StringBuilder text = new StringBuilder ();
|
||||
|
||||
text.append ("Pascal Relocator\n\n");
|
||||
text.append (String.format ("Check byte..... %04X%n%n", checkByte));
|
||||
|
||||
for (DiskRecord diskRecord : diskRecords)
|
||||
{
|
||||
text.append (diskRecord);
|
||||
text.append ("\n");
|
||||
}
|
||||
|
||||
if (false)
|
||||
{
|
||||
int previousDiskNumber = 0;
|
||||
for (MultiDiskAddress multiDiskAddress : addresses)
|
||||
{
|
||||
if (multiDiskAddress.diskNumber != previousDiskNumber)
|
||||
{
|
||||
previousDiskNumber = multiDiskAddress.diskNumber;
|
||||
text.append ("\n");
|
||||
text.append ("Disk Logical Physical Size Name\n");
|
||||
text.append ("---- ------- -------- ---- -------------\n");
|
||||
}
|
||||
text.append (String.format (" %d %03X %03X %03X %s%n",
|
||||
multiDiskAddress.diskNumber, multiDiskAddress.logicalBlockNumber,
|
||||
multiDiskAddress.physicalBlockNumber, multiDiskAddress.totalBlocks,
|
||||
multiDiskAddress.name));
|
||||
}
|
||||
}
|
||||
|
||||
text.append ("\n Logical Size Disk Physical");
|
||||
text.append ("\n--------- ---- ---- ---------\n");
|
||||
|
||||
int first = 0;
|
||||
int lastDisk = diskBlocks[0];
|
||||
int lastOffset = diskOffsets[0];
|
||||
for (int i = 0; i < diskBlocks.length; i++)
|
||||
{
|
||||
if (diskBlocks[i] != lastDisk || diskOffsets[i] != lastOffset)
|
||||
{
|
||||
int size = i - first;
|
||||
if (lastDisk > 0)
|
||||
text.append (String.format ("%03X - %03X %03X %d %03X - %03X%n", first,
|
||||
i - 1, size, lastDisk, lastOffset, lastOffset + size - 1));
|
||||
else
|
||||
text.append (String.format ("%03X - %03X %03X%n", first, i - 1, size));
|
||||
first = i;
|
||||
lastDisk = diskBlocks[i];
|
||||
lastOffset = diskOffsets[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (lastDisk > 0)
|
||||
{
|
||||
int max = diskBlocks.length;
|
||||
int size = max - first;
|
||||
text.append (String.format ("%03X - %03X %03X %d %03X - %03X%n", first,
|
||||
max - 1, size, lastDisk, lastOffset, lastOffset + size - 1));
|
||||
}
|
||||
|
||||
return text.toString ();
|
||||
}
|
||||
|
||||
private class DiskRecord
|
||||
{
|
||||
int diskNumber;
|
||||
int totDiskSegments;
|
||||
List<DiskSegment> diskSegments = new ArrayList<DiskSegment> ();
|
||||
|
||||
public DiskRecord (byte[] buffer, int ptr)
|
||||
{
|
||||
diskNumber = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]);
|
||||
totDiskSegments = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 4]);
|
||||
|
||||
ptr += 4;
|
||||
for (int i = 0; i < totDiskSegments; i++)
|
||||
{
|
||||
diskSegments.add (new DiskSegment (buffer, ptr));
|
||||
ptr += 6;
|
||||
}
|
||||
}
|
||||
|
||||
int size ()
|
||||
{
|
||||
return 4 + diskSegments.size () * 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder text = new StringBuilder ();
|
||||
|
||||
text.append (String.format ("Disk number.... %04X%n", diskNumber));
|
||||
text.append (String.format ("Segments....... %04X%n%n", totDiskSegments));
|
||||
text.append (String.format (" Seg Skip Size Logical Physical%n"));
|
||||
text.append (String.format (" --- ---- ---- ----------- -----------%n"));
|
||||
|
||||
int count = 1;
|
||||
int last = 0;
|
||||
int size = 0;
|
||||
|
||||
for (DiskSegment segment : diskSegments)
|
||||
{
|
||||
if (segment.logicalBlock > last)
|
||||
{
|
||||
int end = segment.logicalBlock - 1;
|
||||
size = end - last + 1;
|
||||
}
|
||||
last = segment.logicalBlock + segment.segmentLength;
|
||||
text.append (
|
||||
String.format (" %02X %04X %s %n", count++, size, segment.toString ()));
|
||||
}
|
||||
|
||||
return text.toString ();
|
||||
}
|
||||
}
|
||||
|
||||
private class DiskSegment
|
||||
{
|
||||
int logicalBlock;
|
||||
int physicalBlock;
|
||||
int segmentLength;
|
||||
|
||||
public DiskSegment (byte[] buffer, int ptr)
|
||||
{
|
||||
logicalBlock = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]);
|
||||
physicalBlock = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]);
|
||||
segmentLength = HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return String.format (" %04X %04X - %04X %04X - %04X", segmentLength,
|
||||
logicalBlock, (logicalBlock + segmentLength - 1), physicalBlock,
|
||||
(physicalBlock + segmentLength - 1));
|
||||
}
|
||||
|
||||
// public String toString (int offset)
|
||||
// {
|
||||
// int logical = logicalBlock - offset;
|
||||
// int physical = physicalBlock - offset;
|
||||
// if (physical >= 0)
|
||||
// return String.format (" %04X %04X %04X %04X %04X",
|
||||
// logicalBlock, physicalBlock, segmentLength, logical, physical);
|
||||
// return String.format (" %04X %04X %04X", logicalBlock, physicalBlock,
|
||||
// segmentLength);
|
||||
// }
|
||||
}
|
||||
|
||||
class MultiDiskAddress implements Comparable<MultiDiskAddress>
|
||||
{
|
||||
int diskNumber;
|
||||
int logicalBlockNumber;
|
||||
int physicalBlockNumber;
|
||||
int totalBlocks;
|
||||
String name = "";
|
||||
|
||||
public MultiDiskAddress (int diskNumber, int logicalBlockNumber,
|
||||
int physicalBlockNumber, int totalBlocks)
|
||||
{
|
||||
this.diskNumber = diskNumber;
|
||||
this.logicalBlockNumber = logicalBlockNumber;
|
||||
this.physicalBlockNumber = physicalBlockNumber;
|
||||
this.totalBlocks = totalBlocks;
|
||||
}
|
||||
|
||||
public MultiDiskAddress (int diskNumber, int logicalBlockNumber,
|
||||
int physicalBlockNumber, int totalBlocks, String name)
|
||||
{
|
||||
this (diskNumber, logicalBlockNumber, physicalBlockNumber, totalBlocks);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return String.format ("%d:%03X", diskNumber, physicalBlockNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo (MultiDiskAddress o)
|
||||
{
|
||||
if (this.diskNumber == o.diskNumber)
|
||||
return this.logicalBlockNumber - o.logicalBlockNumber;
|
||||
return this.diskNumber - o.diskNumber;
|
||||
}
|
||||
}
|
||||
}
|
@ -388,34 +388,35 @@ public class DiskFactory
|
||||
if (debug)
|
||||
System.out.println ("Not a Wizardry 1-3 disk");
|
||||
|
||||
if (Wizardry4BootDisk.isWizardryIV (disk, debug))
|
||||
// check for compressed disk
|
||||
if (file.getName ().endsWith (".tmp"))
|
||||
return new PascalDisk (disk); // complicated joining up compressed disks
|
||||
|
||||
if (Wizardry4BootDisk.isWizardryIVorV (disk, debug))
|
||||
{
|
||||
// collect 4 extra data disks
|
||||
AppleDisk[] disks = new AppleDisk[6];
|
||||
String fileName = file.getAbsolutePath ().toLowerCase ();
|
||||
int pos = file.getAbsolutePath ().indexOf ('.');
|
||||
char c = fileName.charAt (pos - 1);
|
||||
String suffix = fileName.substring (pos + 1);
|
||||
int requiredDisks = c == '1' ? 6 : c == 'a' ? 10 : 0;
|
||||
|
||||
disks[0] = new AppleDisk (file, 256, 8); // will become a PascalDisk
|
||||
disks[1] = new AppleDisk (file, 256, 8); // will remain a DataDisk
|
||||
disks[0].setInterleave (1);
|
||||
disks[1].setInterleave (1);
|
||||
|
||||
for (int i = 2; i < disks.length; i++)
|
||||
if (requiredDisks > 0)
|
||||
{
|
||||
String filename = file.getAbsolutePath ().replace ("1.dsk", i + ".dsk");
|
||||
File f = new File (filename);
|
||||
if (f.exists () && f.isFile ())
|
||||
// collect extra data disks
|
||||
AppleDisk[] disks = new AppleDisk[requiredDisks];
|
||||
|
||||
disks[0] = new AppleDisk (file, 256, 8); // will become a PascalDisk
|
||||
disks[0].setInterleave (1);
|
||||
|
||||
disks[1] = new AppleDisk (file, 256, 8); // will remain a DataDisk
|
||||
disks[1].setInterleave (1);
|
||||
|
||||
if (pos > 0 && requiredDisks > 0)
|
||||
{
|
||||
AppleDisk dataDisk = new AppleDisk (f, 35, 8);
|
||||
dataDisk.setInterleave (1);
|
||||
disks[i] = dataDisk;
|
||||
}
|
||||
else
|
||||
{
|
||||
PascalDisk pascalDisk = new PascalDisk (disk);
|
||||
return pascalDisk;
|
||||
if (collectDataDisks (file.getAbsolutePath (), pos, disks))
|
||||
return new Wizardry4BootDisk (disks);
|
||||
}
|
||||
}
|
||||
Wizardry4BootDisk wiz4 = new Wizardry4BootDisk (disks);
|
||||
return wiz4;
|
||||
}
|
||||
if (debug)
|
||||
System.out.println ("Not a Wizardry IV disk");
|
||||
@ -424,6 +425,29 @@ public class DiskFactory
|
||||
return pascalDisk;
|
||||
}
|
||||
|
||||
private static boolean collectDataDisks (String fileName, int dotPos, AppleDisk[] disks)
|
||||
{
|
||||
char c = fileName.charAt (dotPos - 1);
|
||||
String suffix = fileName.substring (dotPos + 1);
|
||||
|
||||
for (int i = 2; i < disks.length; i++)
|
||||
{
|
||||
String old = new String (c + "." + suffix);
|
||||
String rep = new String ((char) (c + i - 1) + "." + suffix);
|
||||
// System.out.printf ("[%s] [%s]%n", old, rep);
|
||||
File f = new File (fileName.replace (old, rep));
|
||||
// System.out.println (f);
|
||||
if (!f.exists () || !f.isFile ())
|
||||
return false;
|
||||
|
||||
AppleDisk dataDisk = new AppleDisk (f, 35, 8);
|
||||
dataDisk.setInterleave (1);
|
||||
disks[i] = dataDisk;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static InfocomDisk checkInfocomDisk (File file)
|
||||
{
|
||||
if (debug)
|
||||
|
@ -13,15 +13,15 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
|
||||
abstract class CatalogEntry implements AppleFileSource
|
||||
{
|
||||
protected AbstractFile file;
|
||||
protected final PascalDisk parent;
|
||||
protected final String name;
|
||||
int firstBlock;
|
||||
int lastBlock; // block AFTER last used block
|
||||
int fileType;
|
||||
GregorianCalendar date;
|
||||
int bytesUsedInLastBlock;
|
||||
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
||||
AbstractFile file;
|
||||
protected String name;
|
||||
protected int firstBlock;
|
||||
protected int lastBlock; // block AFTER last used block
|
||||
protected int fileType;
|
||||
protected GregorianCalendar date;
|
||||
protected int bytesUsedInLastBlock;
|
||||
protected final List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
||||
|
||||
public CatalogEntry (PascalDisk parent, byte[] buffer)
|
||||
{
|
||||
@ -34,7 +34,8 @@ abstract class CatalogEntry implements AppleFileSource
|
||||
bytesUsedInLastBlock = HexFormatter.intValue (buffer[16], buffer[17]);
|
||||
|
||||
Disk disk = parent.getDisk ();
|
||||
for (int i = firstBlock; i < lastBlock; i++)
|
||||
int max = Math.min (lastBlock, disk.getTotalBlocks ());
|
||||
for (int i = firstBlock; i < max; i++)
|
||||
blocks.add (disk.getDiskAddress (i));
|
||||
}
|
||||
|
||||
@ -47,13 +48,6 @@ abstract class CatalogEntry implements AppleFileSource
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
int size = lastBlock - firstBlock;
|
||||
return String.format ("%03d %s %-15s", size, parent.fileTypes[fileType], name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DiskAddress> getSectors ()
|
||||
{
|
||||
@ -72,4 +66,11 @@ abstract class CatalogEntry implements AppleFileSource
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
int size = lastBlock - firstBlock;
|
||||
return String.format ("%03d %s %-15s", size, parent.fileTypes[fileType], name);
|
||||
}
|
||||
}
|
@ -8,9 +8,7 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
|
||||
public class FileEntry extends CatalogEntry
|
||||
{
|
||||
int bytesUsedInLastBlock;
|
||||
private DefaultMutableTreeNode node;
|
||||
AbstractFile file;
|
||||
|
||||
public FileEntry (PascalDisk parent, byte[] buffer)
|
||||
{
|
||||
@ -19,7 +17,8 @@ public class FileEntry extends CatalogEntry
|
||||
bytesUsedInLastBlock = HexFormatter.intValue (buffer[22], buffer[23]);
|
||||
date = HexFormatter.getPascalDate (buffer, 24);
|
||||
|
||||
for (int i = firstBlock; i < lastBlock; i++)
|
||||
int max = Math.min (lastBlock, parent.getDisk ().getTotalBlocks ());
|
||||
for (int i = firstBlock; i < max; i++)
|
||||
{
|
||||
switch (fileType)
|
||||
{
|
||||
|
@ -10,10 +10,10 @@ import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
import com.bytezone.diskbrowser.applefile.AppleFileSource;
|
||||
import com.bytezone.diskbrowser.applefile.BootSector;
|
||||
import com.bytezone.diskbrowser.applefile.Relocator;
|
||||
import com.bytezone.diskbrowser.disk.*;
|
||||
import com.bytezone.diskbrowser.gui.DataSource;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
import com.bytezone.diskbrowser.wizardry.Relocator;
|
||||
|
||||
public class PascalDisk extends AbstractFormattedDisk
|
||||
{
|
||||
@ -52,12 +52,6 @@ public class PascalDisk extends AbstractFormattedDisk
|
||||
List<DiskAddress> blocks = disk.getDiskAddressList (0, 1); // B0, B1
|
||||
this.bootSector = new BootSector (disk, disk.readSectors (blocks), "Pascal");
|
||||
|
||||
byte[] buffer = disk.readSector (2);
|
||||
byte[] data = new byte[CATALOG_ENTRY_SIZE];
|
||||
System.arraycopy (buffer, 0, data, 0, CATALOG_ENTRY_SIZE);
|
||||
|
||||
volumeEntry = new VolumeEntry (this, data);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (!disk.isSectorEmpty (i))
|
||||
{
|
||||
@ -68,8 +62,18 @@ public class PascalDisk extends AbstractFormattedDisk
|
||||
for (int i = 2; i < disk.getTotalBlocks (); i++)
|
||||
freeBlocks.set (i, true);
|
||||
|
||||
byte[] buffer = disk.readSector (2);
|
||||
byte[] data = new byte[CATALOG_ENTRY_SIZE];
|
||||
System.arraycopy (buffer, 0, data, 0, CATALOG_ENTRY_SIZE);
|
||||
volumeEntry = new VolumeEntry (this, data);
|
||||
|
||||
DefaultMutableTreeNode root = getCatalogTreeRoot ();
|
||||
DefaultMutableTreeNode volumeNode = new DefaultMutableTreeNode (volumeEntry);
|
||||
root.add (volumeNode);
|
||||
|
||||
List<DiskAddress> sectors = new ArrayList<DiskAddress> ();
|
||||
for (int i = 2; i < volumeEntry.lastBlock; i++)
|
||||
int max = Math.min (volumeEntry.lastBlock, disk.getTotalBlocks ());
|
||||
for (int i = 2; i < max; i++)
|
||||
{
|
||||
DiskAddress da = disk.getDiskAddress (i);
|
||||
if (!disk.isSectorEmpty (da))
|
||||
@ -81,13 +85,9 @@ public class PascalDisk extends AbstractFormattedDisk
|
||||
diskCatalogSector =
|
||||
new PascalCatalogSector (disk, disk.readSectors (sectors), sectors);
|
||||
|
||||
DefaultMutableTreeNode root = getCatalogTreeRoot ();
|
||||
DefaultMutableTreeNode volumeNode = new DefaultMutableTreeNode (volumeEntry);
|
||||
root.add (volumeNode);
|
||||
|
||||
// read the catalog
|
||||
List<DiskAddress> addresses = new ArrayList<DiskAddress> ();
|
||||
for (int i = 2; i < volumeEntry.lastBlock; i++)
|
||||
for (int i = 2; i < max; i++)
|
||||
addresses.add (disk.getDiskAddress (i));
|
||||
buffer = disk.readSectors (addresses);
|
||||
|
||||
@ -96,9 +96,9 @@ public class PascalDisk extends AbstractFormattedDisk
|
||||
{
|
||||
int ptr = i * CATALOG_ENTRY_SIZE;
|
||||
data = new byte[CATALOG_ENTRY_SIZE];
|
||||
|
||||
System.arraycopy (buffer, ptr, data, 0, CATALOG_ENTRY_SIZE);
|
||||
FileEntry fileEntry = new FileEntry (this, data);
|
||||
|
||||
fileEntries.add (fileEntry);
|
||||
DefaultMutableTreeNode node = new DefaultMutableTreeNode (fileEntry);
|
||||
fileEntry.setNode (node);
|
||||
@ -106,7 +106,7 @@ public class PascalDisk extends AbstractFormattedDisk
|
||||
if (fileEntry.fileType == 2)
|
||||
{
|
||||
node.setAllowsChildren (true);
|
||||
fileEntry.getDataSource ();
|
||||
fileEntry.getDataSource (); // build segments
|
||||
}
|
||||
else
|
||||
node.setAllowsChildren (false);
|
||||
|
@ -8,37 +8,14 @@ class VolumeEntry extends CatalogEntry
|
||||
{
|
||||
final int totalFiles;
|
||||
final int totalBlocks;
|
||||
final int block1; // first block on the disk (usually 0)
|
||||
final int lastDirectoryBlock; // (plus 1) (usually 6)
|
||||
final int recordType; // 0 = directory
|
||||
final int nameLength;
|
||||
final String name;
|
||||
|
||||
public VolumeEntry (PascalDisk parent, byte[] buffer)
|
||||
{
|
||||
super (parent, buffer);
|
||||
|
||||
block1 = HexFormatter.intValue (buffer[0], buffer[1]); // 0
|
||||
lastDirectoryBlock = HexFormatter.intValue (buffer[2], buffer[3]); // 6
|
||||
recordType = HexFormatter.intValue (buffer[4], buffer[5]); // 0
|
||||
nameLength = buffer[6] & 0xFF;
|
||||
name = HexFormatter.getPascalString (buffer, 6); // 06-0D
|
||||
totalBlocks = HexFormatter.intValue (buffer[14], buffer[15]); // 280
|
||||
totalFiles = HexFormatter.intValue (buffer[16], buffer[17]);
|
||||
firstBlock = HexFormatter.intValue (buffer[18], buffer[19]); // 0
|
||||
date = HexFormatter.getPascalDate (buffer, 20); // 2 bytes
|
||||
// bytes 0x16 - 0x19 are unused
|
||||
|
||||
if (false)
|
||||
{
|
||||
System.out.printf ("Total files ..... %d%n", totalFiles);
|
||||
System.out.printf ("Total blocks .... %d%n", totalBlocks);
|
||||
System.out.printf ("Block1 .......... %d%n", block1);
|
||||
System.out.printf ("Last block ...... %d%n", lastDirectoryBlock);
|
||||
System.out.printf ("Record type ..... %d%n", recordType);
|
||||
System.out.printf ("Name length ..... %d%n", nameLength);
|
||||
System.out.printf ("Name ............ %s%n", name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,206 +11,212 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
|
||||
class MazeLevel extends AbstractFile
|
||||
{
|
||||
public int level;
|
||||
private List<Message> messages;
|
||||
private List<Monster> monsters;
|
||||
private List<Item> items;
|
||||
public final int level;
|
||||
private List<Message> messages;
|
||||
private List<Monster> monsters;
|
||||
private List<Item> items;
|
||||
|
||||
public MazeLevel (byte[] buffer, int level)
|
||||
{
|
||||
super ("Level " + level, buffer);
|
||||
this.level = level;
|
||||
}
|
||||
public MazeLevel (byte[] buffer, int level)
|
||||
{
|
||||
super ("Level " + level, buffer);
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getImage ()
|
||||
{
|
||||
Dimension cellSize = new Dimension (22, 22);
|
||||
image =
|
||||
new BufferedImage (20 * cellSize.width + 1, 20 * cellSize.height + 1,
|
||||
BufferedImage.TYPE_USHORT_555_RGB);
|
||||
Graphics2D g = image.createGraphics ();
|
||||
g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
@Override
|
||||
public BufferedImage getImage ()
|
||||
{
|
||||
Dimension cellSize = new Dimension (22, 22);
|
||||
image = new BufferedImage (20 * cellSize.width + 1, 20 * cellSize.height + 1,
|
||||
BufferedImage.TYPE_USHORT_555_RGB);
|
||||
Graphics2D g = image.createGraphics ();
|
||||
g.setRenderingHint (RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
for (int row = 0; row < 20; row++)
|
||||
for (int column = 0; column < 20; column++)
|
||||
{
|
||||
MazeCell cell = getLocation ((row) % 20, (column) % 20);
|
||||
int x = column * cellSize.width;
|
||||
int y = image.getHeight () - (row + 1) * cellSize.height - 1;
|
||||
cell.draw (g, x, y);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
for (int row = 0; row < 20; row++)
|
||||
for (int column = 0; column < 20; column++)
|
||||
{
|
||||
MazeCell cell = getLocation (row, column);
|
||||
int x = column * cellSize.width;
|
||||
int y = image.getHeight () - (row + 1) * cellSize.height - 1;
|
||||
cell.draw (g, x, y);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setMessages (List<Message> messages)
|
||||
{
|
||||
this.messages = messages;
|
||||
}
|
||||
public void setMessages (List<Message> messages)
|
||||
{
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
public void setMonsters (List<Monster> monsters)
|
||||
{
|
||||
this.monsters = monsters;
|
||||
}
|
||||
public void setMonsters (List<Monster> monsters)
|
||||
{
|
||||
this.monsters = monsters;
|
||||
}
|
||||
|
||||
public void setItems (List<Item> items)
|
||||
{
|
||||
this.items = items;
|
||||
}
|
||||
public void setItems (List<Item> items)
|
||||
{
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public MazeCell getLocation (int row, int column)
|
||||
{
|
||||
MazeAddress address = new MazeAddress (level, row, column);
|
||||
MazeCell cell = new MazeCell (address);
|
||||
public MazeCell getLocation (int row, int column)
|
||||
{
|
||||
MazeAddress address = new MazeAddress (level, row, column);
|
||||
MazeCell cell = new MazeCell (address);
|
||||
|
||||
// doors and walls
|
||||
// doors and walls
|
||||
|
||||
int offset = column * 6 + row / 4; // 6 bytes/column
|
||||
int offset = column * 6 + row / 4; // 6 bytes/column
|
||||
|
||||
int value = HexFormatter.intValue (buffer[offset]);
|
||||
value >>>= (row % 4) * 2;
|
||||
cell.westWall = ((value & 1) == 1);
|
||||
value >>>= 1;
|
||||
cell.westDoor = ((value & 1) == 1);
|
||||
int value = HexFormatter.intValue (buffer[offset]);
|
||||
value >>>= (row % 4) * 2;
|
||||
cell.westWall = ((value & 1) == 1);
|
||||
value >>>= 1;
|
||||
cell.westDoor = ((value & 1) == 1);
|
||||
|
||||
value = HexFormatter.intValue (buffer[offset + 120]);
|
||||
value >>>= (row % 4) * 2;
|
||||
cell.southWall = ((value & 1) == 1);
|
||||
value >>>= 1;
|
||||
cell.southDoor = ((value & 1) == 1);
|
||||
value = HexFormatter.intValue (buffer[offset + 120]);
|
||||
value >>>= (row % 4) * 2;
|
||||
cell.southWall = ((value & 1) == 1);
|
||||
value >>>= 1;
|
||||
cell.southDoor = ((value & 1) == 1);
|
||||
|
||||
value = HexFormatter.intValue (buffer[offset + 240]);
|
||||
value >>>= (row % 4) * 2;
|
||||
cell.eastWall = ((value & 1) == 1);
|
||||
value >>>= 1;
|
||||
cell.eastDoor = ((value & 1) == 1);
|
||||
value = HexFormatter.intValue (buffer[offset + 240]);
|
||||
value >>>= (row % 4) * 2;
|
||||
cell.eastWall = ((value & 1) == 1);
|
||||
value >>>= 1;
|
||||
cell.eastDoor = ((value & 1) == 1);
|
||||
|
||||
value = HexFormatter.intValue (buffer[offset + 360]);
|
||||
value >>>= (row % 4) * 2;
|
||||
cell.northWall = ((value & 1) == 1);
|
||||
value >>>= 1;
|
||||
cell.northDoor = ((value & 1) == 1);
|
||||
value = HexFormatter.intValue (buffer[offset + 360]);
|
||||
value >>>= (row % 4) * 2;
|
||||
cell.northWall = ((value & 1) == 1);
|
||||
value >>>= 1;
|
||||
cell.northDoor = ((value & 1) == 1);
|
||||
|
||||
// monster table
|
||||
// monster table
|
||||
|
||||
offset = column * 4 + row / 8; // 4 bytes/column, 1 bit/row
|
||||
value = HexFormatter.intValue (buffer[offset + 480]);
|
||||
value >>>= row % 8;
|
||||
cell.monsterLair = ((value & 1) == 1);
|
||||
offset = column * 4 + row / 8; // 4 bytes/column, 1 bit/row
|
||||
value = HexFormatter.intValue (buffer[offset + 480]);
|
||||
value >>>= row % 8;
|
||||
cell.monsterLair = ((value & 1) == 1);
|
||||
|
||||
// stairs, pits, darkness etc.
|
||||
// stairs, pits, darkness etc.
|
||||
|
||||
offset = column * 10 + row / 2; // 10 bytes/column, 4 bits/row
|
||||
value = HexFormatter.intValue (buffer[offset + 560]);
|
||||
int b = (row % 2 == 0) ? value % 16 : value / 16;
|
||||
int c = HexFormatter.intValue (buffer[760 + b / 2]);
|
||||
int d = (b % 2 == 0) ? c % 16 : c / 16;
|
||||
offset = column * 10 + row / 2; // 10 bytes/column, 4 bits/row
|
||||
value = HexFormatter.intValue (buffer[offset + 560]);
|
||||
int b = (row % 2 == 0) ? value % 16 : value / 16;
|
||||
int c = HexFormatter.intValue (buffer[760 + b / 2]);
|
||||
int d = (b % 2 == 0) ? c % 16 : c / 16;
|
||||
|
||||
switch (d)
|
||||
{
|
||||
case 1:
|
||||
cell.stairs = true;
|
||||
cell.addressTo = getAddress (b);
|
||||
break;
|
||||
case 2:
|
||||
cell.pit = true;
|
||||
break;
|
||||
case 3:
|
||||
cell.chute = true;
|
||||
cell.addressTo = getAddress (b);
|
||||
break;
|
||||
case 4:
|
||||
cell.spinner = true;
|
||||
break;
|
||||
case 5:
|
||||
cell.darkness = true;
|
||||
break;
|
||||
case 6:
|
||||
cell.teleport = true;
|
||||
cell.addressTo = getAddress (b);
|
||||
break;
|
||||
case 8:
|
||||
cell.elevator = true;
|
||||
cell.elevatorTo = HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]);
|
||||
cell.elevatorFrom = HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
|
||||
break;
|
||||
case 9:
|
||||
cell.rock = true;
|
||||
break;
|
||||
case 10:
|
||||
cell.spellsBlocked = true;
|
||||
break;
|
||||
case 11:
|
||||
int messageNum = HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]);
|
||||
for (Message m : messages)
|
||||
if (m.match (messageNum))
|
||||
{
|
||||
cell.message = m;
|
||||
break;
|
||||
}
|
||||
if (cell.message == null)
|
||||
System.out.println ("message not found : " + messageNum);
|
||||
cell.messageType = HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
|
||||
switch (d)
|
||||
{
|
||||
case 1:
|
||||
cell.stairs = true;
|
||||
cell.addressTo = getAddress (b);
|
||||
break;
|
||||
case 2:
|
||||
cell.pit = true;
|
||||
break;
|
||||
case 3:
|
||||
cell.chute = true;
|
||||
cell.addressTo = getAddress (b);
|
||||
break;
|
||||
case 4:
|
||||
cell.spinner = true;
|
||||
break;
|
||||
case 5:
|
||||
cell.darkness = true;
|
||||
break;
|
||||
case 6:
|
||||
cell.teleport = true;
|
||||
cell.addressTo = getAddress (b);
|
||||
break;
|
||||
case 8:
|
||||
cell.elevator = true;
|
||||
cell.elevatorTo =
|
||||
HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]);
|
||||
cell.elevatorFrom =
|
||||
HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
|
||||
break;
|
||||
case 9:
|
||||
cell.rock = true;
|
||||
break;
|
||||
case 10:
|
||||
cell.spellsBlocked = true;
|
||||
break;
|
||||
case 11:
|
||||
int messageNum = HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]);
|
||||
if (messages != null)
|
||||
for (Message m : messages)
|
||||
if (m.match (messageNum))
|
||||
{
|
||||
cell.message = m;
|
||||
break;
|
||||
}
|
||||
if (cell.message == null)
|
||||
System.out.println ("message not found : " + messageNum);
|
||||
cell.messageType =
|
||||
HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
|
||||
|
||||
int itemID = -1;
|
||||
int itemID = -1;
|
||||
|
||||
if (cell.messageType == 2) // obtain Item
|
||||
{
|
||||
itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]);
|
||||
cell.itemObtained = items.get (itemID);
|
||||
}
|
||||
if (cell.messageType == 5) // requires Item
|
||||
{
|
||||
itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]);
|
||||
cell.itemRequired = items.get (itemID);
|
||||
}
|
||||
if (cell.messageType == 4)
|
||||
{
|
||||
value = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]);
|
||||
if (value <= 100)
|
||||
{
|
||||
cell.monsterID = value;
|
||||
cell.monsters = monsters;
|
||||
}
|
||||
else
|
||||
{
|
||||
int val = (value - 64536) * -1;
|
||||
System.out.println ("Value : " + val);
|
||||
// this gives Index error: 20410, Size 104 in Wizardry_III/legacy2.dsk
|
||||
if (val < items.size ())
|
||||
cell.itemObtained = items.get (val); // check this
|
||||
if (cell.itemObtained == null)
|
||||
System.out.printf ("Item %d not found%n", val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
cell.monsterID = HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
|
||||
cell.monsters = monsters;
|
||||
break;
|
||||
default:
|
||||
cell.unknown = d;
|
||||
break;
|
||||
}
|
||||
if (cell.messageType == 2 && items != null) // obtain Item
|
||||
{
|
||||
itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]);
|
||||
cell.itemObtained = items.get (itemID);
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
if (cell.messageType == 5 && items != null) // requires Item
|
||||
{
|
||||
itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]);
|
||||
cell.itemRequired = items.get (itemID);
|
||||
}
|
||||
|
||||
private MazeAddress getAddress (int a)
|
||||
{
|
||||
int b = a * 2;
|
||||
return new MazeAddress (HexFormatter.intValue (buffer[768 + b], buffer[769 + b]), HexFormatter
|
||||
.intValue (buffer[800 + b], buffer[801 + b]), HexFormatter.intValue (buffer[832 + b],
|
||||
buffer[833 + b]));
|
||||
}
|
||||
if (cell.messageType == 4)
|
||||
{
|
||||
value = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]);
|
||||
if (value <= 100)
|
||||
{
|
||||
cell.monsterID = value;
|
||||
cell.monsters = monsters;
|
||||
}
|
||||
else
|
||||
{
|
||||
int val = (value - 64536) * -1;
|
||||
System.out.println ("Value : " + val);
|
||||
// this gives Index error: 20410, Size 104 in Wizardry_III/legacy2.dsk
|
||||
if (items != null && val < items.size ())
|
||||
cell.itemObtained = items.get (val); // check this
|
||||
if (cell.itemObtained == null)
|
||||
System.out.printf ("Item %d not found%n", val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
cell.monsterID = HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
|
||||
cell.monsters = monsters;
|
||||
break;
|
||||
default:
|
||||
cell.unknown = d;
|
||||
break;
|
||||
}
|
||||
|
||||
public int getRows ()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
public int getColumns ()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
private MazeAddress getAddress (int a)
|
||||
{
|
||||
int b = a * 2;
|
||||
return new MazeAddress (HexFormatter.intValue (buffer[768 + b], buffer[769 + b]),
|
||||
HexFormatter.intValue (buffer[800 + b], buffer[801 + b]),
|
||||
HexFormatter.intValue (buffer[832 + b], buffer[833 + b]));
|
||||
}
|
||||
|
||||
public int getRows ()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
public int getColumns ()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
215
src/com/bytezone/diskbrowser/wizardry/Relocator.java
Normal file
215
src/com/bytezone/diskbrowser/wizardry/Relocator.java
Normal file
@ -0,0 +1,215 @@
|
||||
package com.bytezone.diskbrowser.wizardry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bytezone.diskbrowser.applefile.AbstractFile;
|
||||
import com.bytezone.diskbrowser.disk.AppleDisk;
|
||||
import com.bytezone.diskbrowser.disk.Disk;
|
||||
import com.bytezone.diskbrowser.disk.DiskAddress;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
|
||||
public class Relocator extends AbstractFile
|
||||
{
|
||||
private final int checkByte;
|
||||
private final List<DiskRecord> diskRecords = new ArrayList<DiskRecord> ();
|
||||
|
||||
private final int[] diskBlocks = new int[0x800];
|
||||
private final int[] diskOffsets = new int[0x800];
|
||||
|
||||
public Relocator (String name, byte[] buffer)
|
||||
{
|
||||
super (name, buffer);
|
||||
|
||||
checkByte = HexFormatter.intValue (buffer[0], buffer[1]);
|
||||
|
||||
int ptr = 2; // skip checkByte
|
||||
|
||||
while (buffer[ptr] != 0)
|
||||
{
|
||||
DiskRecord diskRecord = new DiskRecord (buffer, ptr);
|
||||
diskRecords.add (diskRecord);
|
||||
ptr += diskRecord.size ();
|
||||
}
|
||||
|
||||
for (DiskRecord diskRecord : diskRecords)
|
||||
for (DiskSegment diskSegment : diskRecord.diskSegments)
|
||||
addLogicalBlock ((byte) diskRecord.diskNumber, diskSegment);
|
||||
}
|
||||
|
||||
private void addLogicalBlock (byte disk, DiskSegment diskSegment)
|
||||
{
|
||||
int lo = diskSegment.logicalBlock;
|
||||
int hi = diskSegment.logicalBlock + diskSegment.segmentLength;
|
||||
|
||||
for (int i = lo, count = 0; i < hi; i++, count++)
|
||||
// if (diskBlocks[i] == 0) // doesn't matter either way
|
||||
{
|
||||
diskBlocks[i] = disk;
|
||||
diskOffsets[i] = diskSegment.physicalBlock + count;
|
||||
}
|
||||
}
|
||||
|
||||
public void createNewBuffer (Disk[] dataDisks)
|
||||
{
|
||||
AppleDisk master = (AppleDisk) dataDisks[0];
|
||||
|
||||
for (int logicalBlock = 0; logicalBlock < diskBlocks.length; logicalBlock++)
|
||||
{
|
||||
int diskNo = diskBlocks[logicalBlock];
|
||||
if (diskNo > 0)
|
||||
{
|
||||
Disk disk = dataDisks[diskNo];
|
||||
byte[] temp = disk.readSector (diskOffsets[logicalBlock]);
|
||||
DiskAddress da = master.getDiskAddress (logicalBlock);
|
||||
master.writeSector (da, temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText ()
|
||||
{
|
||||
StringBuilder text = new StringBuilder ();
|
||||
|
||||
text.append ("Pascal Relocator\n\n");
|
||||
text.append (String.format ("Check byte..... %04X%n%n", checkByte));
|
||||
|
||||
for (DiskRecord diskRecord : diskRecords)
|
||||
{
|
||||
text.append (diskRecord);
|
||||
text.append ("\n");
|
||||
}
|
||||
|
||||
List<String> lines = new ArrayList<String> ();
|
||||
String heading = " Logical Size Disk Physical";
|
||||
String underline = "--------- ---- ---- ---------";
|
||||
|
||||
int first = 0;
|
||||
int lastDisk = diskBlocks[0];
|
||||
int lastOffset = diskOffsets[0];
|
||||
for (int i = 0; i < diskBlocks.length; i++)
|
||||
{
|
||||
if (diskBlocks[i] != lastDisk || diskOffsets[i] != lastOffset + i - first)
|
||||
{
|
||||
int size = i - first;
|
||||
if (lastDisk > 0)
|
||||
lines.add (String.format ("%03X - %03X %03X %d %03X - %03X", first,
|
||||
i - 1, size, lastDisk, lastOffset, lastOffset + size - 1));
|
||||
else
|
||||
lines.add (String.format ("%03X - %03X %03X", first, i - 1, size));
|
||||
|
||||
first = i;
|
||||
lastDisk = diskBlocks[i];
|
||||
lastOffset = diskOffsets[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (lastDisk > 0)
|
||||
{
|
||||
int max = diskBlocks.length;
|
||||
int size = max - first;
|
||||
lines.add (String.format ("%03X - %03X %03X %d %03X - %03X", first, max - 1,
|
||||
size, lastDisk, lastOffset, lastOffset + size - 1));
|
||||
}
|
||||
|
||||
for (int i = lines.size () - 1; i >= 0; i--)
|
||||
{
|
||||
String line = lines.get (i);
|
||||
if (line.length () > 20)
|
||||
break;
|
||||
lines.remove (i);
|
||||
}
|
||||
|
||||
text.append (String.format (" %s %s%n %s %s%n", heading, heading,
|
||||
underline, underline));
|
||||
int offset = (lines.size () + 1) / 2;
|
||||
// boolean oddLines = lines.size () % 2 == 1;
|
||||
int pairs = lines.size () / 2;
|
||||
|
||||
for (int i = 0; i < pairs; i++)
|
||||
{
|
||||
text.append (
|
||||
String.format (" %-35s %s%n", lines.get (i), lines.get (i + offset)));
|
||||
}
|
||||
if (offset != pairs)
|
||||
text.append (String.format (" %s%n", lines.get (pairs)));
|
||||
|
||||
return text.toString ();
|
||||
}
|
||||
|
||||
private class DiskRecord
|
||||
{
|
||||
int diskNumber;
|
||||
int totDiskSegments;
|
||||
List<DiskSegment> diskSegments = new ArrayList<DiskSegment> ();
|
||||
|
||||
public DiskRecord (byte[] buffer, int ptr)
|
||||
{
|
||||
diskNumber = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]);
|
||||
totDiskSegments = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 4]);
|
||||
|
||||
ptr += 4;
|
||||
for (int i = 0; i < totDiskSegments; i++)
|
||||
{
|
||||
diskSegments.add (new DiskSegment (buffer, ptr));
|
||||
ptr += 6;
|
||||
}
|
||||
}
|
||||
|
||||
int size ()
|
||||
{
|
||||
return 4 + diskSegments.size () * 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder text = new StringBuilder ();
|
||||
|
||||
text.append (String.format ("Disk number.... %04X%n", diskNumber));
|
||||
text.append (String.format ("Segments....... %04X%n%n", totDiskSegments));
|
||||
text.append (String.format (" Seg Skip Size Logical Physical%n"));
|
||||
text.append (String.format (" --- ---- ---- ----------- -----------%n"));
|
||||
|
||||
int count = 1;
|
||||
int last = 0;
|
||||
int skip = 0;
|
||||
|
||||
for (DiskSegment segment : diskSegments)
|
||||
{
|
||||
if (segment.logicalBlock > last)
|
||||
{
|
||||
int end = segment.logicalBlock - 1;
|
||||
skip = end - last + 1;
|
||||
}
|
||||
last = segment.logicalBlock + segment.segmentLength;
|
||||
text.append (String.format (" %02X %04X %s %n", count++, skip, segment));
|
||||
}
|
||||
|
||||
return text.toString ();
|
||||
}
|
||||
}
|
||||
|
||||
private class DiskSegment
|
||||
{
|
||||
int logicalBlock;
|
||||
int physicalBlock;
|
||||
int segmentLength;
|
||||
|
||||
public DiskSegment (byte[] buffer, int ptr)
|
||||
{
|
||||
logicalBlock = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]);
|
||||
physicalBlock = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]);
|
||||
segmentLength = HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return String.format (" %04X %04X - %04X %04X - %04X", segmentLength,
|
||||
logicalBlock, (logicalBlock + segmentLength - 1), physicalBlock,
|
||||
(physicalBlock + segmentLength - 1));
|
||||
}
|
||||
}
|
||||
}
|
46
src/com/bytezone/diskbrowser/wizardry/Wiz4Image.java
Normal file
46
src/com/bytezone/diskbrowser/wizardry/Wiz4Image.java
Normal file
@ -0,0 +1,46 @@
|
||||
package com.bytezone.diskbrowser.wizardry;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBuffer;
|
||||
|
||||
public class Wiz4Image extends AbstractImage
|
||||
{
|
||||
|
||||
public Wiz4Image (String name, byte[] buffer)
|
||||
{
|
||||
super (name, buffer);
|
||||
|
||||
image = new BufferedImage (42, 40, BufferedImage.TYPE_BYTE_GRAY); // width/height
|
||||
DataBuffer db = image.getRaster ().getDataBuffer ();
|
||||
int element = 0;
|
||||
|
||||
// System.out.println (HexFormatter.format (buffer));
|
||||
|
||||
for (int row = 0; row < 5; row++)
|
||||
{
|
||||
for (int line = 0; line < 8; line++)
|
||||
{
|
||||
for (int col = 0; col < 6; col++)
|
||||
{
|
||||
int ptr = row * 48 + col * 8 + line;
|
||||
{
|
||||
byte b = buffer[ptr];
|
||||
for (int bit = 0; bit < 7; bit++)
|
||||
{
|
||||
if ((b & 0x01) == 0x01)
|
||||
{
|
||||
db.setElem (element, 255);
|
||||
// System.out.print ("X");
|
||||
}
|
||||
// else
|
||||
// System.out.print (".");
|
||||
b >>>= 1;
|
||||
element++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// System.out.println ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,27 +6,33 @@ import java.util.List;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
|
||||
import com.bytezone.diskbrowser.applefile.Relocator;
|
||||
import com.bytezone.diskbrowser.applefile.AbstractFile;
|
||||
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.pascal.FileEntry;
|
||||
import com.bytezone.diskbrowser.pascal.PascalDisk;
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
import com.bytezone.diskbrowser.utilities.Utility;
|
||||
|
||||
public class Wizardry4BootDisk extends PascalDisk
|
||||
{
|
||||
List<AppleDisk> disks = new ArrayList<AppleDisk> ();
|
||||
protected Disk[] dataDisks;
|
||||
// protected Disk[] dataDisks;
|
||||
private Relocator relocator;
|
||||
|
||||
public Wizardry4BootDisk (AppleDisk[] dataDisks)
|
||||
{
|
||||
super (dataDisks[0]);
|
||||
|
||||
this.dataDisks = dataDisks;
|
||||
// this.dataDisks = dataDisks;
|
||||
|
||||
DefaultTreeModel model = (DefaultTreeModel) catalogTree.getModel ();
|
||||
DefaultMutableTreeNode currentRoot = (DefaultMutableTreeNode) model.getRoot ();
|
||||
|
||||
// get the relocation table
|
||||
DefaultMutableTreeNode relocNode = findNode (currentRoot, "SYSTEM.RELOC");
|
||||
FileEntry fileEntry = (FileEntry) relocNode.getUserObject ();
|
||||
|
||||
@ -34,27 +40,90 @@ public class Wizardry4BootDisk extends PascalDisk
|
||||
{
|
||||
relocator =
|
||||
new Relocator (fileEntry.getUniqueName (), fileEntry.getDataSource ().buffer);
|
||||
relocator.createNewBuffer (dataDisks);
|
||||
relocator.createNewBuffer (dataDisks); // create new data buffer
|
||||
fileEntry.setFile (relocator);
|
||||
}
|
||||
|
||||
// reset the code segment so that it rebuilds itself from the new data
|
||||
DefaultMutableTreeNode pascalNode = findNode (currentRoot, "SYSTEM.PASCAL");
|
||||
fileEntry = (FileEntry) pascalNode.getUserObject ();
|
||||
fileEntry.setFile (null);
|
||||
fileEntry.getDataSource ();
|
||||
|
||||
if (fileEntry != null)
|
||||
{
|
||||
// fileEntry.setFile (null);
|
||||
// fileEntry.getDataSource ();
|
||||
}
|
||||
|
||||
DefaultMutableTreeNode scenarioNode = findNode (currentRoot, "SCENARIO.DATA");
|
||||
fileEntry = (FileEntry) scenarioNode.getUserObject ();
|
||||
|
||||
if (fileEntry != null)
|
||||
{
|
||||
fileEntry.setFile (null);
|
||||
scenarioNode.setAllowsChildren (true);
|
||||
|
||||
fileEntry.setFile (null);
|
||||
byte[] buffer = fileEntry.getDataSource ().buffer;
|
||||
|
||||
for (int i = 0; i < 11; i++)
|
||||
{
|
||||
byte[] level = new byte[896];
|
||||
System.out.println (HexFormatter.format (buffer, 0, 512));
|
||||
System.arraycopy (buffer, 0xC600 + i * 1024, level, 0, level.length);
|
||||
MazeLevel maze = new MazeLevel (level, i);
|
||||
|
||||
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
||||
addToNode (maze, scenarioNode, blocks, null);
|
||||
}
|
||||
}
|
||||
|
||||
DefaultMutableTreeNode monstersNode = findNode (currentRoot, "200.MONSTERS");
|
||||
fileEntry = (FileEntry) monstersNode.getUserObject ();
|
||||
|
||||
if (fileEntry != null)
|
||||
{
|
||||
monstersNode.setAllowsChildren (true);
|
||||
byte[] pictureBuffer = fileEntry.getDataSource ().buffer;
|
||||
List<DiskAddress> pictureBlocks = fileEntry.getSectors ();
|
||||
|
||||
int count = 0;
|
||||
loop: for (int block = 0; block < 24; block++)
|
||||
{
|
||||
int ptr = block * 512;
|
||||
for (int pic = 0; pic < 2; pic++)
|
||||
{
|
||||
byte[] buffer = new byte[240];
|
||||
System.arraycopy (pictureBuffer, ptr + pic * 256, buffer, 0, 240);
|
||||
Wiz4Image image = new Wiz4Image ("Image " + count++, buffer);
|
||||
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
||||
blocks.add (pictureBlocks.get (block));
|
||||
addToNode (image, monstersNode, blocks, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWizardryIV (Disk disk, boolean debug)
|
||||
private void addToNode (AbstractFile af, DefaultMutableTreeNode node,
|
||||
List<DiskAddress> blocks, SectorType type)
|
||||
{
|
||||
DefaultAppleFileSource dafs =
|
||||
new DefaultAppleFileSource (af.getName (), af, this, blocks);
|
||||
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode (dafs);
|
||||
node.add (childNode);
|
||||
childNode.setAllowsChildren (false);
|
||||
}
|
||||
|
||||
public static boolean isWizardryIVorV (Disk disk, boolean debug)
|
||||
{
|
||||
// Wizardry IV or V boot code
|
||||
byte[] header = { 0x00, (byte) 0xEA, (byte) 0xA9, 0x60, (byte) 0x8D, 0x01, 0x08 };
|
||||
byte[] buffer = disk.readSector (0);
|
||||
|
||||
if (!Utility.matches (buffer, 0, header))
|
||||
return false;
|
||||
buffer = disk.readSector (1);
|
||||
|
||||
if (buffer[510] != 1)
|
||||
buffer = disk.readSector (1);
|
||||
if (buffer[510] != 1 || buffer[511] != 0) // disk #1
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -485,7 +485,8 @@ public class WizardryScenarioDisk extends PascalDisk
|
||||
nodeSectors.addAll (blocks);
|
||||
byte[] buffer = disk.readSectors (blocks);
|
||||
byte[] data2 = new byte[896];
|
||||
System.arraycopy (buffer, 0, data2, 0, 896);
|
||||
System.arraycopy (buffer, 0, data2, 0, data2.length);
|
||||
// System.out.println (HexFormatter.format (data2));
|
||||
|
||||
MazeLevel model = new MazeLevel (data2, i + 1);
|
||||
model.setMessages (messages);
|
||||
|
Loading…
Reference in New Issue
Block a user