mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2024-12-22 23:29:34 +00:00
Added support for writing files.
This commit is contained in:
parent
9a4bfbe118
commit
ae9ec0f016
@ -93,6 +93,47 @@ public class ProdosFormatDisk extends FormattedDisk {
|
|||||||
return "ProDOS";
|
return "ProDOS";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a FileEntry in the Volume Directory.
|
||||||
|
*/
|
||||||
|
public FileEntry createFile() throws DiskFullException {
|
||||||
|
return createFile(volumeHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a FileEntry in the given directory.
|
||||||
|
*/
|
||||||
|
public FileEntry createFile(ProdosCommonDirectoryHeader directory)
|
||||||
|
throws DiskFullException {
|
||||||
|
|
||||||
|
int blockNumber = directory.getFileEntryBlock();
|
||||||
|
while (blockNumber != 0) {
|
||||||
|
byte[] block = readBlock(blockNumber);
|
||||||
|
int offset = 4;
|
||||||
|
while (offset+ProdosCommonEntry.ENTRY_LENGTH < BLOCK_SIZE) {
|
||||||
|
int value = AppleUtil.getUnsignedByte(block[offset]);
|
||||||
|
if (value == 0) {
|
||||||
|
ProdosFileEntry fileEntry =
|
||||||
|
new ProdosFileEntry(this, blockNumber, offset);
|
||||||
|
fileEntry.setCreationDate(new Date());
|
||||||
|
fileEntry.setProdosVersion(0);
|
||||||
|
fileEntry.setMinimumProdosVersion(0);
|
||||||
|
fileEntry.setCanDestroy(true);
|
||||||
|
fileEntry.setCanRead(true);
|
||||||
|
fileEntry.setCanRename(true);
|
||||||
|
fileEntry.setCanWrite(true);
|
||||||
|
fileEntry.setSaplingFile();
|
||||||
|
fileEntry.setFilename("BLANK");
|
||||||
|
directory.incrementFileCount();
|
||||||
|
return fileEntry;
|
||||||
|
}
|
||||||
|
offset+= ProdosCommonEntry.ENTRY_LENGTH;
|
||||||
|
}
|
||||||
|
blockNumber = AppleUtil.getWordValue(block, 2);
|
||||||
|
}
|
||||||
|
throw new DiskFullException("Unable to allocate more space for another file!");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a list of files.
|
* Retrieve a list of files.
|
||||||
* @see com.webcodepro.applecommander.storage.Disk#getFiles()
|
* @see com.webcodepro.applecommander.storage.Disk#getFiles()
|
||||||
@ -310,21 +351,21 @@ public class ProdosFormatDisk extends FormattedDisk {
|
|||||||
* Indicates if this disk image can write data to a file.
|
* Indicates if this disk image can write data to a file.
|
||||||
*/
|
*/
|
||||||
public boolean canWriteFileData() {
|
public boolean canWriteFileData() {
|
||||||
return false; // FIXME - not implemented
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if this disk image can create a file.
|
* Indicates if this disk image can create a file.
|
||||||
*/
|
*/
|
||||||
public boolean canCreateFile() {
|
public boolean canCreateFile() {
|
||||||
return false; // FIXME - not implemented
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if this disk image can delete a file.
|
* Indicates if this disk image can delete a file.
|
||||||
*/
|
*/
|
||||||
public boolean canDeleteFile() {
|
public boolean canDeleteFile() {
|
||||||
return false; // FIXME - not implemented
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -358,6 +399,41 @@ public class ProdosFormatDisk extends FormattedDisk {
|
|||||||
return fileData;
|
return fileData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free blocks used by a DosFileEntry.
|
||||||
|
*/
|
||||||
|
protected void freeBlocks(ProdosFileEntry prodosFileEntry) {
|
||||||
|
byte[] bitmap = readVolumeBitMap();
|
||||||
|
int block = prodosFileEntry.getKeyPointer();
|
||||||
|
if (block == 0) return; // new entry
|
||||||
|
setBlockFree(bitmap,block);
|
||||||
|
if (prodosFileEntry.isSaplingFile()) {
|
||||||
|
freeBlocksInIndex(bitmap,block);
|
||||||
|
} else if (prodosFileEntry.isTreeFile()) {
|
||||||
|
byte[] masterIndexBlock = readBlock(block);
|
||||||
|
int offset = 0;
|
||||||
|
for (int i=0; i<0x100; i++) {
|
||||||
|
int indexBlockNumber = AppleUtil.getWordValue(
|
||||||
|
masterIndexBlock[i], masterIndexBlock[i+0x100]);
|
||||||
|
freeBlocksInIndex(bitmap,indexBlockNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeVolumeBitMap(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the given index block and the data blocks it points to.
|
||||||
|
*/
|
||||||
|
private void freeBlocksInIndex(byte[] bitmap, int indexBlockNumber) {
|
||||||
|
setBlockFree(bitmap, indexBlockNumber);
|
||||||
|
byte[] indexBlock = readBlock(indexBlockNumber);
|
||||||
|
int offset = 0;
|
||||||
|
for (int i=0; i<0x100; i++) {
|
||||||
|
int blockNumber = AppleUtil.getWordValue(indexBlock[i], indexBlock[i+0x100]);
|
||||||
|
if (blockNumber > 0) setBlockFree(bitmap, blockNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read file data from the given index block.
|
* Read file data from the given index block.
|
||||||
* Note that block number 0 is an unused block.
|
* Note that block number 0 is an unused block.
|
||||||
@ -371,6 +447,7 @@ public class ProdosFormatDisk extends FormattedDisk {
|
|||||||
int bytesToCopy = fileData.length - offset;
|
int bytesToCopy = fileData.length - offset;
|
||||||
if (blockNumber != 0) System.arraycopy(blockData, 0, fileData, offset, bytesToCopy);
|
if (blockNumber != 0) System.arraycopy(blockData, 0, fileData, offset, bytesToCopy);
|
||||||
offset+= bytesToCopy;
|
offset+= bytesToCopy;
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (blockNumber != 0) System.arraycopy(blockData, 0, fileData, offset, blockData.length);
|
if (blockNumber != 0) System.arraycopy(blockData, 0, fileData, offset, blockData.length);
|
||||||
offset+= blockData.length;
|
offset+= blockData.length;
|
||||||
@ -379,6 +456,114 @@ public class ProdosFormatDisk extends FormattedDisk {
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the data associated with the specified ProdosFileEntry into sectors
|
||||||
|
* on the disk.
|
||||||
|
*/
|
||||||
|
protected void setFileData(ProdosFileEntry fileEntry, byte[] fileData)
|
||||||
|
throws DiskFullException {
|
||||||
|
|
||||||
|
// compute free space and see if the data will fit!
|
||||||
|
int numberOfDataBlocks = (fileData.length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
|
int numberOfBlocks = numberOfDataBlocks;
|
||||||
|
if (numberOfBlocks > 1) {
|
||||||
|
numberOfBlocks+= (numberOfDataBlocks / 256) + 1; // that's 128K
|
||||||
|
if (numberOfDataBlocks > 256) {
|
||||||
|
numberOfBlocks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numberOfBlocks > getFreeBlocks() + fileEntry.getBlocksUsed()) {
|
||||||
|
throw new DiskFullException("This file requires " + numberOfBlocks
|
||||||
|
+ " blocks but there are only " + getFreeBlocks() + " blocks"
|
||||||
|
+ " available on the disk.");
|
||||||
|
}
|
||||||
|
// free "old" data and just rewrite stuff...
|
||||||
|
freeBlocks(fileEntry);
|
||||||
|
byte[] bitmap = readVolumeBitMap();
|
||||||
|
int blockNumber = fileEntry.getKeyPointer();
|
||||||
|
if (blockNumber == 0) {
|
||||||
|
blockNumber = findFreeBlock(bitmap);
|
||||||
|
}
|
||||||
|
int indexBlockNumber = 0;
|
||||||
|
byte[] indexBlockData = null;
|
||||||
|
int masterIndexBlockNumber = 0;
|
||||||
|
byte[] masterIndexBlockData = new byte[BLOCK_SIZE];
|
||||||
|
int offset = 0;
|
||||||
|
int blockCount = 0;
|
||||||
|
while (offset < fileData.length) {
|
||||||
|
if (blockCount > 0) 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);
|
||||||
|
if (numberOfDataBlocks > 1) {
|
||||||
|
if (indexBlockData == null) { // sapling files
|
||||||
|
indexBlockNumber = findFreeBlock(bitmap);
|
||||||
|
indexBlockData = new byte[BLOCK_SIZE];
|
||||||
|
setBlockUsed(bitmap, indexBlockNumber);
|
||||||
|
blockCount++;
|
||||||
|
// This is only used for Tree files:
|
||||||
|
int position = (offset / (BLOCK_SIZE * 256));
|
||||||
|
byte low = (byte)(indexBlockNumber % 256);
|
||||||
|
byte high = (byte)(indexBlockNumber / 256);
|
||||||
|
masterIndexBlockData[position] = low;
|
||||||
|
masterIndexBlockData[position + 0x100] = high;
|
||||||
|
}
|
||||||
|
int position = (offset / BLOCK_SIZE);
|
||||||
|
byte low = (byte)(blockNumber % 256);
|
||||||
|
byte high = (byte)(blockNumber / 256);
|
||||||
|
indexBlockData[position] = low;
|
||||||
|
indexBlockData[position + 0x100] = high;
|
||||||
|
if (position == 255) { // growing to a tree file
|
||||||
|
if (masterIndexBlockNumber == 0) {
|
||||||
|
masterIndexBlockNumber = findFreeBlock(bitmap);
|
||||||
|
setBlockUsed(bitmap, masterIndexBlockNumber);
|
||||||
|
blockCount++;
|
||||||
|
}
|
||||||
|
writeBlock(indexBlockNumber, indexBlockData);
|
||||||
|
indexBlockData = null;
|
||||||
|
indexBlockNumber = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset+= BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
if (numberOfBlocks == 1) {
|
||||||
|
fileEntry.setKeyPointer(blockNumber);
|
||||||
|
fileEntry.setSeedlingFile();
|
||||||
|
} else if (numberOfBlocks <= 256) {
|
||||||
|
writeBlock(indexBlockNumber, indexBlockData);
|
||||||
|
fileEntry.setKeyPointer(indexBlockNumber);
|
||||||
|
fileEntry.setSaplingFile();
|
||||||
|
} else {
|
||||||
|
writeBlock(indexBlockNumber, indexBlockData);
|
||||||
|
writeBlock(masterIndexBlockNumber, masterIndexBlockData);
|
||||||
|
fileEntry.setKeyPointer(masterIndexBlockNumber);
|
||||||
|
fileEntry.setTreeFile();
|
||||||
|
}
|
||||||
|
fileEntry.setBlocksUsed(blockCount);
|
||||||
|
fileEntry.setEofPosition(fileData.length);
|
||||||
|
fileEntry.setLastModificationDate(new Date());
|
||||||
|
writeVolumeBitMap(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate a free block in the Volume Bitmap.
|
||||||
|
*/
|
||||||
|
protected int findFreeBlock(byte[] volumeBitmap) throws DiskFullException {
|
||||||
|
int block = 1;
|
||||||
|
int blocksOnDisk = getBitmapLength();
|
||||||
|
while (block < blocksOnDisk) {
|
||||||
|
if (isBlockFree(volumeBitmap,block)) {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
block++;
|
||||||
|
}
|
||||||
|
throw new DiskFullException(
|
||||||
|
"Unable to locate a free block in the Volume Bitmap!");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the Volume Bit Map.
|
* Read the Volume Bit Map.
|
||||||
*/
|
*/
|
||||||
@ -474,11 +659,11 @@ public class ProdosFormatDisk extends FormattedDisk {
|
|||||||
volumeHeader.setCreationDate(new Date());
|
volumeHeader.setCreationDate(new Date());
|
||||||
volumeHeader.setProdosVersion(0);
|
volumeHeader.setProdosVersion(0);
|
||||||
volumeHeader.setMinimumProdosVersion(0);
|
volumeHeader.setMinimumProdosVersion(0);
|
||||||
volumeHeader.setChanged(true);
|
volumeHeader.setHasChanged(true);
|
||||||
volumeHeader.setDestroy(true);
|
volumeHeader.setCanDestroy(true);
|
||||||
volumeHeader.setRead(true);
|
volumeHeader.setCanRead(true);
|
||||||
volumeHeader.setRename(true);
|
volumeHeader.setCanRename(true);
|
||||||
volumeHeader.setWrite(true);
|
volumeHeader.setCanWrite(true);
|
||||||
volumeHeader.setEntryLength();
|
volumeHeader.setEntryLength();
|
||||||
volumeHeader.setEntriesPerBlock();
|
volumeHeader.setEntriesPerBlock();
|
||||||
volumeHeader.setFileCount(0);
|
volumeHeader.setFileCount(0);
|
||||||
|
Loading…
Reference in New Issue
Block a user