dmolony-DiskBrowser/src/com/bytezone/diskbrowser/prodos/FileEntry.java

688 lines
24 KiB
Java
Raw Normal View History

2015-06-01 09:35:51 +00:00
package com.bytezone.diskbrowser.prodos;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import com.bytezone.diskbrowser.applefile.*;
import com.bytezone.diskbrowser.appleworks.AppleworksADBFile;
import com.bytezone.diskbrowser.appleworks.AppleworksSSFile;
import com.bytezone.diskbrowser.appleworks.AppleworksWPFile;
import com.bytezone.diskbrowser.disk.DiskAddress;
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
// - Set sector types for each used sector
// - Populate dataBlocks, indexBlocks, catalogBlock and masterIndexBlock
// - Provide getDataSource ()
2019-11-03 05:49:01 +00:00
// -----------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
class FileEntry extends CatalogEntry implements ProdosConstants
2019-11-03 05:49:01 +00:00
// -----------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
private final int fileType;
final int keyPtr;
private final int blocksUsed;
private final int endOfFile;
private final int auxType;
private final GregorianCalendar modified;
2019-08-15 07:02:40 +00:00
private final int headerPointer;
2015-06-01 09:35:51 +00:00
private DataSource file;
private final DiskAddress catalogBlock;
2018-08-18 07:56:54 +00:00
2015-06-01 09:35:51 +00:00
private DiskAddress masterIndexBlock;
2019-11-01 03:30:19 +00:00
private final List<DiskAddress> indexBlocks = new ArrayList<> ();
2018-08-18 07:56:54 +00:00
2015-06-01 09:35:51 +00:00
private boolean invalid;
2016-12-31 09:34:15 +00:00
private FileEntry link;
2018-07-22 20:52:41 +00:00
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
public FileEntry (ProdosDisk fDisk, byte[] entryBuffer, DirectoryHeader parent,
2016-02-05 00:23:53 +00:00
int parentBlock)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
super (fDisk, entryBuffer);
2018-07-22 20:52:41 +00:00
2017-01-20 04:07:08 +00:00
assert parent != null;
2015-06-01 09:35:51 +00:00
this.parentDirectory = parent;
this.catalogBlock = this.disk.getDiskAddress (parentBlock);
2017-05-08 01:46:28 +00:00
fileType = entryBuffer[0x10] & 0xFF;
keyPtr = HexFormatter.unsignedShort (entryBuffer, 0x11);
blocksUsed = HexFormatter.unsignedShort (entryBuffer, 0x13);
2015-06-01 09:35:51 +00:00
endOfFile = HexFormatter.intValue (entryBuffer[21], entryBuffer[22], entryBuffer[23]);
2017-05-08 01:46:28 +00:00
auxType = HexFormatter.unsignedShort (entryBuffer, 0x1F);
modified = HexFormatter.getAppleDate (entryBuffer, 0x21);
2019-08-15 07:02:40 +00:00
headerPointer = HexFormatter.unsignedShort (entryBuffer, 0x25);
2017-05-08 01:46:28 +00:00
2015-06-01 09:35:51 +00:00
switch (storageType)
{
2017-05-12 10:42:20 +00:00
case SEEDLING:
case SAPLING:
case TREE:
2018-07-22 20:52:41 +00:00
addDataBlocks (storageType, keyPtr);
2015-06-01 09:35:51 +00:00
break;
2017-05-12 10:42:20 +00:00
case GSOS_EXTENDED_FILE:
2017-06-12 09:09:19 +00:00
readForks ();
2015-06-01 09:35:51 +00:00
break;
2017-05-12 10:42:20 +00:00
case SUBDIRECTORY:
2015-06-01 09:35:51 +00:00
int block = keyPtr;
do
{
2019-08-25 04:16:36 +00:00
DiskAddress diskAddress = disk.getDiskAddress (block);
if (diskAddress == null)
break;
dataBlocks.add (diskAddress);
2015-06-01 09:35:51 +00:00
byte[] buffer = disk.readSector (block);
2017-05-12 10:42:20 +00:00
block = HexFormatter.unsignedShort (buffer, 2);
2015-06-01 09:35:51 +00:00
} while (block > 0);
break;
2017-05-12 10:42:20 +00:00
case PASCAL_ON_PROFILE:
2017-04-22 06:31:25 +00:00
indexBlocks.add (disk.getDiskAddress (keyPtr));
2017-06-12 09:09:19 +00:00
System.out.println ("PASCAL on PROFILE: " + name);
// are these blocks guaranteed to be contiguous?
2017-04-22 06:31:25 +00:00
break;
2015-06-01 09:35:51 +00:00
default:
System.out.println ("Unknown storage type: " + storageType);
}
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2017-06-12 09:09:19 +00:00
private void readForks ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2017-06-12 09:09:19 +00:00
{
parentDisk.setSectorType (keyPtr, parentDisk.extendedKeySector);
indexBlocks.add (disk.getDiskAddress (keyPtr));
byte[] buffer2 = disk.readSector (keyPtr); // data fork and resource fork
2019-11-03 05:49:01 +00:00
// read 2 mini entries (data fork & resource fork)
2017-06-12 09:09:19 +00:00
for (int i = 0; i < 512; i += 256)
{
int storageType = buffer2[i] & 0x0F;
int keyBlock = HexFormatter.unsignedShort (buffer2, i + 1);
2019-09-13 05:32:35 +00:00
int eof = HexFormatter.intValue (buffer2[i + 3], buffer2[i + 4], buffer2[i + 5]);
2017-06-12 09:09:19 +00:00
addDataBlocks (storageType, keyBlock);
}
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2017-05-08 01:46:28 +00:00
private void addDataBlocks (int storageType, int keyPtr)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
2017-05-08 01:46:28 +00:00
DiskAddress emptyDiskAddress = disk.getDiskAddress (0);
2019-11-03 05:49:01 +00:00
List<Integer> blocks = new ArrayList<> ();
2015-06-01 09:35:51 +00:00
2017-05-08 01:46:28 +00:00
switch (storageType)
2015-06-01 09:35:51 +00:00
{
2017-05-12 10:42:20 +00:00
case SEEDLING:
2018-07-25 05:48:14 +00:00
if (isValid (keyPtr))
2018-07-23 00:36:59 +00:00
blocks.add (keyPtr);
2017-05-08 01:46:28 +00:00
break;
2017-05-12 10:42:20 +00:00
case SAPLING:
2018-07-25 05:48:14 +00:00
if (isValid (keyPtr))
2018-07-23 00:36:59 +00:00
blocks.addAll (readIndex (keyPtr));
2017-05-08 01:46:28 +00:00
break;
2017-05-12 10:42:20 +00:00
case TREE:
2018-07-25 05:48:14 +00:00
if (isValid (keyPtr))
2018-07-23 00:36:59 +00:00
for (Integer indexBlock : readMasterIndex (keyPtr))
2018-07-25 05:48:14 +00:00
if (isValid (indexBlock))
2018-07-23 00:36:59 +00:00
blocks.addAll (readIndex (indexBlock));
2015-06-01 09:35:51 +00:00
break;
}
2017-03-14 04:50:23 +00:00
2017-05-08 01:46:28 +00:00
// remove trailing empty blocks
while (blocks.size () > 0 && blocks.get (blocks.size () - 1) == 0)
blocks.remove (blocks.size () - 1);
for (Integer block : blocks)
2015-06-01 09:35:51 +00:00
{
2017-05-08 01:46:28 +00:00
if (block == 0)
dataBlocks.add (emptyDiskAddress);
2015-06-01 09:35:51 +00:00
else
{
2017-05-08 01:46:28 +00:00
parentDisk.setSectorType (block, parentDisk.dataSector);
2017-05-12 10:42:20 +00:00
dataBlocks.add (disk.getDiskAddress (block));
2015-06-01 09:35:51 +00:00
}
}
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2017-05-08 01:46:28 +00:00
private List<Integer> readIndex (int blockPtr)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2017-03-14 04:50:23 +00:00
{
2019-11-03 05:49:01 +00:00
List<Integer> blocks = new ArrayList<> (256);
2017-03-14 04:50:23 +00:00
2017-05-08 01:46:28 +00:00
if (blockPtr == 0) // master index contains a zero
for (int i = 0; i < 256; i++)
blocks.add (0);
else
{
parentDisk.setSectorType (blockPtr, parentDisk.indexSector);
indexBlocks.add (disk.getDiskAddress (blockPtr));
2017-05-12 10:42:20 +00:00
byte[] buffer = disk.readSector (blockPtr);
for (int i = 0; i < 256; i++)
2018-07-22 20:52:41 +00:00
{
int blockNo = (buffer[i] & 0xFF) | ((buffer[i + 0x100] & 0xFF) << 8);
2018-07-25 05:48:14 +00:00
blocks.add (isValid (blockNo) ? blockNo : 0);
2018-07-22 20:52:41 +00:00
}
2017-03-14 04:50:23 +00:00
}
2017-05-08 01:46:28 +00:00
return blocks;
2017-03-14 04:50:23 +00:00
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2018-08-18 07:56:54 +00:00
private List<Integer> readMasterIndex (int keyPtr)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
2018-08-18 07:56:54 +00:00
masterIndexBlock = disk.getDiskAddress (keyPtr);
parentDisk.setSectorType (keyPtr, parentDisk.masterIndexSector);
indexBlocks.add (disk.getDiskAddress (keyPtr));
2017-01-26 23:59:47 +00:00
2018-08-18 07:56:54 +00:00
byte[] buffer = disk.readSector (keyPtr); // master index
2017-05-12 10:42:20 +00:00
int highest = 0x80;
2018-08-18 07:56:54 +00:00
while (highest-- > 0) // decrement after test
2017-05-12 10:42:20 +00:00
if (buffer[highest] != 0 || buffer[highest + 0x100] != 0)
2015-06-01 09:35:51 +00:00
break;
2017-01-26 23:59:47 +00:00
2019-11-03 05:49:01 +00:00
List<Integer> blocks = new ArrayList<> (highest + 1);
2017-05-12 10:42:20 +00:00
for (int i = 0; i <= highest; i++)
2018-07-22 20:52:41 +00:00
{
int blockNo = (buffer[i] & 0xFF) | ((buffer[i + 256] & 0xFF) << 8);
2018-07-25 05:48:14 +00:00
blocks.add (isValid (blockNo) ? blockNo : 0);
2018-07-22 20:52:41 +00:00
}
2017-01-26 23:59:47 +00:00
2017-05-08 01:46:28 +00:00
return blocks;
2015-06-01 09:35:51 +00:00
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2018-07-25 05:48:14 +00:00
private boolean isValid (int blockNo)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2018-07-25 05:48:14 +00:00
{
2018-08-02 22:13:49 +00:00
if (false)
2018-07-25 05:48:14 +00:00
{
if (!disk.isValidAddress (blockNo))
2018-08-02 22:13:49 +00:00
System.out.println ("--Invalid Block Address: " + blockNo);
2018-07-25 05:48:14 +00:00
if (parentDisk.isSectorFree (blockNo))
System.out.println ("--Free block: " + blockNo);
}
return disk.isValidAddress (blockNo) && !parentDisk.isSectorFree (blockNo);
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
@Override
public DataSource getDataSource ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
if (file != null)
return file;
2017-01-26 23:59:47 +00:00
2015-06-01 09:35:51 +00:00
if (invalid)
{
file = new DefaultAppleFile (name, null);
return file;
}
2017-01-26 23:59:47 +00:00
2017-02-01 21:15:30 +00:00
if (fileType == FILE_TYPE_TEXT && auxType > 0) // random access file
return getRandomAccessTextFile ();
2015-06-01 09:35:51 +00:00
2018-07-22 20:52:41 +00:00
byte[] buffer = getBuffer ();
2015-06-01 09:35:51 +00:00
byte[] exactBuffer = getExactBuffer (buffer);
try
{
switch (fileType)
{
2019-08-03 07:32:36 +00:00
case FILE_TYPE_USER_DEFINED_1: // OVL
if (endOfFile == 0x2000 && auxType == 0)
{
file = new OriginalHiResImage (name, exactBuffer, auxType);
break;
}
// drop through
2015-06-01 09:35:51 +00:00
case FILE_TYPE_BINARY:
case FILE_TYPE_RELOCATABLE:
case FILE_TYPE_SYS:
2018-04-25 23:07:23 +00:00
case FILE_TYPE_BAT:
2018-07-25 05:48:14 +00:00
if (SimpleText.isHTML (exactBuffer))
2015-06-01 09:35:51 +00:00
file = new SimpleText (name, exactBuffer);
2017-01-25 05:26:37 +00:00
else if (HiResImage.isGif (exactBuffer) || HiResImage.isPng (exactBuffer))
file = new OriginalHiResImage (name, exactBuffer, auxType);
else if (name.endsWith (".BMP") && HiResImage.isBmp (exactBuffer))
2016-12-31 09:34:15 +00:00
file = new OriginalHiResImage (name, exactBuffer, auxType);
2018-07-28 12:00:02 +00:00
else if (name.endsWith (".3200")) // $C1/02
file = new SHRPictureFile2 (name, exactBuffer, 0xC1, 0x02, endOfFile);
2018-08-02 22:13:49 +00:00
else if (name.endsWith (".3201") || HiResImage.isAPP (exactBuffer)) // $C0/04
// I made up aux=99 to test it without stepping on aux==04
2018-08-01 07:23:12 +00:00
file = new SHRPictureFile2 (name, exactBuffer, 0xC0, 99, endOfFile);
2017-07-28 05:41:38 +00:00
else if (name.endsWith (".FNT") && FontFile.isFont (exactBuffer))
2019-11-01 06:39:23 +00:00
file = new FontFile (name, exactBuffer, auxType);
2019-11-01 03:30:19 +00:00
else if (name.endsWith (".FONT") && FontFile.isFont (exactBuffer))
2019-11-01 06:39:23 +00:00
file = new FontFile (name, exactBuffer, auxType);
2018-07-25 05:48:14 +00:00
else if (ShapeTable.isShapeTable (exactBuffer))
file = new ShapeTable (name, exactBuffer);
2016-12-31 09:34:15 +00:00
else if (link != null)
{
if (name.endsWith (".AUX"))
file = new DoubleHiResImage (name, link.getBuffer (), exactBuffer);
else
file = new DoubleHiResImage (name, exactBuffer, link.getBuffer ());
}
2018-07-23 04:44:16 +00:00
else if (name.endsWith (".PAC") || name.endsWith (".A2FC")
|| (endOfFile == 0x4000 && auxType == 0x2000))
2017-01-08 23:36:10 +00:00
file = new DoubleHiResImage (name, exactBuffer);
2019-08-01 21:51:58 +00:00
else if (endOfFile == 0x4000 && auxType == 0x4000)
file = new DoubleHiResImage (name, exactBuffer);
2018-07-25 05:48:14 +00:00
else if (oneOf (endOfFile, 0x1FF8, 0x1FFF, 0x2000, 0x4000)
2019-09-13 05:32:35 +00:00
&& oneOf (auxType, 0x1FFF, 0x2000, 0x4000, 0x6000))
2016-12-31 09:34:15 +00:00
file = new OriginalHiResImage (name, exactBuffer, auxType);
2015-06-01 09:35:51 +00:00
else if (endOfFile == 38400 && name.startsWith ("LVL."))
file = new LodeRunner (name, exactBuffer);
2019-11-03 05:49:01 +00:00
else if (auxType == 0x1000 && CharacterRom.isRom (exactBuffer))
2018-08-18 03:24:22 +00:00
file = new CharacterRom (name, exactBuffer);
2019-08-10 11:14:26 +00:00
else if (auxType == 0 && endOfFile == 0x8000)
{
// see gs basic disk, one of the four pictures looks ok
file = new SHRPictureFile2 (name, exactBuffer, 0xC1, 0, endOfFile);
}
2015-06-01 09:35:51 +00:00
else
2016-02-05 00:23:53 +00:00
{
2015-06-01 09:35:51 +00:00
file = new AssemblerProgram (name, exactBuffer, auxType);
2016-02-05 00:23:53 +00:00
if (exactBuffer.length < buffer.length)
2016-12-12 07:43:19 +00:00
((AssemblerProgram) file).setExtraBuffer (buffer, exactBuffer.length,
buffer.length - exactBuffer.length);
2016-02-05 00:23:53 +00:00
}
2015-06-01 09:35:51 +00:00
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_TEXT:
2016-12-31 09:34:15 +00:00
assert auxType == 0; // auxType > 0 handled above
2015-06-01 09:35:51 +00:00
if (name.endsWith (".S"))
file = new MerlinSource (name, exactBuffer, auxType, endOfFile);
2019-08-15 07:02:40 +00:00
else if (name.endsWith ("PLA"))
file = new SimpleText (name, exactBuffer);
2018-07-31 07:02:19 +00:00
else if (name.endsWith (".GIF") && HiResImage.isGif (exactBuffer))
file = new OriginalHiResImage (name, exactBuffer, auxType);
2015-06-01 09:35:51 +00:00
else
file = new TextFile (name, exactBuffer, auxType, endOfFile);
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_APPLESOFT_BASIC:
2019-08-09 23:45:49 +00:00
file = new ApplesoftBasicProgram (name, exactBuffer);
break;
case FILE_TYPE_GS_BASIC:
file = new BasicProgramGS (name, exactBuffer);
2015-06-01 09:35:51 +00:00
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_INTEGER_BASIC:
file = new IntegerBasicProgram (name, exactBuffer);
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_DIRECTORY:
2019-11-03 05:49:01 +00:00
VolumeDirectoryHeader vdh = parentDisk.getVolumeDirectoryHeader ();
2016-02-05 00:23:53 +00:00
file = new ProdosDirectory (parentDisk, name, buffer, vdh.totalBlocks,
vdh.freeBlocks, vdh.usedBlocks);
2015-06-01 09:35:51 +00:00
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_APPLESOFT_BASIC_VARS:
if (endOfFile == 0)
{
System.out.println ("Stored Variables EOF = 0");
file = new StoredVariables (name, buffer);
}
else
file = new StoredVariables (name, exactBuffer);
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_APPLETALK:
file = new DefaultAppleFile (name + " (Appletalk file)", buffer);
break;
2017-07-28 05:41:38 +00:00
2017-01-17 00:00:51 +00:00
case FILE_TYPE_GWP:
2017-01-24 21:59:50 +00:00
file = new SimpleText (name, exactBuffer);
2017-01-17 00:00:51 +00:00
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_AWP:
file = new AppleworksWPFile (name + " (Appleworks Word Processor)", buffer);
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_ADB:
file = new AppleworksADBFile (name + " (Appleworks Database File)", buffer);
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_ASP:
file = new AppleworksSSFile (name + " (Appleworks Spreadsheet File)", buffer);
break;
2017-07-28 05:41:38 +00:00
2017-01-20 04:07:08 +00:00
case FILE_TYPE_IIGS_SOURCE: // I think this has a resource fork
2015-06-01 09:35:51 +00:00
file = new SimpleText (name, exactBuffer);
break;
2017-07-28 05:41:38 +00:00
2017-01-20 04:07:08 +00:00
case FILE_TYPE_IIGS_APPLICATION:
file = new AssemblerProgram (name, buffer, auxType);
break;
2017-07-28 05:41:38 +00:00
2017-01-22 06:55:51 +00:00
case FILE_TYPE_IIGS_DEVICE_DRIVER:
file = new DeviceDriver (name, exactBuffer, auxType);
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_ICN:
file = new IconFile (name, exactBuffer);
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_PNT:
2017-01-26 11:30:16 +00:00
if (auxType == 2)
2018-07-25 05:48:14 +00:00
file = new SHRPictureFile1 (name, exactBuffer, fileType, auxType, endOfFile);
2019-11-09 13:23:30 +00:00
else if (endOfFile < 0x222)
file = new DefaultAppleFile (name, exactBuffer);
2017-01-24 08:59:40 +00:00
else
2017-01-26 11:30:16 +00:00
file = new SHRPictureFile2 (name, exactBuffer, fileType, auxType, endOfFile);
2015-06-01 09:35:51 +00:00
break;
2017-07-28 05:41:38 +00:00
2015-06-01 09:35:51 +00:00
case FILE_TYPE_PIC:
2017-01-26 04:19:23 +00:00
file = new SHRPictureFile2 (name, exactBuffer, fileType, auxType, endOfFile);
2015-06-01 09:35:51 +00:00
break;
2017-07-28 05:41:38 +00:00
2018-08-15 02:32:11 +00:00
case FILE_TYPE_FOT:
if (auxType == 0x8066) // Fadden
file = new FaddenHiResImage (name, exactBuffer, fileType, auxType, endOfFile);
else
2018-08-17 11:46:47 +00:00
{
System.out.println ("Unwritten FOT: " + name);
2018-08-15 02:32:11 +00:00
file = new DefaultAppleFile (name, exactBuffer);
2018-08-17 11:46:47 +00:00
}
2018-07-25 05:48:14 +00:00
break;
2019-06-02 10:46:51 +00:00
case FILE_TYPE_FNT:
2019-11-01 06:39:23 +00:00
file = new FontFile (name, exactBuffer, auxType);
2019-06-02 10:46:51 +00:00
break;
2017-01-17 00:00:51 +00:00
case FILE_TYPE_FONT:
file = new QuickDrawFont (name, exactBuffer, fileType, auxType);
break;
2017-07-28 05:41:38 +00:00
2017-01-22 00:01:15 +00:00
case FILE_TYPE_DESCRIPTOR_TABLE:
file = new FileTypeDescriptorTable (name, exactBuffer);
break;
2017-07-28 05:41:38 +00:00
2017-01-22 00:01:15 +00:00
case FILE_TYPE_GSOS_FILE_SYSTEM_TRANSLATOR:
file = new FileSystemTranslator (name, exactBuffer);
break;
2017-07-28 05:41:38 +00:00
2017-05-08 01:46:28 +00:00
case FILE_TYPE_FINDER:
2018-07-22 20:52:41 +00:00
case FILE_TYPE_PASCAL_VOLUME:
case FILE_TYPE_GEO:
2018-07-25 05:48:14 +00:00
case FILE_TYPE_LDF:
2018-07-28 12:00:02 +00:00
case FILE_TYPE_ANI:
case FILE_TYPE_PAL:
2019-08-15 07:02:40 +00:00
case FILE_TYPE_IIGS_OBJECT:
2017-05-08 01:46:28 +00:00
file = new DefaultAppleFile (name, exactBuffer);
break;
2017-07-28 05:41:38 +00:00
2019-08-09 23:45:49 +00:00
case FILE_TYPE_NON:
if (name.endsWith (".TIFF") && HiResImage.isTiff (exactBuffer))
file = new OriginalHiResImage (name, exactBuffer, auxType);
else
file = new DefaultAppleFile (name, exactBuffer);
break;
2015-06-01 09:35:51 +00:00
default:
2019-08-15 07:02:40 +00:00
// System.out.format ("%02X %s %s - Unknown Prodos file type%n",
// fileType, fileTypes[fileType], name);
2017-01-20 04:07:08 +00:00
file = new DefaultAppleFile (name, exactBuffer);
2015-06-01 09:35:51 +00:00
}
}
catch (Exception e)
{
file = new ErrorMessageFile (name, buffer, e);
e.printStackTrace ();
}
return file;
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2018-07-25 05:48:14 +00:00
private boolean oneOf (int val, int... values)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
2018-07-25 05:48:14 +00:00
for (int value : values)
if (val == value)
return true;
return false;
}
2017-01-24 08:59:40 +00:00
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2018-07-25 05:48:14 +00:00
private byte[] getExactBuffer (byte[] buffer)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2018-07-25 05:48:14 +00:00
{
2015-06-01 09:35:51 +00:00
byte[] exactBuffer;
if (buffer.length < endOfFile)
{
2017-01-25 11:02:50 +00:00
exactBuffer = new byte[endOfFile];
2015-06-01 09:35:51 +00:00
System.arraycopy (buffer, 0, exactBuffer, 0, buffer.length);
}
2017-01-20 05:20:00 +00:00
else if (buffer.length == endOfFile || endOfFile == 512) // 512 seems like crap
2015-06-01 09:35:51 +00:00
exactBuffer = buffer;
else
{
exactBuffer = new byte[endOfFile];
System.arraycopy (buffer, 0, exactBuffer, 0, endOfFile);
}
return exactBuffer;
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2017-02-01 21:15:30 +00:00
private DataSource getRandomAccessTextFile ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2017-02-01 21:15:30 +00:00
{
2019-06-02 10:46:51 +00:00
// Text files with aux (reclen) > 0 are random access, possibly with
2017-02-01 21:15:30 +00:00
// non-contiguous records, so they need to be handled differently
switch (storageType)
{
2017-05-12 10:42:20 +00:00
case TREE:
2017-02-01 21:15:30 +00:00
return getTreeTextFile ();
2017-05-12 10:42:20 +00:00
case SAPLING:
2017-02-01 21:15:30 +00:00
return getSaplingTextFile ();
2017-05-12 10:42:20 +00:00
case SEEDLING:
2017-02-01 21:15:30 +00:00
return getSeedlingTextFile ();
default:
System.out.println ("Impossible: text file: " + storageType);
return null;
}
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
private DataSource getTreeTextFile ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
2019-11-01 03:30:19 +00:00
List<TextBuffer> buffers = new ArrayList<> ();
List<DiskAddress> addresses = new ArrayList<> ();
2015-06-01 09:35:51 +00:00
int logicalBlock = 0;
byte[] mainIndexBuffer = disk.readSector (keyPtr);
for (int i = 0; i < 256; i++)
{
2016-02-05 00:23:53 +00:00
int indexBlock =
HexFormatter.intValue (mainIndexBuffer[i], mainIndexBuffer[i + 256]);
2015-06-01 09:35:51 +00:00
if (indexBlock > 0)
logicalBlock = readIndexBlock (indexBlock, addresses, buffers, logicalBlock);
else
{
if (addresses.size () > 0)
{
byte[] tempBuffer = disk.readSectors (addresses);
2016-12-12 07:43:19 +00:00
buffers.add (
new TextBuffer (tempBuffer, auxType, logicalBlock - addresses.size ()));
2015-06-01 09:35:51 +00:00
addresses.clear ();
}
logicalBlock += 256;
}
}
if (buffers.size () == 1 && name.endsWith (".S"))
return new MerlinSource (name, buffers.get (0).buffer, auxType, endOfFile);
2017-01-26 23:59:47 +00:00
2015-06-01 09:35:51 +00:00
return new TextFile (name, buffers, auxType, endOfFile);
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
private DataSource getSaplingTextFile ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
2019-11-01 03:30:19 +00:00
List<TextBuffer> buffers = new ArrayList<> ();
List<DiskAddress> addresses = new ArrayList<> ();
2015-06-01 09:35:51 +00:00
readIndexBlock (keyPtr, addresses, buffers, 0);
2017-01-26 23:59:47 +00:00
2015-06-01 09:35:51 +00:00
if (buffers.size () == 1 && name.endsWith (".S"))
return new MerlinSource (name, buffers.get (0).buffer, auxType, endOfFile);
2017-01-26 23:59:47 +00:00
2015-06-01 09:35:51 +00:00
return new TextFile (name, buffers, auxType, endOfFile);
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
private DataSource getSeedlingTextFile ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
byte[] buffer = getBuffer ();
if (endOfFile < buffer.length)
{
byte[] exactBuffer = new byte[endOfFile];
System.arraycopy (buffer, 0, exactBuffer, 0, endOfFile);
buffer = exactBuffer;
}
2017-01-26 23:59:47 +00:00
2015-06-01 09:35:51 +00:00
if (name.endsWith (".S"))
return new MerlinSource (name, buffer, auxType, endOfFile);
2017-01-26 23:59:47 +00:00
2015-06-01 09:35:51 +00:00
return new TextFile (name, buffer, auxType, endOfFile);
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
private byte[] getBuffer ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
switch (storageType)
{
2017-05-12 10:42:20 +00:00
case SEEDLING:
case SAPLING:
case TREE:
2015-06-01 09:35:51 +00:00
return disk.readSectors (dataBlocks);
2017-02-01 21:15:30 +00:00
2017-05-12 10:42:20 +00:00
case SUBDIRECTORY:
2017-02-01 21:15:30 +00:00
byte[] fullBuffer = new byte[dataBlocks.size () * BLOCK_ENTRY_SIZE];
2015-06-01 09:35:51 +00:00
int offset = 0;
for (DiskAddress da : dataBlocks)
{
byte[] buffer = disk.readSector (da);
System.arraycopy (buffer, 4, fullBuffer, offset, BLOCK_ENTRY_SIZE);
offset += BLOCK_ENTRY_SIZE;
}
return fullBuffer;
2017-02-01 21:15:30 +00:00
2017-05-12 10:42:20 +00:00
case GSOS_EXTENDED_FILE:
2017-02-01 21:15:30 +00:00
return disk.readSectors (dataBlocks); // data and resource forks concatenated
2017-05-12 10:42:20 +00:00
case PASCAL_ON_PROFILE:
2017-04-22 06:31:25 +00:00
return disk.readSectors (dataBlocks);
2015-06-01 09:35:51 +00:00
default:
System.out.println ("Unknown storage type in getBuffer : " + storageType);
return new byte[512];
}
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
private int readIndexBlock (int indexBlock, List<DiskAddress> addresses,
2016-02-05 00:23:53 +00:00
List<TextBuffer> buffers, int logicalBlock)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
byte[] indexBuffer = disk.readSector (indexBlock);
for (int j = 0; j < 256; j++)
{
int block = HexFormatter.intValue (indexBuffer[j], indexBuffer[j + 256]);
if (block > 0)
addresses.add (disk.getDiskAddress (block));
else if (addresses.size () > 0)
{
byte[] tempBuffer = disk.readSectors (addresses);
2016-02-05 00:23:53 +00:00
buffers
.add (new TextBuffer (tempBuffer, auxType, logicalBlock - addresses.size ()));
2015-06-01 09:35:51 +00:00
addresses.clear ();
}
logicalBlock++;
}
2019-11-03 05:49:01 +00:00
2015-06-01 09:35:51 +00:00
return logicalBlock;
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
@Override
public List<DiskAddress> getSectors ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
2019-11-01 03:30:19 +00:00
List<DiskAddress> sectors = new ArrayList<> ();
2015-06-01 09:35:51 +00:00
sectors.add (catalogBlock);
if (masterIndexBlock != null)
sectors.add (masterIndexBlock);
sectors.addAll (indexBlocks);
sectors.addAll (dataBlocks);
2019-11-03 05:49:01 +00:00
2015-06-01 09:35:51 +00:00
return sectors;
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2016-02-28 07:17:58 +00:00
@Override
2015-06-01 09:35:51 +00:00
public boolean contains (DiskAddress da)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
2017-01-27 07:11:00 +00:00
if (da == null)
return false;
2015-06-01 09:35:51 +00:00
if (da.equals (masterIndexBlock))
return true;
for (DiskAddress block : indexBlocks)
2017-01-27 07:11:00 +00:00
if (da.matches (block))
2015-06-01 09:35:51 +00:00
return true;
for (DiskAddress block : dataBlocks)
2017-01-27 07:11:00 +00:00
if (da.matches (block))
2015-06-01 09:35:51 +00:00
return true;
2019-11-03 05:49:01 +00:00
2015-06-01 09:35:51 +00:00
return false;
}
2019-11-03 05:49:01 +00:00
// called from ProdosDisk.processDirectoryBlock, used to link DoubleHires image files
// ---------------------------------------------------------------------------------//
2016-12-31 09:34:15 +00:00
void link (FileEntry fileEntry)
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2016-12-31 09:34:15 +00:00
{
this.link = fileEntry;
}
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
@Override
public String toString ()
2019-11-03 05:49:01 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
if (ProdosConstants.fileTypes[fileType].equals ("DIR"))
return name;
2019-11-03 05:49:01 +00:00
2015-06-01 09:35:51 +00:00
String locked = (access == 0x00) ? "*" : " ";
2018-08-15 02:32:11 +00:00
2015-06-01 09:35:51 +00:00
if (true)
2016-02-05 00:23:53 +00:00
return String.format ("%s %03d %s", ProdosConstants.fileTypes[fileType],
2016-12-12 07:43:19 +00:00
blocksUsed, locked) + name;
2018-08-15 02:32:11 +00:00
2016-03-24 00:17:09 +00:00
String timeC = created == null ? "" : parentDisk.df.format (created.getTime ());
String timeF = modified == null ? "" : parentDisk.df.format (modified.getTime ());
2015-06-01 09:35:51 +00:00
return String.format ("%s %s%-30s %3d %,10d %15s %15s",
2016-12-12 07:43:19 +00:00
ProdosConstants.fileTypes[fileType], locked, parentDirectory.name + "/" + name,
blocksUsed, endOfFile, timeC, timeF);
2015-06-01 09:35:51 +00:00
}
}