Added ability to create and format a disk. Routines were centralized

a bit and the various file entries now read and write directly to the 
disk image.
This commit is contained in:
Robert Greene 2002-12-12 01:54:01 +00:00
parent ab445b87d8
commit 62c7b5bc70
1 changed files with 146 additions and 48 deletions

View File

@ -20,6 +20,7 @@
package com.webcodepro.applecommander.storage; package com.webcodepro.applecommander.storage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
@ -29,11 +30,6 @@ import java.util.List;
* @author: Rob Greene * @author: Rob Greene
*/ */
public class ProdosFormatDisk extends FormattedDisk { public class ProdosFormatDisk extends FormattedDisk {
/**
* The standard ProDOS file entry length.
*/
public static final int ENTRY_LENGTH = 0x27;
/** /**
* Hold on to the volume directory header. * Hold on to the volume directory header.
*/ */
@ -60,20 +56,9 @@ public class ProdosFormatDisk extends FormattedDisk {
throw new IllegalArgumentException("Invalid dimension for isFree! Did you call next first?"); throw new IllegalArgumentException("Invalid dimension for isFree! Did you call next first?");
} }
if (data == null) { if (data == null) {
int volumeBitmapBlock = volumeHeader.getBitMapPointer(); data = readVolumeBitMap();
int volumeBitmapBlocks = volumeHeader.getTotalBlocks();
int blocksToRead = (volumeBitmapBlocks / 4096) + 1;
// Read in the entire volume bitmap:
data = new byte[blocksToRead * BLOCK_SIZE];
for (int i=0; i<blocksToRead; i++) {
System.arraycopy(readBlock(volumeBitmapBlock+i), 0, data, i*BLOCK_SIZE, BLOCK_SIZE);
}
} }
// Locate appropriate bit and check it: return isBlockFree(data, location);
int byt = location / 8;
int bit = 7 - (location % 8);
boolean free = AppleUtil.isBitSet(data[byt], bit);
return free;
} }
public boolean isUsed() { public boolean isUsed() {
return !isFree(); return !isFree();
@ -87,12 +72,15 @@ public class ProdosFormatDisk extends FormattedDisk {
*/ */
public ProdosFormatDisk(String filename, byte[] diskImage) { public ProdosFormatDisk(String filename, byte[] diskImage) {
super(filename, diskImage); super(filename, diskImage);
volumeHeader = new ProdosVolumeDirectoryHeader(this);
// read volume header: }
byte[] block = readBlock(2);
byte[] entry = new byte[ENTRY_LENGTH]; /**
System.arraycopy(block, 4, entry, 0, ENTRY_LENGTH); * Constructor for ProdosFormatDisk.
volumeHeader = new ProdosVolumeDirectoryHeader(entry); */
public ProdosFormatDisk(String filename, String diskName, int imageSize) {
this(filename, new byte[imageSize]);
volumeHeader.setVolumeName(diskName);
} }
/** /**
@ -120,31 +108,23 @@ public class ProdosFormatDisk extends FormattedDisk {
while (blockNumber != 0) { while (blockNumber != 0) {
byte[] block = readBlock(blockNumber); byte[] block = readBlock(blockNumber);
int offset = 4; int offset = 4;
while (offset+ENTRY_LENGTH < BLOCK_SIZE) { while (offset+ProdosCommonEntry.ENTRY_LENGTH < BLOCK_SIZE) {
byte[] entry = new byte[ENTRY_LENGTH]; ProdosCommonEntry tester =
System.arraycopy(block, offset, entry, 0, ENTRY_LENGTH); new ProdosCommonEntry(this, blockNumber, offset);
int checksum = 0; if (tester.isVolumeHeader() || tester.isSubdirectoryHeader()) {
for (int i=0; i<entry.length; i++) { // ignore it, we've already got it
checksum |= entry[i]; } else {
} ProdosFileEntry fileEntry =
if (checksum != 0) { new ProdosFileEntry(this, blockNumber, offset);
ProdosCommonEntry tester = new ProdosCommonEntry(entry); files.add(fileEntry);
if (tester.isVolumeHeader() || tester.isSubdirectoryHeader()) { if (fileEntry.isDirectory()) {
// ignore it, we've already got it int keyPointer = fileEntry.getKeyPointer();
} else { fileEntry.setSubdirectoryHeader(
ProdosFileEntry fileEntry = new ProdosFileEntry(entry, this); new ProdosSubdirectoryHeader(this, keyPointer));
files.add(fileEntry); fileEntry.setFiles(getFiles(keyPointer));
if (fileEntry.isDirectory()) {
int keyPointer = fileEntry.getKeyPointer();
byte[] subdirBlock = readBlock(keyPointer);
byte[] subdirEntry = new byte[ENTRY_LENGTH];
System.arraycopy(subdirBlock, 4, subdirEntry, 0, ENTRY_LENGTH);
fileEntry.setSubdirectoryHeader(new ProdosSubdirectoryHeader(subdirEntry));
fileEntry.setFiles(getFiles(keyPointer));
}
} }
} }
offset+= entry.length; offset+= ProdosCommonEntry.ENTRY_LENGTH;
} }
blockNumber = AppleUtil.getWordValue(block, 2); blockNumber = AppleUtil.getWordValue(block, 2);
} }
@ -364,7 +344,7 @@ public class ProdosFormatDisk extends FormattedDisk {
offset+= getIndexBlockData(fileData, indexBlock, offset); offset+= getIndexBlockData(fileData, indexBlock, offset);
} }
} else { } else {
throw new IllegalArgumentException("Unknown ProDOS filetype!"); throw new IllegalArgumentException("Unknown ProDOS storage type!");
} }
return fileData; return fileData;
} }
@ -389,4 +369,122 @@ public class ProdosFormatDisk extends FormattedDisk {
} }
return offset; return offset;
} }
/**
* Read the Volume Bit Map.
*/
public byte[] readVolumeBitMap() {
int volumeBitmapBlock = volumeHeader.getBitMapPointer();
int volumeBitmapBlocks = volumeHeader.getTotalBlocks();
int blocksToRead = (volumeBitmapBlocks / 4096) + 1;
// Read in the entire volume bitmap:
byte[] data = new byte[blocksToRead * BLOCK_SIZE];
for (int i=0; i<blocksToRead; i++) {
System.arraycopy(readBlock(volumeBitmapBlock+i), 0, data, i*BLOCK_SIZE, BLOCK_SIZE);
}
return data;
}
/**
* Write the Volume Bit Map.
*/
public void writeVolumeBitMap(byte[] data) {
int volumeBitmapBlock = volumeHeader.getBitMapPointer();
int volumeBitmapBlocks = volumeHeader.getTotalBlocks();
int blocksToWrite = (volumeBitmapBlocks / 4096) + 1;
if (data.length != blocksToWrite * BLOCK_SIZE) {
throw new IllegalArgumentException(
"The ProDOS Volume Bit Map is not the correct size.");
}
byte[] dataBlock = new byte[BLOCK_SIZE];
for (int i=0; i<blocksToWrite; i++) {
System.arraycopy(data, i*BLOCK_SIZE, dataBlock, 0, BLOCK_SIZE);
writeBlock(volumeBitmapBlock+i, dataBlock);
}
}
/**
* Determine if the specified block is free.
*/
public boolean isBlockFree(byte[] data, int blockNumber) {
// Locate appropriate bit and check it:
int byt = blockNumber / 8;
int bit = 7 - (blockNumber % 8);
boolean free = AppleUtil.isBitSet(data[byt], bit);
return free;
}
/**
* Set if the specified block is free.
*/
public void setBlockFree(byte[] data, int blockNumber) {
// Locate appropriate bit and check it:
int byt = blockNumber / 8;
int bit = 7 - (blockNumber % 8);
data[byt] = AppleUtil.setBit(data[byt], bit);
}
/**
* Determine if the specified block is used.
*/
public boolean isBlockUsed(byte[] data, int blockNumber) {
return !isBlockFree(data, blockNumber);
}
/**
* Set if the specified block is free.
*/
public void setBlockUsed(byte[] data, int blockNumber) {
// Locate appropriate bit and check it:
int byt = blockNumber / 8;
int bit = 7 - (blockNumber % 8);
data[byt] = AppleUtil.clearBit(data[byt], bit);
}
/**
* Format the ProDOS volume.
* @see com.webcodepro.applecommander.storage.FormattedDisk#format()
*/
public void format() {
writeBootCode();
String volumeName = volumeHeader.getVolumeName();
int totalBlocks = getDiskImage().length / BLOCK_SIZE;
int usedBlocks = (totalBlocks / 4096) + 7;
// setup volume directory
byte[] data = new byte[BLOCK_SIZE];
for (int block=2; block<6; block++) {
int nextBlock = (block < 5) ? block+1 : 0;
int prevBlock = (block > 2) ? block-1 : 0;
AppleUtil.setWordValue(data, 0, prevBlock);
AppleUtil.setWordValue(data, 2, nextBlock);
writeBlock(block, data);
}
// setup volume header information (each set will also save data)
volumeHeader.setVolumeHeader();
volumeHeader.setVolumeName(volumeName);
volumeHeader.setCreationDate(new Date());
volumeHeader.setProdosVersion(0);
volumeHeader.setMinimumProdosVersion(0);
volumeHeader.setChanged(true);
volumeHeader.setDestroy(true);
volumeHeader.setRead(true);
volumeHeader.setRename(true);
volumeHeader.setWrite(true);
volumeHeader.setEntryLength();
volumeHeader.setEntriesPerBlock();
volumeHeader.setFileCount(0);
volumeHeader.setBitMapPointer(6);
volumeHeader.setTotalBlocks(totalBlocks);
// setup bitmap usage
byte[] bitmap = readVolumeBitMap();
for (int block=0; block<totalBlocks; block++) {
if (block < usedBlocks) {
setBlockUsed(bitmap, block);
} else {
setBlockFree(bitmap, block);
}
}
writeVolumeBitMap(bitmap);
}
} }