mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2024-12-22 08:30:35 +00:00
Implement ProDOS filetype $05 for writing
This commit is contained in:
parent
437270ea95
commit
6c6be6622d
@ -207,6 +207,14 @@ public class ProdosFileEntry extends ProdosCommonEntry implements FileEntry {
|
||||
return (filetype >= 0x80 && filetype <= 0x8f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if this is a GEOS file.
|
||||
*/
|
||||
public boolean isForkedFile() {
|
||||
int storageType = AppleUtil.getUnsignedByte(readFileEntry()[0x00]);
|
||||
return ((storageType & 0x50) == 0x50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key pointer. This is either the data block (seedling),
|
||||
* index block (sapling), or master index block (tree).
|
||||
@ -499,6 +507,15 @@ public class ProdosFileEntry extends ProdosCommonEntry implements FileEntry {
|
||||
getDisk().setFileData(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file data, with the expectation that both data and resource forks
|
||||
* are present (storage type $05). See:
|
||||
* http://www.1000bit.it/support/manuali/apple/technotes/pdos/tn.pdos.25.html
|
||||
*/
|
||||
public void setFileData(byte[] dataFork, byte[] resourceFork) throws DiskFullException {
|
||||
getDisk().setFileData(this, dataFork, resourceFork);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the suggested FileFilter. This appears to be operating system
|
||||
* specific, so each operating system needs to implement some manner
|
||||
|
@ -719,6 +719,178 @@ public class ProdosFormatDisk extends FormattedDisk {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data associated with the specified ProdosFileEntry into sectors
|
||||
* on the disk. Automatically grows the filesystem structures from seedling
|
||||
* to sapling to tree.
|
||||
*/
|
||||
// TODO: the writing of a single fork can be factored out... it is very common to routines nearby.
|
||||
protected void setFileData(ProdosFileEntry fileEntry, byte[] dataFork, byte[] resourceFork)
|
||||
throws DiskFullException {
|
||||
|
||||
// compute free space and see if the data will fit!
|
||||
int numberOfDataBlocks = (dataFork.length + BLOCK_SIZE - 1) / BLOCK_SIZE +
|
||||
(resourceFork.length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||
int numberOfBlocks = numberOfDataBlocks;
|
||||
if (numberOfBlocks > 1) {
|
||||
numberOfBlocks+= ((numberOfDataBlocks-1) / 256) + 1; // that's 128K
|
||||
if (numberOfDataBlocks > 256) {
|
||||
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();
|
||||
int blockNumber = fileEntry.getKeyPointer();
|
||||
if (blockNumber == 0) {
|
||||
blockNumber = findFreeBlock(bitmap);
|
||||
}
|
||||
int blockCount = 0;
|
||||
int extendedKeyBlockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, extendedKeyBlockNumber);
|
||||
byte[] extendedKeyBlockData = new byte[BLOCK_SIZE];
|
||||
int indexBlockNumber = 0;
|
||||
byte[] indexBlockData = null;
|
||||
int masterIndexBlockNumber = 0;
|
||||
byte[] masterIndexBlockData = new byte[BLOCK_SIZE];
|
||||
|
||||
int offset = 0;
|
||||
numberOfDataBlocks = (dataFork.length + BLOCK_SIZE - 1) / BLOCK_SIZE ;
|
||||
while (offset < dataFork.length) {
|
||||
blockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, blockNumber);
|
||||
blockCount++;
|
||||
byte[] blockData = new byte[BLOCK_SIZE];
|
||||
int length = Math.min(BLOCK_SIZE, dataFork.length - offset);
|
||||
System.arraycopy(dataFork,offset,blockData,0,length);
|
||||
writeBlock(blockNumber, blockData);
|
||||
if (numberOfDataBlocks > 1) {
|
||||
// growing to a tree file
|
||||
if (offset > 0 && (offset / BLOCK_SIZE) % 256 == 0) {
|
||||
if (masterIndexBlockNumber == 0) {
|
||||
masterIndexBlockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, masterIndexBlockNumber);
|
||||
blockCount++;
|
||||
}
|
||||
writeBlock(indexBlockNumber, indexBlockData);
|
||||
indexBlockData = null;
|
||||
indexBlockNumber = 0;
|
||||
}
|
||||
// new index block
|
||||
if (indexBlockData == null) { // sapling files
|
||||
indexBlockNumber = findFreeBlock(bitmap);
|
||||
indexBlockData = new byte[BLOCK_SIZE];
|
||||
setBlockUsed(bitmap, indexBlockNumber);
|
||||
blockCount++;
|
||||
// This is only used for Tree files (but we always record it):
|
||||
int position = (offset / (BLOCK_SIZE * 256));
|
||||
byte low = (byte)(indexBlockNumber % 256);
|
||||
byte high = (byte)(indexBlockNumber / 256);
|
||||
masterIndexBlockData[position] = low;
|
||||
masterIndexBlockData[position + 0x100] = high;
|
||||
}
|
||||
// record last block position in index block
|
||||
int position = (offset / BLOCK_SIZE) % 256;
|
||||
byte low = (byte)(blockNumber % 256);
|
||||
byte high = (byte)(blockNumber / 256);
|
||||
indexBlockData[position] = low;
|
||||
indexBlockData[position + 0x100] = high;
|
||||
}
|
||||
offset+= BLOCK_SIZE;
|
||||
}
|
||||
AppleUtil.setWordValue(extendedKeyBlockData,0x03,numberOfDataBlocks); // Set the number of blocks used
|
||||
AppleUtil.set3ByteValue(extendedKeyBlockData,0x05, dataFork.length); // Set the number of bytes used
|
||||
if (numberOfDataBlocks == 1) {
|
||||
extendedKeyBlockData[0] = 1; // Set the seedling ProDOS storage type
|
||||
AppleUtil.setWordValue(extendedKeyBlockData,1,blockNumber); // Set the master block number
|
||||
} else if (numberOfDataBlocks <= 256) {
|
||||
writeBlock(indexBlockNumber, indexBlockData);
|
||||
AppleUtil.setWordValue(extendedKeyBlockData,1,indexBlockNumber); // Set the master block number
|
||||
extendedKeyBlockData[0] = 2; // Set the sapling ProDOS storage type
|
||||
} else {
|
||||
writeBlock(indexBlockNumber, indexBlockData);
|
||||
writeBlock(masterIndexBlockNumber, masterIndexBlockData);
|
||||
AppleUtil.setWordValue(extendedKeyBlockData,1,masterIndexBlockNumber); // Set the master block number
|
||||
extendedKeyBlockData[0] = 3; // Set the tree ProDOS storage type
|
||||
}
|
||||
blockCount++; // To account for extendedKeyBlock
|
||||
|
||||
offset = 0;
|
||||
indexBlockNumber = 0;
|
||||
indexBlockData = null;
|
||||
masterIndexBlockNumber = 0;
|
||||
numberOfDataBlocks = (resourceFork.length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||
while (offset < resourceFork.length) {
|
||||
if (blockCount > 0) blockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, blockNumber);
|
||||
blockCount++;
|
||||
byte[] blockData = new byte[BLOCK_SIZE];
|
||||
int length = Math.min(BLOCK_SIZE, resourceFork.length - offset);
|
||||
System.arraycopy(resourceFork,offset,blockData,0,length);
|
||||
writeBlock(blockNumber, blockData);
|
||||
if (numberOfDataBlocks > 1) {
|
||||
// growing to a tree file
|
||||
if (offset > 0 && (offset / BLOCK_SIZE) % 256 == 0) {
|
||||
if (masterIndexBlockNumber == 0) {
|
||||
masterIndexBlockNumber = findFreeBlock(bitmap);
|
||||
setBlockUsed(bitmap, masterIndexBlockNumber);
|
||||
blockCount++;
|
||||
}
|
||||
writeBlock(indexBlockNumber, indexBlockData);
|
||||
indexBlockData = null;
|
||||
indexBlockNumber = 0;
|
||||
}
|
||||
// new index block
|
||||
if (indexBlockData == null) { // sapling files
|
||||
indexBlockNumber = findFreeBlock(bitmap);
|
||||
indexBlockData = new byte[BLOCK_SIZE];
|
||||
setBlockUsed(bitmap, indexBlockNumber);
|
||||
blockCount++;
|
||||
// This is only used for Tree files (but we always record it):
|
||||
int position = (offset / (BLOCK_SIZE * 256));
|
||||
byte low = (byte)(indexBlockNumber % 256);
|
||||
byte high = (byte)(indexBlockNumber / 256);
|
||||
masterIndexBlockData[position] = low;
|
||||
masterIndexBlockData[position + 0x100] = high;
|
||||
}
|
||||
// record last block position in index block
|
||||
int position = (offset / BLOCK_SIZE) % 256;
|
||||
byte low = (byte)(blockNumber % 256);
|
||||
byte high = (byte)(blockNumber / 256);
|
||||
indexBlockData[position] = low;
|
||||
indexBlockData[position + 0x100] = high;
|
||||
}
|
||||
offset+= BLOCK_SIZE;
|
||||
}
|
||||
AppleUtil.setWordValue(extendedKeyBlockData,0x103,numberOfDataBlocks); // Set the number of blocks used
|
||||
AppleUtil.set3ByteValue(extendedKeyBlockData,0x105, resourceFork.length); // Set the number of bytes used
|
||||
if (numberOfDataBlocks == 1) {
|
||||
extendedKeyBlockData[0x100] = 1; // Set the seedling ProDOS storage type
|
||||
AppleUtil.setWordValue(extendedKeyBlockData,0x101,blockNumber); // Set the master block number
|
||||
} else if (numberOfDataBlocks <= 256) {
|
||||
writeBlock(indexBlockNumber, indexBlockData);
|
||||
AppleUtil.setWordValue(extendedKeyBlockData,0x101,indexBlockNumber); // Set the master block number
|
||||
extendedKeyBlockData[0x100] = 2; // Set the sapling ProDOS storage type
|
||||
} else {
|
||||
writeBlock(indexBlockNumber, indexBlockData);
|
||||
writeBlock(masterIndexBlockNumber, masterIndexBlockData);
|
||||
AppleUtil.setWordValue(extendedKeyBlockData,0x101,masterIndexBlockNumber); // Set the master block number
|
||||
extendedKeyBlockData[0x100] = 3; // Set the tree ProDOS storage type
|
||||
}
|
||||
writeBlock(extendedKeyBlockNumber, extendedKeyBlockData);
|
||||
|
||||
fileEntry.setKeyPointer(extendedKeyBlockNumber);
|
||||
fileEntry.setBlocksUsed(blockCount);
|
||||
fileEntry.setEofPosition(dataFork.length+resourceFork.length);
|
||||
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.
|
||||
@ -1153,6 +1325,7 @@ public class ProdosFormatDisk extends FormattedDisk {
|
||||
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
|
||||
*/
|
||||
public DirectoryEntry createDirectory() throws DiskFullException {
|
||||
System.out.println("What?!?");
|
||||
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
@ -67,8 +67,11 @@ public class Utilities
|
||||
ImageOrder imageOrder = new ProdosOrder(layout);
|
||||
FormattedDisk[] disks = ProdosFormatDisk.create(fileName, "APPLECOMMANDER", imageOrder);
|
||||
ProdosFormatDisk pdDisk = (ProdosFormatDisk)disks[0];
|
||||
ThreadRecord dataFork, resourceFork;
|
||||
for (HeaderBlock b : a.getHeaderBlocks()) {
|
||||
ProdosFileEntry newFile = null;
|
||||
dataFork = null;
|
||||
resourceFork = null;
|
||||
for (ThreadRecord r : b.getThreadRecords()) {
|
||||
try
|
||||
{
|
||||
@ -83,19 +86,19 @@ public class Utilities
|
||||
break;
|
||||
case DATA_FORK:
|
||||
// This is a normal-ish file
|
||||
newFile = (ProdosFileEntry) pdDisk.createFile();
|
||||
if (newFile != null) {
|
||||
newFile.setFileData(readThread(r));
|
||||
}
|
||||
dataFork = r;
|
||||
break;
|
||||
case DISK_IMAGE:
|
||||
dmgBuffer = readThread(r);
|
||||
break;
|
||||
case RESOURCE_FORK:
|
||||
// This is a resource fork - we're talking GSOS FST here
|
||||
resourceFork = r;
|
||||
break;
|
||||
case FILENAME:
|
||||
break;
|
||||
default:
|
||||
System.out.println("ERRR, What?");
|
||||
// Hmmm, this should not occur - but let us not fret about it.
|
||||
break;
|
||||
}
|
||||
@ -105,7 +108,17 @@ public class Utilities
|
||||
System.out.println(ex);
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
if (dataFork != null) {
|
||||
newFile = (ProdosFileEntry) pdDisk.createFile();
|
||||
if (newFile != null) {
|
||||
if (resourceFork != null) {
|
||||
newFile.setFileData(readThread(dataFork),readThread(resourceFork));
|
||||
newFile.setStorageType(0x05);
|
||||
} else {
|
||||
newFile.setFileData(readThread(dataFork));
|
||||
}
|
||||
newFile.setFilename(b.getFilename());
|
||||
newFile.setFiletype(b.getFileType());
|
||||
newFile.setAuxiliaryType((int)b.getExtraType());
|
||||
@ -114,6 +127,12 @@ public class Utilities
|
||||
newFile = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.out.println(ex);
|
||||
}
|
||||
}
|
||||
if (dmgBuffer != null)
|
||||
return dmgBuffer;
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user