mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2024-05-31 14:41:31 +00:00
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:
parent
ab445b87d8
commit
62c7b5bc70
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user