mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2025-01-02 19:29:17 +00:00
Add file-put and delete capabilities for GEOS files
This commit is contained in:
parent
394381f561
commit
199b36d5a6
@ -122,9 +122,14 @@ public class ProdosFileEntry extends ProdosCommonEntry implements FileEntry {
|
||||
byte[] fileEntry = readFileEntry();
|
||||
if (isDeleted()) {
|
||||
AppleUtil.setString(fileEntry, 1, filename.toUpperCase(), 15);
|
||||
} else {
|
||||
if (isGEOSFile()) {
|
||||
// No need to upper-case or be picky about GEOS filenames
|
||||
AppleUtil.setProdosString(fileEntry, 0, filename, 15);
|
||||
} else {
|
||||
AppleUtil.setProdosString(fileEntry, 0, filename.toUpperCase(), 15);
|
||||
}
|
||||
}
|
||||
if (isAppleWorksFile()) {
|
||||
byte lowByte = 0;
|
||||
byte highByte = 0;
|
||||
@ -173,6 +178,14 @@ public class ProdosFileEntry extends ProdosCommonEntry implements FileEntry {
|
||||
return (filetype == 0x19 || filetype == 0x1a || filetype == 0x1b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if this is a GEOS file.
|
||||
*/
|
||||
public boolean isGEOSFile() {
|
||||
int filetype = AppleUtil.getUnsignedByte(readFileEntry()[0x10]);
|
||||
return (filetype >= 0x80 && filetype <= 0x8f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key pointer. This is either the data block (seedling),
|
||||
* index block (sapling), or master index block (tree).
|
||||
|
@ -73,6 +73,25 @@ filetype.6e=PRE
|
||||
# PC Volume
|
||||
filetype.6f=HDV
|
||||
|
||||
# GEOS
|
||||
# $80-$8F ($82 for a GEOS 'application').
|
||||
filetype.80=GEZ
|
||||
filetype.81=GE1
|
||||
filetype.82=GEO
|
||||
filetype.83=GE3
|
||||
filetype.84=GE4
|
||||
filetype.85=GE5
|
||||
filetype.86=GE6
|
||||
filetype.87=GE7
|
||||
filetype.88=GE8
|
||||
filetype.89=GE9
|
||||
filetype.8a=GEA
|
||||
filetype.8b=GEB
|
||||
filetype.8c=GEC
|
||||
filetype.8d=GED
|
||||
filetype.8e=GEE
|
||||
filetype.8f=GEF
|
||||
|
||||
filetype.a0=WP_
|
||||
filetype.ab=GSB
|
||||
filetype.ac=TDF
|
||||
|
@ -551,21 +551,31 @@ public class ProdosFormatDisk extends FormattedDisk {
|
||||
}
|
||||
|
||||
/**
|
||||
* Free blocks used by a DosFileEntry.
|
||||
* Free blocks used by a ProdosFileEntry.
|
||||
*/
|
||||
protected void freeBlocks(ProdosFileEntry prodosFileEntry) {
|
||||
byte[] bitmap = readVolumeBitMap();
|
||||
int block = prodosFileEntry.getKeyPointer();
|
||||
if (block == 0) return; // new entry
|
||||
if (prodosFileEntry.isGEOSFile()) {
|
||||
// A GEOS file allocates another block, pointed to by the aux bytes.
|
||||
setBlockFree(bitmap,prodosFileEntry.getAuxiliaryType());
|
||||
}
|
||||
setBlockFree(bitmap,block);
|
||||
if (prodosFileEntry.isSaplingFile()) {
|
||||
freeBlocksInIndex(bitmap,block);
|
||||
freeBlocksInIndex(bitmap,block,false);
|
||||
} else if (prodosFileEntry.isTreeFile()) {
|
||||
byte[] masterIndexBlock = readBlock(block);
|
||||
for (int i=0; i<0x100; i++) {
|
||||
if (!prodosFileEntry.isGEOSFile() ||
|
||||
(prodosFileEntry.isGEOSFile() && (i < 0xfe)))
|
||||
{
|
||||
// As long as we're not deleting a GEOS file, delete all index entries.
|
||||
// GEOS uses records 0xfe and 0xff for space calculations, not pointers.
|
||||
int indexBlockNumber = AppleUtil.getWordValue(
|
||||
masterIndexBlock[i], masterIndexBlock[i+0x100]);
|
||||
if (indexBlockNumber > 0) freeBlocksInIndex(bitmap,indexBlockNumber);
|
||||
if (indexBlockNumber > 0) freeBlocksInIndex(bitmap,indexBlockNumber,prodosFileEntry.isGEOSFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
writeVolumeBitMap(bitmap);
|
||||
@ -574,14 +584,19 @@ public class ProdosFormatDisk extends FormattedDisk {
|
||||
/**
|
||||
* Free the given index block and the data blocks it points to.
|
||||
*/
|
||||
private void freeBlocksInIndex(byte[] bitmap, int indexBlockNumber) {
|
||||
private void freeBlocksInIndex(byte[] bitmap, int indexBlockNumber, boolean isGEOS) {
|
||||
setBlockFree(bitmap, indexBlockNumber);
|
||||
byte[] indexBlock = readBlock(indexBlockNumber);
|
||||
for (int i=0; i<0x100; i++) {
|
||||
if (!isGEOS ||
|
||||
(isGEOS && (i < 0xfe))) {
|
||||
// As long as we're not deleting a GEOS file, delete all entries.
|
||||
// GEOS uses records 0xfe and 0xff for space calculations, not pointers.
|
||||
int blockNumber = AppleUtil.getWordValue(indexBlock[i], indexBlock[i+0x100]);
|
||||
if (blockNumber > 0) setBlockFree(bitmap, blockNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read file data from the given index block.
|
||||
@ -605,11 +620,16 @@ public class ProdosFormatDisk extends FormattedDisk {
|
||||
|
||||
/**
|
||||
* Set the data associated with the specified ProdosFileEntry into sectors
|
||||
* on the disk.
|
||||
* on the disk. Automatically grows the filesystem structures from seedling
|
||||
* to sapling to tree.
|
||||
*/
|
||||
protected void setFileData(ProdosFileEntry fileEntry, byte[] fileData)
|
||||
throws DiskFullException {
|
||||
|
||||
if (fileEntry.isGEOSFile()) {
|
||||
// If this is a GEOS file, things are a bit different.
|
||||
setGEOSFileData(fileEntry, fileData);
|
||||
} else {
|
||||
// compute free space and see if the data will fit!
|
||||
int numberOfDataBlocks = (fileData.length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||
int numberOfBlocks = numberOfDataBlocks;
|
||||
@ -697,6 +717,152 @@ public class ProdosFormatDisk extends FormattedDisk {
|
||||
fileEntry.setLastModificationDate(new Date());
|
||||
writeVolumeBitMap(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data associated with the specified ProdosFileEntry into sectors
|
||||
* on the disk. Take GEOS file structures into account.
|
||||
*/
|
||||
protected void setGEOSFileData(ProdosFileEntry fileEntry, byte[] fileData)
|
||||
throws DiskFullException {
|
||||
|
||||
// compute free space and see if the data will fit!
|
||||
int numberOfDataBlocks = (fileData.length - 1) / BLOCK_SIZE;
|
||||
int numberOfBlocks = numberOfDataBlocks;
|
||||
numberOfBlocks+= ((numberOfDataBlocks-1) / 254) + 1; // GEOS uses the last two blocks for eof calculations
|
||||
if (numberOfDataBlocks > 254) {
|
||||
numberOfBlocks++;
|
||||
}
|
||||
if (numberOfBlocks > getFreeBlocks() + fileEntry.getBlocksUsed()) {
|
||||
throw new DiskFullException(textBundle.
|
||||
format("ProdosFormatDisk.NotEnoughSpaceOnDiskError", //$NON-NLS-1$
|
||||
numberOfBlocks, getFreeBlocks()));
|
||||
}
|
||||
// free "old" data and just rewrite stuff...
|
||||
freeBlocks(fileEntry);
|
||||
byte[] bitmap = readVolumeBitMap();
|
||||
|
||||
// Place the first BLOCK_SIZE bytes of data in a block pointed to by the aux address.
|
||||
int headerBlockNumber = findFreeBlock(bitmap);
|
||||
byte[] headerData = new byte[BLOCK_SIZE];
|
||||
setBlockUsed(bitmap, headerBlockNumber);
|
||||
System.arraycopy(fileData,0,headerData,0,BLOCK_SIZE);
|
||||
writeBlock(headerBlockNumber, headerData);
|
||||
fileEntry.setAddress(headerBlockNumber);
|
||||
|
||||
if (AppleUtil.getUnsignedByte(fileData[0x180]) >> 4 == 2) {
|
||||
setGEOSSaplingData(bitmap, fileEntry, fileData);
|
||||
} else {
|
||||
setGEOSTreeData(bitmap, fileEntry, fileData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the GEOS "sapling" file data.
|
||||
*/
|
||||
protected void setGEOSSaplingData(byte[] bitmap, ProdosFileEntry fileEntry, byte[] fileData)
|
||||
throws DiskFullException {
|
||||
|
||||
int indexBlockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, indexBlockNumber);
|
||||
byte[] indexBlockData = new byte[BLOCK_SIZE];
|
||||
int offset = BLOCK_SIZE;
|
||||
int blockNumber = 0;
|
||||
int blockCount = 1; // The header block counts for one
|
||||
while (offset < fileData.length) {
|
||||
blockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, blockNumber);
|
||||
blockCount++;
|
||||
byte[] blockData = new byte[BLOCK_SIZE];
|
||||
int length = Math.min(BLOCK_SIZE, fileData.length - offset);
|
||||
System.arraycopy(fileData,offset,blockData,0,length);
|
||||
writeBlock(blockNumber, blockData);
|
||||
// record last block position in index block
|
||||
int position = ((offset - BLOCK_SIZE) / BLOCK_SIZE) % 256;
|
||||
byte low = (byte)(blockNumber % 256);
|
||||
byte high = (byte)(blockNumber / 256);
|
||||
indexBlockData[position] = low;
|
||||
indexBlockData[position + 0x100] = high;
|
||||
offset+= BLOCK_SIZE;
|
||||
}
|
||||
indexBlockData[255] = (byte)((fileData.length - BLOCK_SIZE) % 256); // Lo file eof
|
||||
indexBlockData[511] = (byte)((fileData.length - BLOCK_SIZE) / 256); // Med file eof
|
||||
writeBlock(indexBlockNumber, indexBlockData);
|
||||
fileEntry.setKeyPointer(indexBlockNumber);
|
||||
fileEntry.setSaplingFile();
|
||||
fileEntry.setBlocksUsed(blockCount);
|
||||
fileEntry.setEofPosition(fileData.length - BLOCK_SIZE);
|
||||
fileEntry.setLastModificationDate(new Date());
|
||||
writeVolumeBitMap(bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the GEOS "tree" file data.
|
||||
*/
|
||||
protected void setGEOSTreeData(byte[] bitmap, ProdosFileEntry fileEntry, byte[] fileData)
|
||||
throws DiskFullException {
|
||||
|
||||
int masterIndexBlockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, masterIndexBlockNumber);
|
||||
byte[] masterIndexBlockData = new byte[BLOCK_SIZE];
|
||||
int offset = BLOCK_SIZE;
|
||||
int blockCount = 2; // Start by counting the header block and master index
|
||||
int eofCount = 0;
|
||||
for (int masterIterator = 0; masterIterator < 254; masterIterator++) {
|
||||
if ((fileData[0x100+masterIterator] != 0xff) && (offset < fileData.length)){
|
||||
byte[] lengthData = new byte[BLOCK_SIZE];
|
||||
System.arraycopy(fileData,offset,lengthData,0,BLOCK_SIZE);
|
||||
offset += BLOCK_SIZE;
|
||||
int recordLength = AppleUtil.getUnsignedByte(lengthData[0xff])
|
||||
+ AppleUtil.getUnsignedByte(lengthData[0x1ff])*256;
|
||||
int indexBlockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, indexBlockNumber);
|
||||
blockCount +=1;
|
||||
byte[] indexBlockData = new byte[BLOCK_SIZE];
|
||||
int blockNumber = 0;
|
||||
int startingPoint = offset;
|
||||
while (offset < startingPoint + recordLength) {
|
||||
blockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, blockNumber);
|
||||
blockCount +=1;
|
||||
byte[] blockData = new byte[BLOCK_SIZE];
|
||||
int length = Math.min(BLOCK_SIZE, recordLength - offset + startingPoint);
|
||||
System.arraycopy(fileData,offset,blockData,0,length);
|
||||
writeBlock(blockNumber, blockData);
|
||||
eofCount += length;
|
||||
// record last block position in index block
|
||||
int position = ((offset-startingPoint) / BLOCK_SIZE) % 256;
|
||||
byte low = (byte)(blockNumber % 256);
|
||||
byte high = (byte)(blockNumber / 256);
|
||||
indexBlockData[position] = low;
|
||||
indexBlockData[position + 0x100] = high;
|
||||
offset+= BLOCK_SIZE;
|
||||
}
|
||||
indexBlockData[0xff] = (byte) (recordLength & 0x0000ff);
|
||||
indexBlockData[0x1ff] = (byte)((recordLength & 0x00ff00) >> 8);
|
||||
indexBlockData[0x1fe] = (byte)((recordLength & 0xff0000) >> 16);
|
||||
writeBlock(indexBlockNumber, indexBlockData);
|
||||
byte low = (byte)(indexBlockNumber % 256);
|
||||
byte high = (byte)(indexBlockNumber / 256);
|
||||
masterIndexBlockData[masterIterator] = low;
|
||||
masterIndexBlockData[masterIterator + 0x100] = high;
|
||||
|
||||
} else if (fileData[0x100+masterIterator] == 0xff) {
|
||||
masterIndexBlockData[masterIterator] = (byte)0xff;
|
||||
masterIndexBlockData[masterIterator+0x100] = (byte)0xff;
|
||||
}
|
||||
}
|
||||
masterIndexBlockData[0x0ff] = (byte) (eofCount & 0x0000ff);
|
||||
masterIndexBlockData[0x1ff] = (byte)((eofCount & 0x00ff00) >> 8);
|
||||
masterIndexBlockData[0x1fe] = (byte)((eofCount & 0xff0000) >> 16);
|
||||
writeBlock(masterIndexBlockNumber, masterIndexBlockData);
|
||||
fileEntry.setKeyPointer(masterIndexBlockNumber);
|
||||
fileEntry.setTreeFile();
|
||||
fileEntry.setBlocksUsed(blockCount);
|
||||
fileEntry.setEofPosition(eofCount);
|
||||
fileEntry.setLastModificationDate(new Date());
|
||||
writeVolumeBitMap(bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a free block in the Volume Bitmap.
|
||||
|
@ -151,8 +151,8 @@ public class ac {
|
||||
FormattedDisk formattedDisk = formattedDisks[0];
|
||||
FileEntry entry = name.createEntry(formattedDisk);
|
||||
if (entry != null) {
|
||||
entry.setFilename(name.name);
|
||||
entry.setFiletype(fileType);
|
||||
entry.setFilename(name.name);
|
||||
entry.setFileData(buf.toByteArray());
|
||||
if (entry.needsAddress()) {
|
||||
entry.setAddress(stringToInt(address));
|
||||
|
Loading…
Reference in New Issue
Block a user