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);
|
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),
|
* Get the key pointer. This is either the data block (seedling),
|
||||||
* index block (sapling), or master index block (tree).
|
* index block (sapling), or master index block (tree).
|
||||||
@ -499,6 +507,15 @@ public class ProdosFileEntry extends ProdosCommonEntry implements FileEntry {
|
|||||||
getDisk().setFileData(this, data);
|
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
|
* Get the suggested FileFilter. This appears to be operating system
|
||||||
* specific, so each operating system needs to implement some manner
|
* 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
|
* Set the data associated with the specified ProdosFileEntry into sectors
|
||||||
* on the disk. Take GEOS file structures into account.
|
* 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()
|
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
|
||||||
*/
|
*/
|
||||||
public DirectoryEntry createDirectory() throws DiskFullException {
|
public DirectoryEntry createDirectory() throws DiskFullException {
|
||||||
|
System.out.println("What?!?");
|
||||||
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
|
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,11 @@ public class Utilities
|
|||||||
ImageOrder imageOrder = new ProdosOrder(layout);
|
ImageOrder imageOrder = new ProdosOrder(layout);
|
||||||
FormattedDisk[] disks = ProdosFormatDisk.create(fileName, "APPLECOMMANDER", imageOrder);
|
FormattedDisk[] disks = ProdosFormatDisk.create(fileName, "APPLECOMMANDER", imageOrder);
|
||||||
ProdosFormatDisk pdDisk = (ProdosFormatDisk)disks[0];
|
ProdosFormatDisk pdDisk = (ProdosFormatDisk)disks[0];
|
||||||
|
ThreadRecord dataFork, resourceFork;
|
||||||
for (HeaderBlock b : a.getHeaderBlocks()) {
|
for (HeaderBlock b : a.getHeaderBlocks()) {
|
||||||
ProdosFileEntry newFile = null;
|
ProdosFileEntry newFile = null;
|
||||||
|
dataFork = null;
|
||||||
|
resourceFork = null;
|
||||||
for (ThreadRecord r : b.getThreadRecords()) {
|
for (ThreadRecord r : b.getThreadRecords()) {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -83,19 +86,19 @@ public class Utilities
|
|||||||
break;
|
break;
|
||||||
case DATA_FORK:
|
case DATA_FORK:
|
||||||
// This is a normal-ish file
|
// This is a normal-ish file
|
||||||
newFile = (ProdosFileEntry) pdDisk.createFile();
|
dataFork = r;
|
||||||
if (newFile != null) {
|
|
||||||
newFile.setFileData(readThread(r));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case DISK_IMAGE:
|
case DISK_IMAGE:
|
||||||
dmgBuffer = readThread(r);
|
dmgBuffer = readThread(r);
|
||||||
break;
|
break;
|
||||||
case RESOURCE_FORK:
|
case RESOURCE_FORK:
|
||||||
|
// This is a resource fork - we're talking GSOS FST here
|
||||||
|
resourceFork = r;
|
||||||
break;
|
break;
|
||||||
case FILENAME:
|
case FILENAME:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
System.out.println("ERRR, What?");
|
||||||
// Hmmm, this should not occur - but let us not fret about it.
|
// Hmmm, this should not occur - but let us not fret about it.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -105,13 +108,29 @@ public class Utilities
|
|||||||
System.out.println(ex);
|
System.out.println(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (newFile != null) {
|
try
|
||||||
newFile.setFilename(b.getFilename());
|
{
|
||||||
newFile.setFiletype(b.getFileType());
|
if (dataFork != null) {
|
||||||
newFile.setAuxiliaryType((int)b.getExtraType());
|
newFile = (ProdosFileEntry) pdDisk.createFile();
|
||||||
newFile.setCreationDate(b.getCreateWhen());
|
if (newFile != null) {
|
||||||
newFile.setLastModificationDate(b.getModWhen());
|
if (resourceFork != null) {
|
||||||
newFile = 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());
|
||||||
|
newFile.setCreationDate(b.getCreateWhen());
|
||||||
|
newFile.setLastModificationDate(b.getModWhen());
|
||||||
|
newFile = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.out.println(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dmgBuffer != null)
|
if (dmgBuffer != null)
|
||||||
|
Loading…
Reference in New Issue
Block a user