dmolony-DiskBrowser/src/com/bytezone/diskbrowser/pascal/PascalDisk.java

286 lines
9.8 KiB
Java
Raw Normal View History

2015-06-01 09:35:51 +00:00
package com.bytezone.diskbrowser.pascal;
import java.awt.Color;
import java.text.DateFormat;
import java.util.ArrayList;
2016-08-02 10:37:27 +00:00
import java.util.GregorianCalendar;
2015-06-01 09:35:51 +00:00
import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode;
2016-02-25 09:23:08 +00:00
import com.bytezone.diskbrowser.applefile.AppleFileSource;
import com.bytezone.diskbrowser.applefile.BootSector;
2015-06-01 09:35:51 +00:00
import com.bytezone.diskbrowser.disk.*;
import com.bytezone.diskbrowser.gui.DataSource;
2016-02-24 21:11:14 +00:00
import com.bytezone.diskbrowser.utilities.HexFormatter;
2016-08-14 08:41:19 +00:00
import com.bytezone.diskbrowser.wizardry.Relocator;
2015-06-01 09:35:51 +00:00
public class PascalDisk extends AbstractFormattedDisk
{
static final int CATALOG_ENTRY_SIZE = 26;
2016-03-24 00:17:09 +00:00
private final DateFormat df = DateFormat.getDateInstance (DateFormat.SHORT);
2016-08-09 04:15:44 +00:00
private final VolumeEntry volumeEntry;
private final PascalCatalogSector diskCatalogSector;
2016-08-08 10:34:25 +00:00
2016-08-08 04:53:29 +00:00
protected Relocator relocator;
2015-06-01 09:35:51 +00:00
2016-02-25 09:23:08 +00:00
final String[] fileTypes =
2017-04-26 08:04:48 +00:00
{ "Volume", "Bad ", "Code", "Text", "Info", "Data", "Graf", "Foto", "SecureDir" };
2015-06-01 09:35:51 +00:00
SectorType diskBootSector = new SectorType ("Boot", Color.lightGray);
SectorType catalogSector = new SectorType ("Catalog", Color.magenta);
SectorType dataSector = new SectorType ("Data", new Color (0, 200, 0)); // green
SectorType codeSector = new SectorType ("Code", Color.red);
SectorType textSector = new SectorType ("Text", Color.blue);
SectorType infoSector = new SectorType ("Info", Color.orange);
SectorType grafSector = new SectorType ("Graf", Color.cyan);
SectorType fotoSector = new SectorType ("Foto", Color.gray);
2017-04-26 08:04:48 +00:00
SectorType badSector = new SectorType ("Bad", Color.darkGray);
SectorType[] sectors = { catalogSector, badSector, codeSector, textSector, infoSector,
dataSector, grafSector, fotoSector };
2015-06-01 09:35:51 +00:00
public PascalDisk (Disk disk)
{
super (disk);
sectorTypesList.add (diskBootSector);
sectorTypesList.add (catalogSector);
sectorTypesList.add (dataSector);
sectorTypesList.add (codeSector);
sectorTypesList.add (textSector);
sectorTypesList.add (infoSector);
sectorTypesList.add (grafSector);
sectorTypesList.add (fotoSector);
2017-04-26 08:04:48 +00:00
sectorTypesList.add (badSector);
2015-06-01 09:35:51 +00:00
2016-08-08 04:53:29 +00:00
List<DiskAddress> blocks = disk.getDiskAddressList (0, 1); // B0, B1
this.bootSector = new BootSector (disk, disk.readSectors (blocks), "Pascal");
2015-06-01 09:35:51 +00:00
for (int i = 0; i < 2; i++)
if (!disk.isSectorEmpty (i))
{
sectorTypes[i] = diskBootSector;
freeBlocks.set (i, false);
}
2016-08-08 04:53:29 +00:00
for (int i = 2; i < disk.getTotalBlocks (); i++)
2015-06-01 09:35:51 +00:00
freeBlocks.set (i, true);
2016-08-14 08:41:19 +00:00
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);
2019-11-01 03:30:19 +00:00
List<DiskAddress> sectors = new ArrayList<> ();
2016-08-14 08:41:19 +00:00
int max = Math.min (volumeEntry.lastBlock, disk.getTotalBlocks ());
for (int i = 2; i < max; i++)
2015-06-01 09:35:51 +00:00
{
DiskAddress da = disk.getDiskAddress (i);
if (!disk.isSectorEmpty (da))
sectorTypes[i] = catalogSector;
sectors.add (da);
freeBlocks.set (i, false);
}
2016-02-29 01:54:44 +00:00
2016-08-06 10:00:01 +00:00
diskCatalogSector =
new PascalCatalogSector (disk, disk.readSectors (sectors), sectors);
2015-06-01 09:35:51 +00:00
// read the catalog
2019-11-01 03:30:19 +00:00
List<DiskAddress> addresses = new ArrayList<> ();
2016-08-14 08:41:19 +00:00
for (int i = 2; i < max; i++)
2015-06-01 09:35:51 +00:00
addresses.add (disk.getDiskAddress (i));
buffer = disk.readSectors (addresses);
// loop through each catalog entry (what if there are deleted files?)
2016-08-02 10:37:27 +00:00
for (int i = 1; i <= volumeEntry.totalFiles; i++)
2015-06-01 09:35:51 +00:00
{
int ptr = i * CATALOG_ENTRY_SIZE;
data = new byte[CATALOG_ENTRY_SIZE];
System.arraycopy (buffer, ptr, data, 0, CATALOG_ENTRY_SIZE);
2016-08-09 04:15:44 +00:00
FileEntry fileEntry = new FileEntry (this, data);
2016-08-14 08:41:19 +00:00
2016-08-02 10:37:27 +00:00
fileEntries.add (fileEntry);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (fileEntry);
2016-08-09 04:15:44 +00:00
fileEntry.setNode (node);
2016-02-25 09:23:08 +00:00
2016-08-09 09:09:11 +00:00
if (fileEntry.fileType == 2)
2015-06-01 09:35:51 +00:00
{
node.setAllowsChildren (true);
2016-08-14 08:41:19 +00:00
fileEntry.getDataSource (); // build segments
2015-06-01 09:35:51 +00:00
}
else
node.setAllowsChildren (false);
2016-02-29 01:54:44 +00:00
2015-06-01 09:35:51 +00:00
volumeNode.add (node);
2016-08-02 10:37:27 +00:00
for (int j = fileEntry.firstBlock; j < fileEntry.lastBlock; j++)
2015-06-01 09:35:51 +00:00
freeBlocks.set (j, false);
}
volumeNode.setUserObject (getCatalog ());
makeNodeVisible (volumeNode.getFirstLeaf ());
}
public static boolean isCorrectFormat (AppleDisk disk, boolean debug)
{
2016-08-02 10:37:27 +00:00
disk.setInterleave (1); // should only ever be Prodos
2015-06-01 09:35:51 +00:00
if (checkFormat (disk, debug))
return true;
2019-11-01 03:30:19 +00:00
disk.setInterleave (0); // see SANE Disk 2.po
2017-06-12 09:09:19 +00:00
if (checkFormat (disk, debug))
return true;
2016-08-03 11:32:47 +00:00
return false;
2015-06-01 09:35:51 +00:00
}
public static boolean checkFormat (AppleDisk disk, boolean debug)
{
byte[] buffer = disk.readSector (2);
2016-12-17 22:07:55 +00:00
int nameLength = buffer[6] & 0xFF;
2015-06-01 09:35:51 +00:00
if (nameLength < 1 || nameLength > 7)
{
if (debug)
System.out.println ("bad name length : " + nameLength);
return false;
}
2016-02-29 01:54:44 +00:00
2015-06-01 09:35:51 +00:00
if (debug)
{
String name = HexFormatter.getPascalString (buffer, 6);
System.out.println ("Name ok : " + name);
}
int from = HexFormatter.intValue (buffer[0], buffer[1]);
int to = HexFormatter.intValue (buffer[2], buffer[3]);
if (from != 0 || to != 6)
2016-02-29 01:54:44 +00:00
{
if (debug)
System.out.printf ("from: %d, to: %d%n", from, to);
return false; // will only work for floppies!
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
int blocks = HexFormatter.intValue (buffer[14], buffer[15]);
if (blocks > 280)
{
if (debug)
System.out.printf ("Blocks > 280: %d%n", blocks);
// return false;
}
2019-11-01 03:30:19 +00:00
List<DiskAddress> addresses = new ArrayList<> ();
2015-06-01 09:35:51 +00:00
for (int i = 2; i < to; i++)
addresses.add (disk.getDiskAddress (i));
buffer = disk.readSectors (addresses);
int files = HexFormatter.intValue (buffer[16], buffer[17]);
if (files < 0 || files > 77)
2016-02-29 01:54:44 +00:00
{
if (debug)
System.out.printf ("Files: %d%n", files);
2015-06-01 09:35:51 +00:00
return false;
2016-02-29 01:54:44 +00:00
}
2015-06-01 09:35:51 +00:00
if (debug)
System.out.println ("Files found : " + files);
for (int i = 1; i <= files; i++)
{
int ptr = i * 26;
2016-08-02 10:37:27 +00:00
int firstBlock = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]);
int lastBlock = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]);
int kind = HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]);
if (lastBlock < firstBlock)
2015-06-01 09:35:51 +00:00
return false;
2016-08-02 10:37:27 +00:00
if (kind == 0)
2015-06-01 09:35:51 +00:00
return false;
2016-12-17 22:07:55 +00:00
nameLength = buffer[ptr + 6] & 0xFF;
2015-06-01 09:35:51 +00:00
if (nameLength < 1 || nameLength > 15)
return false;
2016-08-02 10:37:27 +00:00
int lastByte = HexFormatter.intValue (buffer[ptr + 22], buffer[ptr + 23]);
GregorianCalendar date = HexFormatter.getPascalDate (buffer, 24);
2016-02-29 01:54:44 +00:00
if (debug)
2016-08-02 10:37:27 +00:00
System.out.printf ("%4d %4d %d %-15s %d %s%n", firstBlock, lastBlock, kind,
2016-08-05 08:40:32 +00:00
new String (buffer, ptr + 7, nameLength), lastByte, date);
2015-06-01 09:35:51 +00:00
}
return true;
}
@Override
public DataSource getFormattedSector (DiskAddress da)
{
SectorType st = sectorTypes[da.getBlock ()];
if (st == diskBootSector)
return bootSector;
if (st == catalogSector)
return diskCatalogSector;
String name = getSectorFilename (da);
if (name != null)
return new DefaultSector (name, disk, disk.readSector (da), da);
2015-06-01 09:35:51 +00:00
return super.getFormattedSector (da);
}
@Override
public String getSectorFilename (DiskAddress da)
{
for (AppleFileSource ce : fileEntries)
if (((CatalogEntry) ce).contains (da))
return ((CatalogEntry) ce).name;
return null;
}
@Override
public List<DiskAddress> getFileSectors (int fileNo)
{
if (fileNo < 0 || fileNo >= fileEntries.size ())
return null;
return fileEntries.get (fileNo).getSectors ();
}
public DataSource getFile (int fileNo)
{
if (fileNo < 0 || fileNo >= fileEntries.size ())
return null;
return fileEntries.get (fileNo).getDataSource ();
}
@Override
public AppleFileSource getCatalog ()
{
String newLine = String.format ("%n");
String newLine2 = newLine + newLine;
2016-08-05 08:40:32 +00:00
String line = "---- --------------- ---- -------- ------- ---- ---- ----"
+ newLine;
2016-08-02 10:37:27 +00:00
String date =
volumeEntry.date == null ? "--" : df.format (volumeEntry.date.getTime ());
2015-06-01 09:35:51 +00:00
StringBuilder text = new StringBuilder ();
2019-01-26 20:06:13 +00:00
text.append ("Disk : " + getDisplayPath () + newLine2);
2016-08-02 10:37:27 +00:00
text.append ("Volume : " + volumeEntry.name + newLine);
2015-06-01 09:35:51 +00:00
text.append ("Date : " + date + newLine2);
2016-08-05 08:40:32 +00:00
text.append (
"Blks Name Type Date Length Frst Last Blks\n");
2015-06-01 09:35:51 +00:00
text.append (line);
int usedBlocks = 6;
for (AppleFileSource fe : fileEntries)
{
FileEntry ce = (FileEntry) fe;
int size = ce.lastBlock - ce.firstBlock;
usedBlocks += size;
date = ce.date == null ? "--" : df.format (ce.date.getTime ());
int bytes = (size - 1) * 512 + ce.bytesUsedInLastBlock;
2017-03-20 02:50:41 +00:00
String fileType = ce.fileType < 0 || ce.fileType >= fileTypes.length ? "????"
: fileTypes[ce.fileType];
2016-08-05 08:40:32 +00:00
text.append (String.format ("%4d %-15s %s %8s %,8d $%03X $%03X $%03X%n",
2017-03-20 02:50:41 +00:00
size, ce.name, fileType, date, bytes, ce.firstBlock, ce.lastBlock, size));
2015-06-01 09:35:51 +00:00
}
text.append (line);
2016-08-05 08:40:32 +00:00
text.append (
String.format ("Blocks free : %3d Blocks used : %3d Total blocks : %3d%n",
(volumeEntry.totalBlocks - usedBlocks), usedBlocks, volumeEntry.totalBlocks));
2016-08-02 10:37:27 +00:00
return new DefaultAppleFileSource (volumeEntry.name, text.toString (), this);
2015-06-01 09:35:51 +00:00
}
}