mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-11-23 04:33:18 +00:00
rewrote Prodos index traversal
This commit is contained in:
parent
bdbd837376
commit
c4d789c501
@ -246,4 +246,29 @@ public class IntegerBasicProgram extends AbstractFile
|
||||
|
||||
return pgm.toString ();
|
||||
}
|
||||
|
||||
/*
|
||||
* https://groups.google.com/forum/#!topic/comp.sys.apple2/Baf36jyqwAM
|
||||
* To convert Integer Basic to Applesoft
|
||||
|
||||
INPUT comands - change comma to semi-colon
|
||||
remove all DIM of a string variable (not needed)
|
||||
change string variables to use MID$ - i.e. A$(1,1)(in INT) is MID$(A$,1,1)(in AS basic)
|
||||
change GOTO or GOSUB with a variable to ON GOTO
|
||||
change IF statements to ON GOTO where possible and convert to multiple lines.
|
||||
All statements that follow an IF on the same line are executed whether the statement
|
||||
is true or not.
|
||||
change MOD function to X=Y-(INT(Y/Z)*Z)
|
||||
change "#" to "<>"
|
||||
change TAB to HTAB
|
||||
change RND(X) to INT(RND(1)*X)
|
||||
relocate ML programs and change CALL'S and POKE'S. Since INT programs go from
|
||||
HIMEM down, binary code is usually in low memory.
|
||||
|
||||
These few are not necessary but make for compact code.
|
||||
|
||||
change CALL -384 to INVERSE
|
||||
change CALL -380 to NORMAL
|
||||
change CALL -936 to HOME
|
||||
*/
|
||||
}
|
@ -294,8 +294,6 @@ public abstract class AbstractFormattedDisk implements FormattedDisk
|
||||
{
|
||||
if (block >= sectorTypes.length)
|
||||
System.out.println ("Invalid block number: " + block);
|
||||
else if (sectorTypes[block] == emptySector)
|
||||
System.out.printf ("Tried to assign %s to empty block %d%n", type.name, block);
|
||||
else
|
||||
sectorTypes[block] = type;
|
||||
}
|
||||
|
@ -34,11 +34,13 @@ abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
{
|
||||
this.dosDisk = dosDisk;
|
||||
this.disk = dosDisk.getDisk ();
|
||||
this.disk = dosDisk.getDisk ();
|
||||
this.catalogSectorDA = catalogSector;
|
||||
reportedSize = HexFormatter.intValue (entryBuffer[33], entryBuffer[34]);
|
||||
|
||||
// reportedSize = HexFormatter.intValue (entryBuffer[33], entryBuffer[34]);
|
||||
reportedSize = HexFormatter.unsignedShort (entryBuffer, 33);
|
||||
int type = entryBuffer[2] & 0xFF;
|
||||
locked = (type & 0x80) > 0;
|
||||
this.disk = dosDisk.getDisk ();
|
||||
|
||||
if ((type & 0x7F) == 0)
|
||||
fileType = FileType.Text;
|
||||
@ -154,14 +156,14 @@ abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
break;
|
||||
|
||||
case IntegerBasic:
|
||||
reportedLength = HexFormatter.intValue (buffer[0], buffer[1]);
|
||||
reportedLength = HexFormatter.unsignedShort (buffer, 0);
|
||||
exactBuffer = new byte[reportedLength];
|
||||
System.arraycopy (buffer, 2, exactBuffer, 0, reportedLength);
|
||||
appleFile = new IntegerBasicProgram (name, exactBuffer);
|
||||
break;
|
||||
|
||||
case ApplesoftBasic:
|
||||
reportedLength = HexFormatter.intValue (buffer[0], buffer[1]);
|
||||
reportedLength = HexFormatter.unsignedShort (buffer, 0);
|
||||
exactBuffer = new byte[reportedLength];
|
||||
if (reportedLength > buffer.length)
|
||||
reportedLength = buffer.length - 2;
|
||||
@ -171,12 +173,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
|
||||
case Binary: // binary file
|
||||
case Relocatable: // relocatable binary file
|
||||
// if (buffer.length == 0)
|
||||
// appleFile = new AssemblerProgram (name, buffer, 0);
|
||||
// else
|
||||
// {
|
||||
int loadAddress = HexFormatter.intValue (buffer[0], buffer[1]);
|
||||
reportedLength = HexFormatter.intValue (buffer[2], buffer[3]);
|
||||
int loadAddress = HexFormatter.unsignedShort (buffer, 0);
|
||||
reportedLength = HexFormatter.unsignedShort (buffer, 2);
|
||||
if (reportedLength == 0)
|
||||
{
|
||||
System.out.println (name.trim () + " reported length : 0 - reverting to "
|
||||
@ -275,8 +273,10 @@ abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
{
|
||||
byte[] exactBuffer;
|
||||
|
||||
int loadAddress = HexFormatter.intValue (buffer[0], buffer[1]);
|
||||
int reportedLength = HexFormatter.intValue (buffer[2], buffer[3]);
|
||||
// int loadAddress = HexFormatter.intValue (buffer[0], buffer[1]);
|
||||
int loadAddress = HexFormatter.unsignedShort (buffer, 0);
|
||||
// int reportedLength = HexFormatter.intValue (buffer[2], buffer[3]);
|
||||
int reportedLength = HexFormatter.unsignedShort (buffer, 2);
|
||||
if (reportedLength == 0)
|
||||
{
|
||||
System.out.println (
|
||||
|
@ -6,13 +6,14 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
|
||||
class CatalogEntry extends AbstractCatalogEntry
|
||||
{
|
||||
int textFileGaps;
|
||||
int length;
|
||||
int address;
|
||||
private int textFileGaps;
|
||||
private int length;
|
||||
private int address;
|
||||
|
||||
public CatalogEntry (DosDisk dosDisk, DiskAddress catalogSector, byte[] entryBuffer)
|
||||
{
|
||||
super (dosDisk, catalogSector, entryBuffer); // build lists of ts and data sectors
|
||||
|
||||
if (reportedSize > 0 && disk.isValidAddress (entryBuffer[0], entryBuffer[1]))
|
||||
{
|
||||
// Get address of first TS-list sector
|
||||
|
@ -68,7 +68,8 @@ class DosTSListSector extends AbstractSector
|
||||
if (buffer[i] == 0 && buffer[i + 1] == 0)
|
||||
msg = "";
|
||||
else
|
||||
msg = "Track/sector of file sector " + ((i - 10) / 2 + sectorBase);
|
||||
msg = String.format ("Track/sector of file sector %04X (%<,d)",
|
||||
((i - 12) / 2 + sectorBase));
|
||||
addText (text, buffer, i, 2, msg);
|
||||
}
|
||||
|
||||
|
@ -40,73 +40,53 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||
this.parentDirectory = parent;
|
||||
this.catalogBlock = this.disk.getDiskAddress (parentBlock);
|
||||
|
||||
fileType = entryBuffer[16] & 0xFF;
|
||||
// keyPtr = HexFormatter.intValue (entryBuffer[17], entryBuffer[18]);
|
||||
keyPtr = HexFormatter.unsignedShort (entryBuffer, 17);
|
||||
// System.out.printf ("%5d %5d%n",
|
||||
// HexFormatter.intValue (entryBuffer[17], entryBuffer[18]), keyPtr);
|
||||
// blocksUsed = HexFormatter.intValue (entryBuffer[19], entryBuffer[20]);
|
||||
blocksUsed = HexFormatter.unsignedShort (entryBuffer, 19);
|
||||
fileType = entryBuffer[0x10] & 0xFF;
|
||||
keyPtr = HexFormatter.unsignedShort (entryBuffer, 0x11);
|
||||
blocksUsed = HexFormatter.unsignedShort (entryBuffer, 0x13);
|
||||
endOfFile = HexFormatter.intValue (entryBuffer[21], entryBuffer[22], entryBuffer[23]);
|
||||
|
||||
// auxType = HexFormatter.intValue (entryBuffer[31], entryBuffer[32]);
|
||||
auxType = HexFormatter.unsignedShort (entryBuffer, 31);
|
||||
modified = HexFormatter.getAppleDate (entryBuffer, 33);
|
||||
// headerPointer = HexFormatter.intValue (entryBuffer[37], entryBuffer[38]);
|
||||
headerPointer = HexFormatter.unsignedShort (entryBuffer, 37);
|
||||
auxType = HexFormatter.unsignedShort (entryBuffer, 0x1F);
|
||||
modified = HexFormatter.getAppleDate (entryBuffer, 0x21);
|
||||
headerPointer = HexFormatter.unsignedShort (entryBuffer, 0x25);
|
||||
|
||||
if (isGSOSFile ()) // I think this is wrong
|
||||
System.out.printf ("************************************ %s is GS/OS%n", name);
|
||||
|
||||
switch (storageType)
|
||||
{
|
||||
case TYPE_SEEDLING:
|
||||
parentDisk.setSectorType (keyPtr, fDisk.dataSector);
|
||||
DiskAddress da = disk.getDiskAddress (keyPtr);
|
||||
if (da != null)
|
||||
dataBlocks.add (da);
|
||||
else
|
||||
invalid = true;
|
||||
addDataBlocks (storageType, keyPtr);
|
||||
break;
|
||||
|
||||
case TYPE_SAPLING:
|
||||
if (isGEOSFile ())
|
||||
if (isGSOSFile ()) // not sure why this exists
|
||||
traverseGEOSIndex (keyPtr);
|
||||
else
|
||||
traverseIndex (keyPtr);
|
||||
addDataBlocks (storageType, keyPtr);
|
||||
break;
|
||||
|
||||
case TYPE_TREE:
|
||||
parentDisk.setSectorType (keyPtr, fDisk.masterIndexSector);
|
||||
masterIndexBlock = disk.getDiskAddress (keyPtr);
|
||||
indexBlocks.add (masterIndexBlock);
|
||||
if (isGEOSFile ())
|
||||
if (isGSOSFile ()) // not sure why this exists
|
||||
traverseGEOSMasterIndex (keyPtr);
|
||||
else
|
||||
traverseMasterIndex (keyPtr);
|
||||
addDataBlocks (storageType, keyPtr);
|
||||
break;
|
||||
|
||||
case TYPE_GSOS_EXTENDED_FILE:
|
||||
parentDisk.setSectorType (keyPtr, fDisk.extendedKeySector);
|
||||
parentDisk.setSectorType (keyPtr, parentDisk.extendedKeySector);
|
||||
indexBlocks.add (disk.getDiskAddress (keyPtr));
|
||||
|
||||
byte[] buffer2 = disk.readSector (keyPtr); // data fork and resource fork
|
||||
|
||||
// read 2 mini entries (data fork / resource fork)
|
||||
for (int i = 0; i < 512; i += 256)
|
||||
{
|
||||
int storageType = buffer2[i] & 0x0F;
|
||||
int keyBlock = HexFormatter.intValue (buffer2[i + 1], buffer2[i + 2]);
|
||||
switch (storageType)
|
||||
{
|
||||
case ProdosConstants.TYPE_SEEDLING:
|
||||
parentDisk.setSectorType (keyBlock, fDisk.dataSector);
|
||||
dataBlocks.add (disk.getDiskAddress (keyBlock));
|
||||
break;
|
||||
case ProdosConstants.TYPE_SAPLING:
|
||||
traverseIndex (keyBlock);
|
||||
break;
|
||||
case ProdosConstants.TYPE_TREE:
|
||||
traverseMasterIndex (keyBlock);
|
||||
break;
|
||||
default:
|
||||
System.out.println ("fork not a tree, sapling or seedling!!!");
|
||||
}
|
||||
int keyBlock = HexFormatter.unsignedShort (buffer2, i + 1);
|
||||
int eof =
|
||||
HexFormatter.intValue (buffer2[i + 3], buffer2[i + 4], buffer2[i + 5]);
|
||||
addDataBlocks (storageType, keyBlock);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -129,90 +109,87 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGEOSFile ()
|
||||
private void addDataBlocks (int storageType, int keyPtr)
|
||||
{
|
||||
DiskAddress emptyDiskAddress = disk.getDiskAddress (0);
|
||||
List<Integer> blocks = new ArrayList<Integer> ();
|
||||
|
||||
switch (storageType)
|
||||
{
|
||||
case TYPE_SEEDLING:
|
||||
blocks.add (keyPtr);
|
||||
break;
|
||||
|
||||
case TYPE_SAPLING:
|
||||
blocks.addAll (readIndex (keyPtr));
|
||||
break;
|
||||
|
||||
case TYPE_TREE:
|
||||
for (Integer indexBlock : readMasterIndex (keyPtr))
|
||||
blocks.addAll (readIndex (indexBlock));
|
||||
break;
|
||||
}
|
||||
|
||||
// remove trailing empty blocks
|
||||
while (blocks.size () > 0 && blocks.get (blocks.size () - 1) == 0)
|
||||
blocks.remove (blocks.size () - 1);
|
||||
|
||||
for (Integer block : blocks)
|
||||
{
|
||||
if (block == 0)
|
||||
dataBlocks.add (emptyDiskAddress);
|
||||
else
|
||||
{
|
||||
dataBlocks.add (disk.getDiskAddress (block));
|
||||
parentDisk.setSectorType (block, parentDisk.dataSector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Integer> readIndex (int blockPtr)
|
||||
{
|
||||
List<Integer> blocks = new ArrayList<Integer> (256);
|
||||
|
||||
if (blockPtr == 0) // master index contains a zero
|
||||
for (int i = 0; i < 256; i++)
|
||||
blocks.add (0);
|
||||
else
|
||||
{
|
||||
byte[] buffer = disk.readSector (blockPtr);
|
||||
for (int i = 0; i < 256; i++)
|
||||
blocks.add ((buffer[i] & 0xFF) | ((buffer[i + 256] & 0xFF) << 8));
|
||||
parentDisk.setSectorType (blockPtr, parentDisk.indexSector);
|
||||
indexBlocks.add (disk.getDiskAddress (blockPtr));
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
private List<Integer> readMasterIndex (int blockPtr)
|
||||
{
|
||||
List<Integer> blocks = new ArrayList<Integer> (128);
|
||||
|
||||
byte[] buffer = disk.readSector (blockPtr); // master index
|
||||
parentDisk.setSectorType (blockPtr, parentDisk.masterIndexSector);
|
||||
indexBlocks.add (disk.getDiskAddress (blockPtr));
|
||||
|
||||
int max = 128;
|
||||
while (max-- > 0)
|
||||
if (buffer[max] != 0 || buffer[max + 256] != 0)
|
||||
break;
|
||||
|
||||
for (int i = 0; i <= max; i++)
|
||||
blocks.add ((buffer[i] & 0xFF) | ((buffer[i + 256] & 0xFF) << 8));
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
private boolean isGSOSFile ()
|
||||
{
|
||||
return ((fileType & 0xF0) == 0x80);
|
||||
}
|
||||
|
||||
private void traverseMasterIndex (int keyPtr)
|
||||
{
|
||||
byte[] buffer = disk.readSector (keyPtr); // master index
|
||||
|
||||
// find the last used index block
|
||||
// get the file size from the catalog and only check those blocks
|
||||
int highestBlock = 0;
|
||||
// A master index block can never be more than half full
|
||||
for (int i = 127; i >= 0; i--)
|
||||
{
|
||||
int block = HexFormatter.intValue (buffer[i], buffer[i + 256]);
|
||||
if (block > 0)
|
||||
{
|
||||
highestBlock = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i <= highestBlock; i++)
|
||||
{
|
||||
int block = HexFormatter.intValue (buffer[i], buffer[i + 256]); // index
|
||||
if (block != 0)
|
||||
traverseIndex (block);
|
||||
else
|
||||
// add 256 empty data blocks
|
||||
{
|
||||
DiskAddress da = disk.getDiskAddress (0);
|
||||
for (int j = 0; j < 256; j++)
|
||||
dataBlocks.add (da);
|
||||
}
|
||||
}
|
||||
|
||||
removeEmptyBlocks ();
|
||||
}
|
||||
|
||||
private void removeEmptyBlocks ()
|
||||
{
|
||||
while (dataBlocks.size () > 0)
|
||||
{
|
||||
DiskAddress da = dataBlocks.get (dataBlocks.size () - 1);
|
||||
|
||||
if (da == null || da.getBlock () != 0)
|
||||
break;
|
||||
|
||||
dataBlocks.remove (dataBlocks.size () - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void traverseIndex (int keyBlock)
|
||||
{
|
||||
parentDisk.setSectorType (keyBlock, parentDisk.indexSector);
|
||||
indexBlocks.add (disk.getDiskAddress (keyBlock));
|
||||
byte[] buffer = disk.readSector (keyBlock);
|
||||
|
||||
int maxBlocks = (endOfFile - 1) / 512 + 1;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int block = HexFormatter.intValue (buffer[i], buffer[i + 256]);
|
||||
if (!disk.isValidAddress (block))
|
||||
{
|
||||
System.out.println ("Invalid block in " + name + " : " + block);
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dataBlocks.size () == maxBlocks)
|
||||
break;
|
||||
|
||||
if (block == 0)
|
||||
dataBlocks.add (null); // allow for sparse image files
|
||||
else
|
||||
{
|
||||
parentDisk.setSectorType (block, parentDisk.dataSector);
|
||||
dataBlocks.add (disk.getDiskAddress (block));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should be removed
|
||||
private void traverseGEOSMasterIndex (int keyPtr)
|
||||
{
|
||||
byte[] buffer = disk.readSector (keyPtr); // master index
|
||||
@ -227,6 +204,7 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||
}
|
||||
}
|
||||
|
||||
// should be removed
|
||||
private void traverseGEOSIndex (int keyPtr)
|
||||
{
|
||||
parentDisk.setSectorType (keyPtr, parentDisk.indexSector);
|
||||
@ -260,7 +238,7 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||
if (fileType == FILE_TYPE_TEXT && auxType > 0) // random access file
|
||||
return getRandomAccessTextFile ();
|
||||
|
||||
byte[] buffer = isGEOSFile () ? getGEOSBuffer () : getBuffer ();
|
||||
byte[] buffer = isGSOSFile () ? getGEOSBuffer () : getBuffer ();
|
||||
byte[] exactBuffer = getExactBuffer (buffer);
|
||||
|
||||
try
|
||||
@ -379,6 +357,9 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||
case FILE_TYPE_PASCAL_VOLUME:
|
||||
file = new DefaultAppleFile (name, exactBuffer);
|
||||
break;
|
||||
case FILE_TYPE_FINDER:
|
||||
file = new DefaultAppleFile (name, exactBuffer);
|
||||
break;
|
||||
default:
|
||||
System.out.format ("%s - Unknown Prodos file type : %02X%n", name, fileType);
|
||||
file = new DefaultAppleFile (name, exactBuffer);
|
||||
|
@ -20,6 +20,7 @@ public interface ProdosConstants
|
||||
int FILE_TYPE_PNT = 0xC0;
|
||||
int FILE_TYPE_PIC = 0xC1;
|
||||
int FILE_TYPE_FONT = 0xC8;
|
||||
int FILE_TYPE_FINDER = 0xC9;
|
||||
int FILE_TYPE_ICN = 0xCA;
|
||||
int FILE_TYPE_APPLETALK = 0xE2;
|
||||
int FILE_TYPE_PASCAL_VOLUME = 0xEF;
|
||||
|
@ -4,6 +4,7 @@ import com.bytezone.diskbrowser.disk.AbstractSector;
|
||||
import com.bytezone.diskbrowser.disk.Disk;
|
||||
import com.bytezone.diskbrowser.disk.DiskAddress;
|
||||
|
||||
// see Prodos 8 Tech note #25
|
||||
class ProdosExtendedKeySector extends AbstractSector
|
||||
{
|
||||
public ProdosExtendedKeySector (Disk disk, byte[] buffer, DiskAddress diskAddress)
|
||||
@ -18,11 +19,24 @@ class ProdosExtendedKeySector extends AbstractSector
|
||||
|
||||
for (int i = 0; i < 512; i += 256)
|
||||
{
|
||||
addText (text, buffer, i, 1, "Storage type (" + getType (buffer[i]) + ")");
|
||||
String type = i == 0 ? "Data" : "Resource";
|
||||
addText (text, buffer, i, 1,
|
||||
type + " fork storage type (" + getType (buffer[i]) + ")");
|
||||
addTextAndDecimal (text, buffer, i + 1, 2, "Key block");
|
||||
addTextAndDecimal (text, buffer, i + 3, 2, "Blocks used");
|
||||
addTextAndDecimal (text, buffer, i + 5, 3, "EOF");
|
||||
text.append ("\n");
|
||||
|
||||
// check for Finder Info records
|
||||
if (i == 0 && buffer[8] != 0)
|
||||
{
|
||||
for (int j = 0; j <= 18; j += 18)
|
||||
{
|
||||
addTextAndDecimal (text, buffer, j + 8, 1, "Size");
|
||||
addTextAndDecimal (text, buffer, j + 9, 1, "Type");
|
||||
addTextAndDecimal (text, buffer, j + 10, 16, "Finder info");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return text.toString ();
|
||||
|
@ -25,9 +25,10 @@ class VolumeDirectoryHeader extends DirectoryHeader
|
||||
|
||||
bitMapBlock = HexFormatter.unsignedShort (entryBuffer, 35);
|
||||
totalBlocks = HexFormatter.unsignedShort (entryBuffer, 37);
|
||||
if (totalBlocks == 0xFFFF || totalBlocks == 0x7FFF)
|
||||
totalBlocks = (int) disk.getFile ().length () / 4096 * 8; // ignore extra bytes
|
||||
// totalBitMapBlocks = (totalBlocks * 8 - 1) / 4096 + 1;
|
||||
|
||||
// if (totalBlocks == 0xFFFF || totalBlocks == 0x7FFF)
|
||||
// totalBlocks = (int) disk.getFile ().length () / 4096 * 8;// ignore extra bytes
|
||||
|
||||
totalBitMapBlocks = (totalBlocks - 1) / 512 + 1;
|
||||
|
||||
int block = 2;
|
||||
@ -39,7 +40,7 @@ class VolumeDirectoryHeader extends DirectoryHeader
|
||||
} while (block > 0);
|
||||
|
||||
// convert the Free Sector Table
|
||||
int bitMapBytes = totalBlocks / 8; // one bit per block
|
||||
int bitMapBytes = totalBlocks / 8; // one bit per block
|
||||
byte[] buffer = new byte[bitMapBytes];
|
||||
int bitMapBlocks = (bitMapBytes - 1) / disk.getSectorsPerTrack () + 1;
|
||||
int lastBitMapBlock = bitMapBlock + bitMapBlocks - 1;
|
||||
@ -63,6 +64,8 @@ class VolumeDirectoryHeader extends DirectoryHeader
|
||||
// int max2 = (disk.getTotalBlocks () - 1) / 8 + 1; // bytes required for sector map
|
||||
|
||||
int max = (Math.min (totalBlocks, disk.getTotalBlocks ()) - 1) / 8 + 1;
|
||||
// System.out.printf ("total blocks %,d%n", totalBlocks);
|
||||
// System.out.printf ("disk blocks %,d%n", disk.getTotalBlocks ());
|
||||
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user